@jtff/miztemplate-lib 3.2.1 → 3.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- env.info('*** MOOSE GITHUB Commit Hash ID: 2024-02-03T12:48:41+01:00-86e13df3039b95b46af4786cb3196cb931175778 ***')
1
+ env.info('*** MOOSE GITHUB Commit Hash ID: 2024-05-04T14:54:20+02:00-044fb66ca064687a743791e5a4a5d02c109ca9c1 ***')
2
2
  if not MOOSE_DEVELOPMENT_FOLDER then
3
3
  MOOSE_DEVELOPMENT_FOLDER='Scripts'
4
4
  end
@@ -1315,9 +1315,9 @@ return s
1315
1315
  end
1316
1316
  end
1317
1317
  end
1318
- function UTILS.PrintTableToLog(table,indent)
1318
+ function UTILS.PrintTableToLog(table,indent,noprint)
1319
1319
  local text="\n"
1320
- if not table then
1320
+ if not table or type(table)~="table"then
1321
1321
  env.warning("No table passed!")
1322
1322
  return nil
1323
1323
  end
@@ -1325,11 +1325,16 @@ if not indent then indent=0 end
1325
1325
  for k,v in pairs(table)do
1326
1326
  if string.find(k," ")then k='"'..k..'"'end
1327
1327
  if type(v)=="table"then
1328
+ if not noprint then
1328
1329
  env.info(string.rep(" ",indent)..tostring(k).." = {")
1330
+ end
1329
1331
  text=text..string.rep(" ",indent)..tostring(k).." = {\n"
1330
1332
  text=text..tostring(UTILS.PrintTableToLog(v,indent+1)).."\n"
1333
+ if not noprint then
1331
1334
  env.info(string.rep(" ",indent).."},")
1335
+ end
1332
1336
  text=text..string.rep(" ",indent).."},\n"
1337
+ elseif type(v)=="function"then
1333
1338
  else
1334
1339
  local value
1335
1340
  if tostring(v)=="true"or tostring(v)=="false"or tonumber(v)~=nil then
@@ -1337,7 +1342,9 @@ value=v
1337
1342
  else
1338
1343
  value='"'..tostring(v)..'"'
1339
1344
  end
1345
+ if not noprint then
1340
1346
  env.info(string.rep(" ",indent)..tostring(k).." = "..tostring(value)..",\n")
1347
+ end
1341
1348
  text=text..string.rep(" ",indent)..tostring(k).." = "..tostring(value)..",\n"
1342
1349
  end
1343
1350
  end
@@ -2402,6 +2409,10 @@ if type_name=="Bronco-OV-10A"then
2402
2409
  BASE:T(unit_name.." front door(s) are open")
2403
2410
  return true
2404
2411
  end
2412
+ if type_name=="MH-60R"and(unit:getDrawArgumentValue(403)>0 or unit:getDrawArgumentValue(403)==-1)then
2413
+ BASE:T(unit_name.." cargo door is open")
2414
+ return true
2415
+ end
2405
2416
  return false
2406
2417
  end
2407
2418
  return nil
@@ -3255,6 +3266,18 @@ end
3255
3266
  function string.contains(str,value)
3256
3267
  return string.match(str,value)
3257
3268
  end
3269
+ function table.move_object(obj,from_table,to_table)
3270
+ local index
3271
+ for i,v in pairs(from_table)do
3272
+ if v==obj then
3273
+ index=i
3274
+ end
3275
+ end
3276
+ if index then
3277
+ local moved=table.remove(from_table,index)
3278
+ table.insert_unique(to_table,moved)
3279
+ end
3280
+ end
3258
3281
  function table.contains(tbl,element)
3259
3282
  if element==nil or tbl==nil then return false end
3260
3283
  local index=1
@@ -3391,6 +3414,90 @@ end
3391
3414
  function UTILS.OctalToDecimal(Number)
3392
3415
  return tonumber(Number,8)
3393
3416
  end
3417
+ function UTILS.HexToRGBA(hex_string)
3418
+ local hexNumber=tonumber(string.sub(hex_string,3),16)
3419
+ local alpha=hexNumber%256
3420
+ hexNumber=(hexNumber-alpha)/256
3421
+ local blue=hexNumber%256
3422
+ hexNumber=(hexNumber-blue)/256
3423
+ local green=hexNumber%256
3424
+ hexNumber=(hexNumber-green)/256
3425
+ local red=hexNumber%256
3426
+ return{R=red,G=green,B=blue,A=alpha}
3427
+ end
3428
+ function UTILS.SaveSetOfOpsGroups(Set,Path,Filename,Structured)
3429
+ local filename=Filename or"SetOfGroups"
3430
+ local data="--Save SET of groups: (name,legion,template,alttemplate,units,position.x,position.y,position.z,strucdata) "..Filename.."\n"
3431
+ local List=Set:GetSetObjects()
3432
+ for _,_group in pairs(List)do
3433
+ local group=_group:GetGroup()
3434
+ if group and group:IsAlive()then
3435
+ local name=group:GetName()
3436
+ local template=string.gsub(name,"(.AID.%d+$","")
3437
+ if string.find(template,"#")then
3438
+ template=string.gsub(name,"#(%d+)$","")
3439
+ end
3440
+ local alttemplate=_group.templatename or"none"
3441
+ local legiono=_group.legion
3442
+ local legion="none"
3443
+ if legiono and type(legiono)=="table"and legiono.ClassName then
3444
+ legion=legiono:GetName()
3445
+ local asset=legiono:GetAssetByName(name)
3446
+ alttemplate=asset.templatename
3447
+ end
3448
+ local units=group:CountAliveUnits()
3449
+ local position=group:GetVec3()
3450
+ if Structured then
3451
+ local structure=UTILS.GetCountPerTypeName(group)
3452
+ local strucdata=""
3453
+ for typen,anzahl in pairs(structure)do
3454
+ strucdata=strucdata..typen.."=="..anzahl..";"
3455
+ end
3456
+ data=string.format("%s%s,%s,%s,%s,%d,%d,%d,%d,%s\n",data,name,legion,template,alttemplate,units,position.x,position.y,position.z,strucdata)
3457
+ else
3458
+ data=string.format("%s%s,%s,%s,%s,%d,%d,%d,%d\n",data,name,legion,template,alttemplate,units,position.x,position.y,position.z)
3459
+ end
3460
+ end
3461
+ end
3462
+ local outcome=UTILS.SaveToFile(Path,Filename,data)
3463
+ return outcome
3464
+ end
3465
+ function UTILS.LoadSetOfOpsGroups(Path,Filename)
3466
+ local filename=Filename or"SetOfGroups"
3467
+ local datatable={}
3468
+ if UTILS.CheckFileExists(Path,filename)then
3469
+ local outcome,loadeddata=UTILS.LoadFromFile(Path,Filename)
3470
+ table.remove(loadeddata,1)
3471
+ for _id,_entry in pairs(loadeddata)do
3472
+ local dataset=UTILS.Split(_entry,",")
3473
+ local groupname=dataset[1]
3474
+ local legion=dataset[2]
3475
+ local template=dataset[3]
3476
+ local alttemplate=dataset[4]
3477
+ local size=tonumber(dataset[5])
3478
+ local posx=tonumber(dataset[6])
3479
+ local posy=tonumber(dataset[7])
3480
+ local posz=tonumber(dataset[8])
3481
+ local structure=dataset[9]
3482
+ local coordinate=COORDINATE:NewFromVec3({x=posx,y=posy,z=posz})
3483
+ if size>0 then
3484
+ local data={groupname=groupname,size=size,coordinate=coordinate,template=template,structure=structure,legion=legion,alttemplate=alttemplate}
3485
+ table.insert(datatable,data)
3486
+ end
3487
+ end
3488
+ else
3489
+ return nil
3490
+ end
3491
+ return datatable
3492
+ end
3493
+ function UTILS.ClockHeadingString(refHdg,tgtHdg)
3494
+ local relativeAngle=tgtHdg-refHdg
3495
+ if relativeAngle<0 then
3496
+ relativeAngle=relativeAngle+360
3497
+ end
3498
+ local clockPos=math.ceil((relativeAngle%360)/30)
3499
+ return clockPos.." o'clock"
3500
+ end
3394
3501
  PROFILER={
3395
3502
  ClassName="PROFILER",
3396
3503
  Counters={},
@@ -5006,6 +5113,14 @@ end
5006
5113
  _TraceClassMethod[Class].Method[Method]=true
5007
5114
  self:I("Tracing method "..Method.." of class "..Class)
5008
5115
  end
5116
+ function BASE:_Serialize(Arguments)
5117
+ local text=UTILS.PrintTableToLog({Arguments},0,true)
5118
+ text=string.gsub(text,"(\n+)","")
5119
+ text=string.gsub(text,"%(%(","%(")
5120
+ text=string.gsub(text,"%)%)","%)")
5121
+ text=string.gsub(text,"(%s+)"," ")
5122
+ return text
5123
+ end
5009
5124
  function BASE:_F(Arguments,DebugInfoCurrentParam,DebugInfoFromParam)
5010
5125
  if BASE.Debug and(_TraceAll==true)or(_TraceClass[self.ClassName]or _TraceClassMethod[self.ClassName])then
5011
5126
  local DebugInfoCurrent=DebugInfoCurrentParam and DebugInfoCurrentParam or BASE.Debug.getinfo(2,"nl")
@@ -5023,7 +5138,7 @@ local LineFrom=0
5023
5138
  if DebugInfoFrom then
5024
5139
  LineFrom=DebugInfoFrom.currentline
5025
5140
  end
5026
- env.info(string.format("%6d(%6d)/%1s:%30s%05d.%s(%s)",LineCurrent,LineFrom,"F",self.ClassName,self.ClassID,Function,UTILS.BasicSerialize(Arguments)))
5141
+ env.info(string.format("%6d(%6d)/%1s:%30s%05d.%s(%s)",LineCurrent,LineFrom,"F",self.ClassName,self.ClassID,Function,BASE:_Serialize(Arguments)))
5027
5142
  end
5028
5143
  end
5029
5144
  end
@@ -5071,7 +5186,7 @@ local LineFrom=0
5071
5186
  if DebugInfoFrom then
5072
5187
  LineFrom=DebugInfoFrom.currentline
5073
5188
  end
5074
- env.info(string.format("%6d(%6d)/%1s:%30s%05d.%s",LineCurrent,LineFrom,"T",self.ClassName,self.ClassID,UTILS.BasicSerialize(Arguments)))
5189
+ env.info(string.format("%6d(%6d)/%1s:%30s%05d.%s",LineCurrent,LineFrom,"T",self.ClassName,self.ClassID,BASE:_Serialize(Arguments)))
5075
5190
  end
5076
5191
  end
5077
5192
  end
@@ -5117,7 +5232,7 @@ LineFrom=DebugInfoFrom.currentline
5117
5232
  end
5118
5233
  env.info(string.format("%6d(%6d)/%1s:%30s%05d.%s(%s)",LineCurrent,LineFrom,"E",self.ClassName,self.ClassID,Function,UTILS.BasicSerialize(Arguments)))
5119
5234
  else
5120
- env.info(string.format("%1s:%30s%05d(%s)","E",self.ClassName,self.ClassID,UTILS.BasicSerialize(Arguments)))
5235
+ env.info(string.format("%1s:%30s%05d(%s)","E",self.ClassName,self.ClassID,BASE:_Serialize(Arguments)))
5121
5236
  end
5122
5237
  end
5123
5238
  function BASE:I(Arguments)
@@ -5135,7 +5250,7 @@ LineFrom=DebugInfoFrom.currentline
5135
5250
  end
5136
5251
  env.info(string.format("%6d(%6d)/%1s:%30s%05d.%s(%s)",LineCurrent,LineFrom,"I",self.ClassName,self.ClassID,Function,UTILS.BasicSerialize(Arguments)))
5137
5252
  else
5138
- env.info(string.format("%1s:%30s%05d(%s)","I",self.ClassName,self.ClassID,UTILS.BasicSerialize(Arguments)))
5253
+ env.info(string.format("%1s:%30s%05d(%s)","I",self.ClassName,self.ClassID,BASE:_Serialize(Arguments)))
5139
5254
  end
5140
5255
  end
5141
5256
  ASTAR={
@@ -5503,6 +5618,7 @@ BEACON={
5503
5618
  ClassName="BEACON",
5504
5619
  Positionable=nil,
5505
5620
  name=nil,
5621
+ UniqueName=0,
5506
5622
  }
5507
5623
  BEACON.Type={
5508
5624
  NULL=0,
@@ -5607,6 +5723,7 @@ return self
5607
5723
  end
5608
5724
  function BEACON:AATACAN(TACANChannel,Message,Bearing,BeaconDuration)
5609
5725
  self:F({TACANChannel,Message,Bearing,BeaconDuration})
5726
+ self:E("This method is DEPRECATED! Please use ActivateTACAN() instead.")
5610
5727
  local IsValid=true
5611
5728
  if not self.Positionable:IsAir()then
5612
5729
  self:E({"The POSITIONABLE you want to attach the AA Tacan Beacon is not an aircraft ! The BEACON is not emitting",self.Positionable})
@@ -5661,6 +5778,7 @@ end
5661
5778
  function BEACON:RadioBeacon(FileName,Frequency,Modulation,Power,BeaconDuration)
5662
5779
  self:F({FileName,Frequency,Modulation,Power,BeaconDuration})
5663
5780
  local IsValid=false
5781
+ Modulation=Modulation or radio.modulation.AM
5664
5782
  if type(FileName)=="string"then
5665
5783
  if FileName:find(".ogg")or FileName:find(".wav")then
5666
5784
  if not FileName:find("l10n/DEFAULT/")then
@@ -5670,7 +5788,7 @@ IsValid=true
5670
5788
  end
5671
5789
  end
5672
5790
  if not IsValid then
5673
- self:E({"File name invalid. Maybe something wrong with the extension ? ",FileName})
5791
+ self:E({"File name invalid. Maybe something wrong with the extension? ",FileName})
5674
5792
  end
5675
5793
  if type(Frequency)~="number"and IsValid then
5676
5794
  self:E({"Frequency invalid. ",Frequency})
@@ -5688,7 +5806,9 @@ end
5688
5806
  Power=math.floor(math.abs(Power))
5689
5807
  if IsValid then
5690
5808
  self:T2({"Activating Beacon on ",Frequency,Modulation})
5691
- trigger.action.radioTransmission(FileName,self.Positionable:GetPositionVec3(),Modulation,true,Frequency,Power,tostring(self.ID))
5809
+ BEACON.UniqueName=BEACON.UniqueName+1
5810
+ self.BeaconName="MooseBeacon"..tostring(BEACON.UniqueName)
5811
+ trigger.action.radioTransmission(FileName,self.Positionable:GetPositionVec3(),Modulation,true,Frequency,Power,self.BeaconName)
5692
5812
  if BeaconDuration then
5693
5813
  SCHEDULER:New(nil,
5694
5814
  function()
@@ -5696,10 +5816,11 @@ self:StopRadioBeacon()
5696
5816
  end,{},BeaconDuration)
5697
5817
  end
5698
5818
  end
5819
+ return self
5699
5820
  end
5700
5821
  function BEACON:StopRadioBeacon()
5701
5822
  self:F()
5702
- trigger.action.stopRadioTransmission(tostring(self.ID))
5823
+ trigger.action.stopRadioTransmission(self.BeaconName)
5703
5824
  return self
5704
5825
  end
5705
5826
  function BEACON:_TACANToFrequency(TACANChannel,TACANMode)
@@ -7038,6 +7159,7 @@ Event.MarkVec3=Event.pos
7038
7159
  Event.MarkCoordinate=COORDINATE:NewFromVec3(Event.pos)
7039
7160
  Event.MarkText=Event.text
7040
7161
  Event.MarkCoalition=Event.coalition
7162
+ Event.IniCoalition=Event.coalition
7041
7163
  Event.MarkGroupID=Event.groupID
7042
7164
  end
7043
7165
  if Event.cargo then
@@ -8726,6 +8848,7 @@ end
8726
8848
  function ZONE_RADIUS:BoundZone(Points,CountryID,UnBound)
8727
8849
  local Point={}
8728
8850
  local Vec2=self:GetVec2()
8851
+ local countryID=CountryID or country.id.USA
8729
8852
  Points=Points and Points or 360
8730
8853
  local Angle
8731
8854
  local RadialBase=math.pi*2
@@ -8733,7 +8856,7 @@ for Angle=0,360,(360/Points)do
8733
8856
  local Radial=Angle*RadialBase/360
8734
8857
  Point.x=Vec2.x+math.cos(Radial)*self:GetRadius()
8735
8858
  Point.y=Vec2.y+math.sin(Radial)*self:GetRadius()
8736
- local CountryName=_DATABASE.COUNTRY_NAME[CountryID]
8859
+ local CountryName=_DATABASE.COUNTRY_NAME[countryID]
8737
8860
  local Tire={
8738
8861
  ["country"]=CountryName,
8739
8862
  ["category"]="Fortifications",
@@ -8745,7 +8868,7 @@ local Tire={
8745
8868
  ["name"]=string.format("%s-Tire #%0d",self:GetName(),Angle),
8746
8869
  ["heading"]=0,
8747
8870
  }
8748
- local Group=coalition.addStaticObject(CountryID,Tire)
8871
+ local Group=coalition.addStaticObject(countryID,Tire)
8749
8872
  if UnBound and UnBound==true then
8750
8873
  Group:destroy()
8751
8874
  end
@@ -10263,7 +10386,7 @@ function ZONE_OVAL:GetRandomPointVec2()
10263
10386
  return POINT_VEC2:NewFromVec2(self:GetRandomVec2())
10264
10387
  end
10265
10388
  function ZONE_OVAL:GetRandomPointVec3()
10266
- return POINT_VEC2:NewFromVec3(self:GetRandomVec2())
10389
+ return POINT_VEC3:NewFromVec3(self:GetRandomVec2())
10267
10390
  end
10268
10391
  function ZONE_OVAL:DrawZone(Coalition,Color,Alpha,FillColor,FillAlpha,LineType)
10269
10392
  Coalition=Coalition or self:GetDrawCoalition()
@@ -10472,6 +10595,8 @@ FLIGHTCONTROLS={},
10472
10595
  OPSZONES={},
10473
10596
  PATHLINES={},
10474
10597
  STORAGES={},
10598
+ STNS={},
10599
+ SADL={},
10475
10600
  }
10476
10601
  local _DATABASECoalition=
10477
10602
  {
@@ -10853,7 +10978,7 @@ local SpawnCategoryID=SpawnTemplate.CategoryID
10853
10978
  SpawnTemplate.CoalitionID=nil
10854
10979
  SpawnTemplate.CountryID=nil
10855
10980
  SpawnTemplate.CategoryID=nil
10856
- self:_RegisterGroupTemplate(SpawnTemplate,SpawnCoalitionID,SpawnCategoryID,SpawnCountryID)
10981
+ self:_RegisterGroupTemplate(SpawnTemplate,SpawnCoalitionID,SpawnCategoryID,SpawnCountryID,SpawnTemplate.name)
10857
10982
  self:T3(SpawnTemplate)
10858
10983
  coalition.addGroup(SpawnCountryID,SpawnCategoryID,SpawnTemplate)
10859
10984
  SpawnTemplate.CoalitionID=SpawnCoalitionID
@@ -10916,6 +11041,26 @@ self.Templates.ClientsByName[UnitTemplate.name].CoalitionID=CoalitionSide
10916
11041
  self.Templates.ClientsByName[UnitTemplate.name].CountryID=CountryID
10917
11042
  self.Templates.ClientsByID[UnitTemplate.unitId]=UnitTemplate
10918
11043
  end
11044
+ if UnitTemplate.AddPropAircraft then
11045
+ if UnitTemplate.AddPropAircraft.STN_L16 then
11046
+ local stn=UTILS.OctalToDecimal(UnitTemplate.AddPropAircraft.STN_L16)
11047
+ if stn==nil or stn<1 then
11048
+ self:E("WARNING: Invalid STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for "..UnitTemplate.name)
11049
+ else
11050
+ self.STNS[stn]=UnitTemplate.name
11051
+ self:I("Register STN "..tostring(UnitTemplate.AddPropAircraft.STN_L16).." for "..UnitTemplate.name)
11052
+ end
11053
+ end
11054
+ if UnitTemplate.AddPropAircraft.SADL_TN then
11055
+ local sadl=UTILS.OctalToDecimal(UnitTemplate.AddPropAircraft.SADL_TN)
11056
+ if sadl==nil or sadl<1 then
11057
+ self:E("WARNING: Invalid SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for "..UnitTemplate.name)
11058
+ else
11059
+ self.SADL[sadl]=UnitTemplate.name
11060
+ self:I("Register SADL "..tostring(UnitTemplate.AddPropAircraft.SADL_TN).." for "..UnitTemplate.name)
11061
+ end
11062
+ end
11063
+ end
10919
11064
  UnitNames[#UnitNames+1]=self.Templates.Units[UnitTemplate.name].UnitName
10920
11065
  end
10921
11066
  self:T({Group=self.Templates.Groups[GroupTemplateName].GroupName,
@@ -10926,6 +11071,66 @@ Units=UnitNames
10926
11071
  }
10927
11072
  )
10928
11073
  end
11074
+ function DATABASE:GetNextSTN(octal,unitname)
11075
+ local first=UTILS.OctalToDecimal(octal)or 0
11076
+ if self.STNS[first]==unitname then return octal end
11077
+ local nextoctal=77777
11078
+ local found=false
11079
+ if 32767-first<10 then
11080
+ first=0
11081
+ end
11082
+ for i=first+1,32767 do
11083
+ if self.STNS[i]==nil then
11084
+ found=true
11085
+ nextoctal=UTILS.DecimalToOctal(i)
11086
+ self.STNS[i]=unitname
11087
+ self:T("Register STN "..tostring(nextoctal).." for "..unitname)
11088
+ break
11089
+ end
11090
+ end
11091
+ if not found then
11092
+ self:E(string.format("WARNING: No next free STN past %05d found!",octal))
11093
+ local NewSTNS={}
11094
+ for _id,_name in pairs(self.STNS)do
11095
+ if self.UNITS[_name]~=nil then
11096
+ NewSTNS[_id]=_name
11097
+ end
11098
+ end
11099
+ self.STNS=nil
11100
+ self.STNS=NewSTNS
11101
+ end
11102
+ return nextoctal
11103
+ end
11104
+ function DATABASE:GetNextSADL(octal,unitname)
11105
+ local first=UTILS.OctalToDecimal(octal)or 0
11106
+ if self.SADL[first]==unitname then return octal end
11107
+ local nextoctal=7777
11108
+ local found=false
11109
+ if 4095-first<10 then
11110
+ first=0
11111
+ end
11112
+ for i=first+1,4095 do
11113
+ if self.STNS[i]==nil then
11114
+ found=true
11115
+ nextoctal=UTILS.DecimalToOctal(i)
11116
+ self.SADL[i]=unitname
11117
+ self:T("Register SADL "..tostring(nextoctal).." for "..unitname)
11118
+ break
11119
+ end
11120
+ end
11121
+ if not found then
11122
+ self:E(string.format("WARNING: No next free SADL past %04d found!",octal))
11123
+ local NewSTNS={}
11124
+ for _id,_name in pairs(self.SADL)do
11125
+ if self.UNITS[_name]~=nil then
11126
+ NewSTNS[_id]=_name
11127
+ end
11128
+ end
11129
+ self.SADL=nil
11130
+ self.SADL=NewSTNS
11131
+ end
11132
+ return nextoctal
11133
+ end
10929
11134
  function DATABASE:GetGroupTemplate(GroupName)
10930
11135
  local GroupTemplate=self.Templates.Groups[GroupName].Template
10931
11136
  GroupTemplate.SpawnCoalitionID=self.Templates.Groups[GroupName].CoalitionID
@@ -11208,7 +11413,7 @@ return playername
11208
11413
  end
11209
11414
  if Event.IniUnit then
11210
11415
  if Event.IniObjectCategory==1 then
11211
- local PlayerName=Event.IniUnit:GetPlayerName()or FindPlayerName(Event.IniUnitName)
11416
+ local PlayerName=Event.IniPlayerName or Event.IniUnit:GetPlayerName()or FindPlayerName(Event.IniUnitName)
11212
11417
  if PlayerName then
11213
11418
  self:I(string.format("Player '%s' left unit %s",tostring(PlayerName),tostring(Event.IniUnitName)))
11214
11419
  local Settings=SETTINGS:Set(PlayerName)
@@ -11896,6 +12101,7 @@ Countries=nil,
11896
12101
  GroupPrefixes=nil,
11897
12102
  Zones=nil,
11898
12103
  Functions=nil,
12104
+ Alive=nil,
11899
12105
  },
11900
12106
  FilterMeta={
11901
12107
  Coalitions={
@@ -12102,6 +12308,10 @@ Active=Active or not(Active==false)
12102
12308
  self.Filter.Active=Active
12103
12309
  return self
12104
12310
  end
12311
+ function SET_GROUP:FilterAlive()
12312
+ self.Filter.Alive=true
12313
+ return self
12314
+ end
12105
12315
  function SET_GROUP:FilterStart()
12106
12316
  if _DATABASE then
12107
12317
  self:_FilterStart()
@@ -12337,6 +12547,14 @@ end
12337
12547
  function SET_GROUP:IsIncludeObject(MGroup)
12338
12548
  self:F2(MGroup)
12339
12549
  local MGroupInclude=true
12550
+ if self.Filter.Alive==true then
12551
+ local MGroupAlive=false
12552
+ self:F({Active=self.Filter.Active})
12553
+ if MGroup and MGroup:IsAlive()then
12554
+ MGroupAlive=true
12555
+ end
12556
+ MGroupInclude=MGroupInclude and MGroupAlive
12557
+ end
12340
12558
  if self.Filter.Active~=nil then
12341
12559
  local MGroupActive=false
12342
12560
  self:F({Active=self.Filter.Active})
@@ -12861,7 +13079,7 @@ local heading=self:GetHeading()or 0
12861
13079
  local velocity=self:GetVelocity()or 0
12862
13080
  Coordinate:SetHeading(heading)
12863
13081
  Coordinate:SetVelocity(velocity)
12864
- self:I(UTILS.PrintTableToLog(Coordinate))
13082
+ self:T(UTILS.PrintTableToLog(Coordinate))
12865
13083
  end
12866
13084
  return Coordinate
12867
13085
  end
@@ -13728,7 +13946,7 @@ self:I("_EventPlayerEnterUnit")
13728
13946
  if Event.IniDCSUnit then
13729
13947
  if Event.IniObjectCategory==Object.Category.UNIT and Event.IniGroup and Event.IniGroup:IsGround()then
13730
13948
  local ObjectName,Object=self:AddInDatabase(Event)
13731
- self:I(ObjectName,UTILS.PrintTableToLog(Object))
13949
+ self:T(ObjectName,UTILS.PrintTableToLog(Object))
13732
13950
  if Object and self:IsIncludeObject(Object)then
13733
13951
  self:Add(ObjectName,Object)
13734
13952
  end
@@ -15951,6 +16169,7 @@ return umin
15951
16169
  end
15952
16170
  function COORDINATE:DistanceFromPointVec2(PointVec2Reference)
15953
16171
  self:F2(PointVec2Reference)
16172
+ if not PointVec2Reference then return math.huge end
15954
16173
  local Distance=((PointVec2Reference.x-self.x)^2+(PointVec2Reference.z-self.z)^2)^0.5
15955
16174
  self:T2(Distance)
15956
16175
  return Distance
@@ -17154,17 +17373,18 @@ local coord=COORDINATE:NewFromVec2({x=point.x,y=point.z})
17154
17373
  return coord
17155
17374
  end
17156
17375
  function COORDINATE:NewFromMGRS(UTMZone,MGRSDigraph,Easting,Northing)
17157
- if string.len(Easting)<5 then Easting=Easting..string.rep("0",5-string.len(Easting))end
17158
- if string.len(Northing)<5 then Northing=Northing..string.rep("0",5-string.len(Northing))end
17376
+ if string.len(Easting)<5 then Easting=tostring(Easting..string.rep("0",5-string.len(Easting)))end
17377
+ if string.len(Northing)<5 then Northing=tostring(Northing..string.rep("0",5-string.len(Northing)))end
17159
17378
  local MGRS={
17160
17379
  UTMZone=UTMZone,
17161
17380
  MGRSDigraph=MGRSDigraph,
17162
- Easting=Easting,
17163
- Northing=Northing,
17381
+ Easting=tostring(Easting),
17382
+ Northing=tostring(Northing),
17164
17383
  }
17165
17384
  local lat,lon=coord.MGRStoLL(MGRS)
17166
17385
  local point=coord.LLtoLO(lat,lon,0)
17167
17386
  local coord=COORDINATE:NewFromVec2({x=point.x,y=point.z})
17387
+ return coord
17168
17388
  end
17169
17389
  function COORDINATE:ToStringFromRP(ReferenceCoord,ReferenceName,Controllable,Settings,MagVar)
17170
17390
  self:F2({ReferenceCoord=ReferenceCoord,ReferenceName=ReferenceName})
@@ -18408,7 +18628,7 @@ BASE:I("ERROR: in function NewFromTemplate, required parameter SpawnTemplatePref
18408
18628
  return nil
18409
18629
  end
18410
18630
  if SpawnTemplate then
18411
- self.SpawnTemplate=SpawnTemplate
18631
+ self.SpawnTemplate=UTILS.DeepCopy(SpawnTemplate)
18412
18632
  self.SpawnTemplatePrefix=SpawnTemplatePrefix
18413
18633
  self.SpawnAliasPrefix=SpawnAliasPrefix or SpawnTemplatePrefix
18414
18634
  self.SpawnTemplate.name=SpawnTemplatePrefix
@@ -18525,6 +18745,56 @@ self.SpawnInitSkill="High"
18525
18745
  end
18526
18746
  return self
18527
18747
  end
18748
+ function SPAWN:InitSTN(Octal)
18749
+ self:F({Octal=Octal})
18750
+ self.SpawnInitSTN=Octal or 77777
18751
+ local num=UTILS.OctalToDecimal(Octal)
18752
+ if num==nil or num<1 then
18753
+ self:E("WARNING - STN "..tostring(Octal).." is not valid!")
18754
+ return self
18755
+ end
18756
+ if _DATABASE.STNS[num]~=nil then
18757
+ self:E("WARNING - STN already assigned: "..tostring(Octal).." is used for ".._DATABASE.STNS[Octal])
18758
+ end
18759
+ return self
18760
+ end
18761
+ function SPAWN:InitSADL(Octal)
18762
+ self:F({Octal=Octal})
18763
+ self.SpawnInitSADL=Octal or 7777
18764
+ local num=UTILS.OctalToDecimal(Octal)
18765
+ if num==nil or num<1 then
18766
+ self:E("WARNING - SADL "..tostring(Octal).." is not valid!")
18767
+ return self
18768
+ end
18769
+ if _DATABASE.SADL[num]~=nil then
18770
+ self:E("WARNING - SADL already assigned: "..tostring(Octal).." is used for ".._DATABASE.SADL[Octal])
18771
+ end
18772
+ return self
18773
+ end
18774
+ function SPAWN:InitSpeedMps(MPS)
18775
+ self:F({MPS=MPS})
18776
+ if MPS==nil or tonumber(MPS)<0 then
18777
+ MPS=125
18778
+ end
18779
+ self.InitSpeed=MPS
18780
+ return self
18781
+ end
18782
+ function SPAWN:InitSpeedKnots(Knots)
18783
+ self:F({Knots=Knots})
18784
+ if Knots==nil or tonumber(Knots)<0 then
18785
+ Knots=300
18786
+ end
18787
+ self.InitSpeed=UTILS.KnotsToMps(Knots)
18788
+ return self
18789
+ end
18790
+ function SPAWN:InitSpeedKph(KPH)
18791
+ self:F({KPH=KPH})
18792
+ if KPH==nil or tonumber(KPH)<0 then
18793
+ KPH=UTILS.KnotsToKmph(300)
18794
+ end
18795
+ self.InitSpeed=UTILS.KmphToMps(KPH)
18796
+ return self
18797
+ end
18528
18798
  function SPAWN:InitRadioCommsOnOff(switch)
18529
18799
  self:F({switch=switch})
18530
18800
  self.SpawnInitRadio=switch or true
@@ -18644,11 +18914,12 @@ self.SpawnRandomCallsign=true
18644
18914
  return self
18645
18915
  end
18646
18916
  function SPAWN:InitCallSign(ID,Name,Minor,Major)
18917
+ local Name=Name or"Enfield"
18647
18918
  self.SpawnInitCallSign=true
18648
18919
  self.SpawnInitCallSignID=ID or 1
18649
18920
  self.SpawnInitCallSignMinor=Minor or 1
18650
18921
  self.SpawnInitCallSignMajor=Major or 1
18651
- self.SpawnInitCallSignName=string.lower(Name)or"enfield"
18922
+ self.SpawnInitCallSignName=string.lower(Name):gsub("^%l",string.upper)
18652
18923
  return self
18653
18924
  end
18654
18925
  function SPAWN:InitPositionCoordinate(Coordinate)
@@ -18761,6 +19032,18 @@ function SPAWN:InitDelayOff()
18761
19032
  return self:InitDelayOnOff(false)
18762
19033
  end
18763
19034
  end
19035
+ function SPAWN:InitHiddenOnMap()
19036
+ self.SpawnHiddenOnMap=true
19037
+ return self
19038
+ end
19039
+ function SPAWN:InitHiddenOnMFD()
19040
+ self.SpawnHiddenOnMFD=true
19041
+ return self
19042
+ end
19043
+ function SPAWN:InitHiddenOnPlanner()
19044
+ self.SpawnHiddenOnPlanner=true
19045
+ return self
19046
+ end
18764
19047
  function SPAWN:Spawn()
18765
19048
  self:F({self.SpawnTemplatePrefix,self.SpawnIndex,self.AliveUnits})
18766
19049
  if self.SpawnInitAirbase then
@@ -18953,6 +19236,15 @@ end
18953
19236
  if self.SpawnInitModu then
18954
19237
  SpawnTemplate.modulation=self.SpawnInitModu
18955
19238
  end
19239
+ if self.SpawnHiddenOnPlanner then
19240
+ SpawnTemplate.hiddenOnPlanner=true
19241
+ end
19242
+ if self.SpawnHiddenOnMFD then
19243
+ SpawnTemplate.hiddenOnMFD=true
19244
+ end
19245
+ if self.SpawnHiddenOnMap then
19246
+ SpawnTemplate.hidden=true
19247
+ end
18956
19248
  SpawnTemplate.CategoryID=self.SpawnInitCategory or SpawnTemplate.CategoryID
18957
19249
  SpawnTemplate.CountryID=self.SpawnInitCountry or SpawnTemplate.CountryID
18958
19250
  SpawnTemplate.CoalitionID=self.SpawnInitCoalition or SpawnTemplate.CoalitionID
@@ -18981,6 +19273,7 @@ self.SpawnHookScheduler:Schedule(nil,self.SpawnFunctionHook,{self.SpawnGroups[se
18981
19273
  end
18982
19274
  end
18983
19275
  self.SpawnGroups[self.SpawnIndex].Spawned=true
19276
+ self.SpawnGroups[self.SpawnIndex].Group.TemplateDonor=self.SpawnTemplatePrefix
18984
19277
  return self.SpawnGroups[self.SpawnIndex].Group
18985
19278
  else
18986
19279
  end
@@ -19786,8 +20079,17 @@ SpawnTemplate.units[UnitID].unitId=nil
19786
20079
  end
19787
20080
  else
19788
20081
  for UnitID=1,#SpawnTemplate.units do
19789
- local UnitPrefix,Rest=string.match(SpawnTemplate.units[UnitID].name,"^([^#]+)#?"):gsub("^%s*(.-)%s*$","%1")
20082
+ local SpawnInitKeepUnitIFF=false
20083
+ if string.find(SpawnTemplate.units[UnitID].name,"#IFF_",1,true)then
20084
+ SpawnInitKeepUnitIFF=true
20085
+ end
20086
+ local UnitPrefix,Rest
20087
+ if SpawnInitKeepUnitIFF==false then
20088
+ UnitPrefix,Rest=string.match(SpawnTemplate.units[UnitID].name,"^([^#]+)#?"):gsub("^%s*(.-)%s*$","%1")
19790
20089
  self:T({UnitPrefix,Rest})
20090
+ else
20091
+ UnitPrefix=SpawnTemplate.units[UnitID].name
20092
+ end
19791
20093
  SpawnTemplate.units[UnitID].name=string.format('%s#%03d-%02d',UnitPrefix,SpawnIndex,UnitID)
19792
20094
  SpawnTemplate.units[UnitID].unitId=nil
19793
20095
  end
@@ -19859,32 +20161,54 @@ elseif type(Callsign)=="number"then
19859
20161
  SpawnTemplate.units[UnitID].callsign=Callsign+SpawnIndex
19860
20162
  end
19861
20163
  end
20164
+ if self.InitSpeed then
20165
+ SpawnTemplate.units[UnitID].speed=self.InitSpeed
20166
+ end
19862
20167
  local AddProps=SpawnTemplate.units[UnitID].AddPropAircraft
19863
20168
  if AddProps then
19864
20169
  if SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 then
20170
+ if self.SpawnInitSTN then
20171
+ local octal=self.SpawnInitSTN
20172
+ if UnitID>1 then
20173
+ octal=_DATABASE:GetNextSTN(self.SpawnInitSTN,SpawnTemplate.units[UnitID].name)
20174
+ end
20175
+ SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16=string.format("%05d",octal)
20176
+ else
19865
20177
  if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16)~=nil then
19866
20178
  local octal=SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16
19867
- local decimal=UTILS.OctalToDecimal(octal)+UnitID-1
19868
- SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16=string.format("%05d",UTILS.DecimalToOctal(decimal))
20179
+ local num=UTILS.OctalToDecimal(octal)
20180
+ if _DATABASE.STNS[num]~=nil or UnitID>1 then
20181
+ octal=_DATABASE:GetNextSTN(octal,SpawnTemplate.units[UnitID].name)
20182
+ end
20183
+ SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16=string.format("%05d",octal)
19869
20184
  else
19870
- local STN=math.floor(UTILS.RandomGaussian(4088/2,nil,1000,4088))
19871
- STN=STN+UnitID-1
19872
- local OSTN=UTILS.DecimalToOctal(STN)
20185
+ local OSTN=_DATABASE:GetNextSTN(1,SpawnTemplate.units[UnitID].name)
19873
20186
  SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16=string.format("%05d",OSTN)
19874
20187
  end
19875
20188
  end
20189
+ end
19876
20190
  if SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN then
20191
+ if self.SpawnInitSADL then
20192
+ local octal=self.SpawnInitSADL
20193
+ if UnitID>1 then
20194
+ octal=_DATABASE:GetNextSADL(self.SpawnInitSADL,SpawnTemplate.units[UnitID].name)
20195
+ end
20196
+ SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN=string.format("%04d",octal)
20197
+ else
19877
20198
  if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN)~=nil then
19878
20199
  local octal=SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN
19879
- local decimal=UTILS.OctalToDecimal(octal)+UnitID-1
19880
- SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN=string.format("%04d",UTILS.DecimalToOctal(decimal))
20200
+ local num=UTILS.OctalToDecimal(octal)
20201
+ self.SpawnInitSADL=num
20202
+ if _DATABASE.SADL[num]~=nil or UnitID>1 then
20203
+ octal=_DATABASE:GetNextSADL(self.SpawnInitSADL,SpawnTemplate.units[UnitID].name)
20204
+ end
20205
+ SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN=string.format("%04d",octal)
19881
20206
  else
19882
- local STN=math.floor(UTILS.RandomGaussian(504/2,nil,100,504))
19883
- STN=STN+UnitID-1
19884
- local OSTN=UTILS.DecimalToOctal(STN)
20207
+ local OSTN=_DATABASE:GetNextSADL(1,SpawnTemplate.units[UnitID].name)
19885
20208
  SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN=string.format("%04d",OSTN)
19886
20209
  end
19887
20210
  end
20211
+ end
19888
20212
  if SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignNumber and type(Callsign)~="number"then
19889
20213
  SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignNumber=SpawnTemplate.units[UnitID].callsign[2]..SpawnTemplate.units[UnitID].callsign[3]
19890
20214
  end
@@ -20648,7 +20972,7 @@ MARKEROPS_BASE={
20648
20972
  ClassName="MARKEROPS",
20649
20973
  Tag="mytag",
20650
20974
  Keywords={},
20651
- version="0.1.1",
20975
+ version="0.1.3",
20652
20976
  debug=false,
20653
20977
  Casesensitive=true,
20654
20978
  }
@@ -20688,26 +21012,27 @@ local coordtext=coord:ToStringLLDDM()
20688
21012
  local text=tostring(Event.text)
20689
21013
  local m=MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
20690
21014
  end
21015
+ local coalition=Event.MarkCoalition
20691
21016
  if Event.id==world.event.S_EVENT_MARK_ADDED then
20692
- self:T({event="S_EVENT_MARK_ADDED",carrier=self.groupname,vec3=Event.pos})
21017
+ self:T({event="S_EVENT_MARK_ADDED",carrier=Event.IniGroupName,vec3=Event.pos})
20693
21018
  local Eventtext=tostring(Event.text)
20694
21019
  if Eventtext~=nil then
20695
21020
  if self:_MatchTag(Eventtext)then
20696
21021
  local matchtable=self:_MatchKeywords(Eventtext)
20697
- self:MarkAdded(Eventtext,matchtable,coord)
21022
+ self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition)
20698
21023
  end
20699
21024
  end
20700
21025
  elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
20701
- self:T({event="S_EVENT_MARK_CHANGE",carrier=self.groupname,vec3=Event.pos})
21026
+ self:T({event="S_EVENT_MARK_CHANGE",carrier=Event.IniGroupName,vec3=Event.pos})
20702
21027
  local Eventtext=tostring(Event.text)
20703
21028
  if Eventtext~=nil then
20704
21029
  if self:_MatchTag(Eventtext)then
20705
21030
  local matchtable=self:_MatchKeywords(Eventtext)
20706
- self:MarkChanged(Eventtext,matchtable,coord,Event.idx)
21031
+ self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition)
20707
21032
  end
20708
21033
  end
20709
21034
  elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
20710
- self:T({event="S_EVENT_MARK_REMOVED",carrier=self.groupname,vec3=Event.pos})
21035
+ self:T({event="S_EVENT_MARK_REMOVED",carrier=Event.IniGroupName,vec3=Event.pos})
20711
21036
  local Eventtext=tostring(Event.text)
20712
21037
  if Eventtext~=nil then
20713
21038
  if self:_MatchTag(Eventtext)then
@@ -20741,10 +21066,10 @@ end
20741
21066
  end
20742
21067
  return matchtable
20743
21068
  end
20744
- function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord)
21069
+ function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord,MarkerID,CoalitionNumber)
20745
21070
  self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
20746
21071
  end
20747
- function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord)
21072
+ function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord,MarkerID,CoalitionNumber)
20748
21073
  self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
20749
21074
  end
20750
21075
  function MARKEROPS_BASE:onbeforeMarkDeleted(From,Event,To)
@@ -23225,7 +23550,7 @@ local TaskRoute=PatrolGroup:TaskFunction("CONTROLLABLE.PatrolRoute")
23225
23550
  self:F({Waypoints=Waypoints})
23226
23551
  local Waypoint=Waypoints[#Waypoints]
23227
23552
  PatrolGroup:SetTaskWaypoint(Waypoint,TaskRoute)
23228
- PatrolGroup:Route(Waypoints)
23553
+ PatrolGroup:Route(Waypoints,2)
23229
23554
  end
23230
23555
  end
23231
23556
  function CONTROLLABLE:PatrolRouteRandom(Speed,Formation,ToWaypoint)
@@ -24183,6 +24508,9 @@ return nil
24183
24508
  end
24184
24509
  function CONTROLLABLE:WayPointFunction(WayPoint,WayPointIndex,WayPointFunction,...)
24185
24510
  self:F2({WayPoint,WayPointIndex,WayPointFunction})
24511
+ if not self.WayPoints then
24512
+ self:WayPointInitialize()
24513
+ end
24186
24514
  table.insert(self.WayPoints[WayPoint].task.params.tasks,WayPointIndex)
24187
24515
  self.WayPoints[WayPoint].task.params.tasks[WayPointIndex]=self:TaskFunction(WayPointFunction,arg)
24188
24516
  return self
@@ -24306,6 +24634,49 @@ self:SetOption(AI.Option.Air.id.RADAR_USING,3)
24306
24634
  end
24307
24635
  return self
24308
24636
  end
24637
+ function CONTROLLABLE:SetOptionWaypointPassReport(OnOff)
24638
+ self:F2({self.ControllableName})
24639
+ local onoff=(OnOff==nil or OnOff==true)and false or true
24640
+ if self:IsAir()then
24641
+ self:SetOption(AI.Option.Air.id.PROHIBIT_WP_PASS_REPORT,onoff)
24642
+ end
24643
+ return self
24644
+ end
24645
+ function CONTROLLABLE:SetOptionRadioSilence(OnOff)
24646
+ local onoff=(OnOff==true or OnOff==nil)and true or false
24647
+ self:F2({self.ControllableName})
24648
+ if self:IsAir()then
24649
+ self:SetOption(AI.Option.Air.id.SILENCE,onoff)
24650
+ end
24651
+ return self
24652
+ end
24653
+ function CONTROLLABLE:SetOptionRadioContact(Objects)
24654
+ self:F2({self.ControllableName})
24655
+ if not Objects then Objects={"Air"}end
24656
+ if type(Objects)~="table"then Objects={Objects}end
24657
+ if self:IsAir()then
24658
+ self:SetOption(AI.Option.Air.id.OPTION_RADIO_USAGE_CONTACT,Objects)
24659
+ end
24660
+ return self
24661
+ end
24662
+ function CONTROLLABLE:SetOptionRadioEngage(Objects)
24663
+ self:F2({self.ControllableName})
24664
+ if not Objects then Objects={"Air"}end
24665
+ if type(Objects)~="table"then Objects={Objects}end
24666
+ if self:IsAir()then
24667
+ self:SetOption(AI.Option.Air.id.OPTION_RADIO_USAGE_ENGAGE,Objects)
24668
+ end
24669
+ return self
24670
+ end
24671
+ function CONTROLLABLE:SetOptionRadioKill(Objects)
24672
+ self:F2({self.ControllableName})
24673
+ if not Objects then Objects={"Air"}end
24674
+ if type(Objects)~="table"then Objects={Objects}end
24675
+ if self:IsAir()then
24676
+ self:SetOption(AI.Option.Air.id.OPTION_RADIO_USAGE_KILL,Objects)
24677
+ end
24678
+ return self
24679
+ end
24309
24680
  function CONTROLLABLE:RelocateGroundRandomInRadius(speed,radius,onroad,shortcut,formation,onland)
24310
24681
  self:F2({self.ControllableName})
24311
24682
  local _coord=self:GetCoordinate()
@@ -25377,7 +25748,7 @@ end
25377
25748
  function GROUP:IsActive()
25378
25749
  self:F2(self.GroupName)
25379
25750
  local DCSGroup=self:GetDCSObject()
25380
- if DCSGroup then
25751
+ if DCSGroup and DCSGroup:isExist()then
25381
25752
  local unit=DCSGroup:getUnit(1)
25382
25753
  if unit then
25383
25754
  local GroupIsActive=unit:isActive()
@@ -25835,7 +26206,7 @@ function GROUP:GetCoordinate()
25835
26206
  local Units=self:GetUnits()or{}
25836
26207
  for _,_unit in pairs(Units)do
25837
26208
  local FirstUnit=_unit
25838
- if FirstUnit then
26209
+ if FirstUnit and FirstUnit:IsAlive()then
25839
26210
  local FirstUnitCoordinate=FirstUnit:GetCoordinate()
25840
26211
  if FirstUnitCoordinate then
25841
26212
  local Heading=self:GetHeading()
@@ -25844,6 +26215,18 @@ return FirstUnitCoordinate
25844
26215
  end
25845
26216
  end
25846
26217
  end
26218
+ local DCSGroup=Group.getByName(self.GroupName)
26219
+ local DCSUnits=DCSGroup:getUnits()or{}
26220
+ for _,_unit in pairs(DCSUnits)do
26221
+ if Object.isExist(_unit)then
26222
+ local position=_unit:getPosition()
26223
+ local point=position.p~=nil and position.p or _unit:GetPoint()
26224
+ if point then
26225
+ local coord=COORDINATE:NewFromVec3(point)
26226
+ return coord
26227
+ end
26228
+ end
26229
+ end
25847
26230
  BASE:E({"Cannot GetCoordinate",Group=self,Alive=self:IsAlive()})
25848
26231
  end
25849
26232
  function GROUP:GetRandomVec3(Radius)
@@ -26705,6 +27088,9 @@ end
26705
27088
  return self
26706
27089
  end
26707
27090
  function GROUP:SetCommandInvisible(switch)
27091
+ return self:CommandSetInvisible(switch)
27092
+ end
27093
+ function GROUP:CommandSetInvisible(switch)
26708
27094
  self:F2(self.GroupName)
26709
27095
  if switch==nil then
26710
27096
  switch=false
@@ -26714,6 +27100,9 @@ self:SetCommand(SetInvisible)
26714
27100
  return self
26715
27101
  end
26716
27102
  function GROUP:SetCommandImmortal(switch)
27103
+ return self:CommandSetImmortal(switch)
27104
+ end
27105
+ function GROUP:CommandSetImmortal(switch)
26717
27106
  self:F2(self.GroupName)
26718
27107
  if switch==nil then
26719
27108
  switch=false
@@ -27445,7 +27834,9 @@ local ThreatLevels={
27445
27834
  }
27446
27835
  if Attributes["Fighters"]then ThreatLevel=10
27447
27836
  elseif Attributes["Multirole fighters"]then ThreatLevel=9
27837
+ elseif Attributes["Interceptors"]then ThreatLevel=9
27448
27838
  elseif Attributes["Battleplanes"]then ThreatLevel=8
27839
+ elseif Attributes["Battle airplanes"]then ThreatLevel=8
27449
27840
  elseif Attributes["Attack helicopters"]then ThreatLevel=7
27450
27841
  elseif Attributes["Strategic bombers"]then ThreatLevel=6
27451
27842
  elseif Attributes["Bombers"]then ThreatLevel=5
@@ -28075,6 +28466,25 @@ SpawnStatic:SpawnFromCoordinate(Coordinate,Heading,self.StaticName)
28075
28466
  end
28076
28467
  return self
28077
28468
  end
28469
+ function STATIC:FindByMatching(Pattern)
28470
+ local GroupFound=nil
28471
+ for name,static in pairs(_DATABASE.STATICS)do
28472
+ if string.match(name,Pattern)then
28473
+ GroupFound=static
28474
+ break
28475
+ end
28476
+ end
28477
+ return GroupFound
28478
+ end
28479
+ function STATIC:FindAllByMatching(Pattern)
28480
+ local GroupsFound={}
28481
+ for name,static in pairs(_DATABASE.STATICS)do
28482
+ if string.match(name,Pattern)then
28483
+ GroupsFound[#GroupsFound+1]=static
28484
+ end
28485
+ end
28486
+ return GroupsFound
28487
+ end
28078
28488
  AIRBASE={
28079
28489
  ClassName="AIRBASE",
28080
28490
  CategoryName={
@@ -28085,152 +28495,155 @@ CategoryName={
28085
28495
  activerwyno=nil,
28086
28496
  }
28087
28497
  AIRBASE.Caucasus={
28498
+ ["Anapa_Vityazevo"]="Anapa-Vityazevo",
28499
+ ["Batumi"]="Batumi",
28500
+ ["Beslan"]="Beslan",
28088
28501
  ["Gelendzhik"]="Gelendzhik",
28089
- ["Krasnodar_Pashkovsky"]="Krasnodar-Pashkovsky",
28090
- ["Sukhumi_Babushara"]="Sukhumi-Babushara",
28091
28502
  ["Gudauta"]="Gudauta",
28092
- ["Batumi"]="Batumi",
28093
- ["Senaki_Kolkhi"]="Senaki-Kolkhi",
28094
28503
  ["Kobuleti"]="Kobuleti",
28095
- ["Kutaisi"]="Kutaisi",
28096
- ["Tbilisi_Lochini"]="Tbilisi-Lochini",
28097
- ["Soganlug"]="Soganlug",
28098
- ["Vaziani"]="Vaziani",
28099
- ["Anapa_Vityazevo"]="Anapa-Vityazevo",
28100
28504
  ["Krasnodar_Center"]="Krasnodar-Center",
28101
- ["Novorossiysk"]="Novorossiysk",
28505
+ ["Krasnodar_Pashkovsky"]="Krasnodar-Pashkovsky",
28102
28506
  ["Krymsk"]="Krymsk",
28507
+ ["Kutaisi"]="Kutaisi",
28103
28508
  ["Maykop_Khanskaya"]="Maykop-Khanskaya",
28104
- ["Sochi_Adler"]="Sochi-Adler",
28105
28509
  ["Mineralnye_Vody"]="Mineralnye Vody",
28106
- ["Nalchik"]="Nalchik",
28107
28510
  ["Mozdok"]="Mozdok",
28108
- ["Beslan"]="Beslan",
28511
+ ["Nalchik"]="Nalchik",
28512
+ ["Novorossiysk"]="Novorossiysk",
28513
+ ["Senaki_Kolkhi"]="Senaki-Kolkhi",
28514
+ ["Sochi_Adler"]="Sochi-Adler",
28515
+ ["Soganlug"]="Soganlug",
28516
+ ["Sukhumi_Babushara"]="Sukhumi-Babushara",
28517
+ ["Tbilisi_Lochini"]="Tbilisi-Lochini",
28518
+ ["Vaziani"]="Vaziani",
28109
28519
  }
28110
28520
  AIRBASE.Nevada={
28111
- ["Creech_AFB"]="Creech",
28112
- ["Groom_Lake_AFB"]="Groom Lake",
28113
- ["McCarran_International_Airport"]="McCarran International",
28114
- ["Nellis_AFB"]="Nellis",
28115
- ["Beatty_Airport"]="Beatty",
28116
- ["Boulder_City_Airport"]="Boulder City",
28521
+ ["Beatty"]="Beatty",
28522
+ ["Boulder_City"]="Boulder City",
28523
+ ["Creech"]="Creech",
28117
28524
  ["Echo_Bay"]="Echo Bay",
28118
- ["Henderson_Executive_Airport"]="Henderson Executive",
28119
- ["Jean_Airport"]="Jean",
28120
- ["Laughlin_Airport"]="Laughlin",
28525
+ ["Groom_Lake"]="Groom Lake",
28526
+ ["Henderson_Executive"]="Henderson Executive",
28527
+ ["Jean"]="Jean",
28528
+ ["Laughlin"]="Laughlin",
28121
28529
  ["Lincoln_County"]="Lincoln County",
28530
+ ["McCarran_International"]="McCarran International",
28122
28531
  ["Mesquite"]="Mesquite",
28123
- ["Mina_Airport"]="Mina",
28532
+ ["Mina"]="Mina",
28533
+ ["Nellis"]="Nellis",
28124
28534
  ["North_Las_Vegas"]="North Las Vegas",
28125
- ["Pahute_Mesa_Airstrip"]="Pahute Mesa",
28126
- ["Tonopah_Airport"]="Tonopah",
28127
- ["Tonopah_Test_Range_Airfield"]="Tonopah Test Range",
28535
+ ["Pahute_Mesa"]="Pahute Mesa",
28536
+ ["Tonopah"]="Tonopah",
28537
+ ["Tonopah_Test_Range"]="Tonopah Test Range",
28128
28538
  }
28129
28539
  AIRBASE.Normandy={
28130
- ["Saint_Pierre_du_Mont"]="Saint Pierre du Mont",
28131
- ["Lignerolles"]="Lignerolles",
28132
- ["Cretteville"]="Cretteville",
28133
- ["Maupertus"]="Maupertus",
28134
- ["Brucheville"]="Brucheville",
28135
- ["Meautis"]="Meautis",
28136
- ["Cricqueville_en_Bessin"]="Cricqueville-en-Bessin",
28137
- ["Lessay"]="Lessay",
28138
- ["Sainte_Laurent_sur_Mer"]="Sainte-Laurent-sur-Mer",
28139
- ["Biniville"]="Biniville",
28140
- ["Cardonville"]="Cardonville",
28141
- ["Deux_Jumeaux"]="Deux Jumeaux",
28142
- ["Chippelle"]="Chippelle",
28143
- ["Beuzeville"]="Beuzeville",
28540
+ ["Abbeville_Drucat"]="Abbeville Drucat",
28541
+ ["Amiens_Glisy"]="Amiens-Glisy",
28542
+ ["Argentan"]="Argentan",
28543
+ ["Avranches_Le_Val_Saint_Pere"]="Avranches Le Val-Saint-Pere",
28144
28544
  ["Azeville"]="Azeville",
28145
- ["Picauville"]="Picauville",
28146
- ["Le_Molay"]="Le Molay",
28147
- ["Longues_sur_Mer"]="Longues-sur-Mer",
28148
- ["Carpiquet"]="Carpiquet",
28545
+ ["Barville"]="Barville",
28149
28546
  ["Bazenville"]="Bazenville",
28150
- ["Sainte_Croix_sur_Mer"]="Sainte-Croix-sur-Mer",
28547
+ ["Beaumont_le_Roger"]="Beaumont-le-Roger",
28548
+ ["Beauvais_Tille"]="Beauvais-Tille",
28151
28549
  ["Beny_sur_Mer"]="Beny-sur-Mer",
28152
- ["Rucqueville"]="Rucqueville",
28153
- ["Sommervieu"]="Sommervieu",
28154
- ["Lantheuil"]="Lantheuil",
28155
- ["Evreux"]="Evreux",
28550
+ ["Bernay_Saint_Martin"]="Bernay Saint Martin",
28551
+ ["Beuzeville"]="Beuzeville",
28552
+ ["Biggin_Hill"]="Biggin Hill",
28553
+ ["Biniville"]="Biniville",
28554
+ ["Broglie"]="Broglie",
28555
+ ["Brucheville"]="Brucheville",
28556
+ ["Cardonville"]="Cardonville",
28557
+ ["Carpiquet"]="Carpiquet",
28156
28558
  ["Chailey"]="Chailey",
28157
- ["Needs_Oar_Point"]="Needs Oar Point",
28158
- ["Funtington"]="Funtington",
28159
- ["Tangmere"]="Tangmere",
28160
- ["Ford"]="Ford",
28161
- ["Argentan"]="Argentan",
28162
- ["Goulet"]="Goulet",
28163
- ["Barville"]="Barville",
28164
- ["Essay"]="Essay",
28165
- ["Hauterive"]="Hauterive",
28166
- ["Lymington"]="Lymington",
28167
- ["Vrigny"]="Vrigny",
28168
- ["Odiham"]="Odiham",
28559
+ ["Chippelle"]="Chippelle",
28169
28560
  ["Conches"]="Conches",
28170
- ["West_Malling"]="West Malling",
28171
- ["Villacoublay"]="Villacoublay",
28172
- ["Kenley"]="Kenley",
28173
- ["Beauvais_Tille"]="Beauvais-Tille",
28174
28561
  ["Cormeilles_en_Vexin"]="Cormeilles-en-Vexin",
28175
28562
  ["Creil"]="Creil",
28176
- ["Guyancourt"]="Guyancourt",
28177
- ["Lonrai"]="Lonrai",
28563
+ ["Cretteville"]="Cretteville",
28564
+ ["Cricqueville_en_Bessin"]="Cricqueville-en-Bessin",
28565
+ ["Deanland"]="Deanland",
28566
+ ["Deauville"]="Deauville",
28567
+ ["Detling"]="Detling",
28568
+ ["Deux_Jumeaux"]="Deux Jumeaux",
28178
28569
  ["Dinan_Trelivan"]="Dinan-Trelivan",
28179
- ["Heathrow"]="Heathrow",
28180
- ["Fecamp_Benouville"]="Fecamp-Benouville",
28570
+ ["Dunkirk_Mardyck"]="Dunkirk-Mardyck",
28571
+ ["Essay"]="Essay",
28572
+ ["Evreux"]="Evreux",
28181
28573
  ["Farnborough"]="Farnborough",
28574
+ ["Fecamp_Benouville"]="Fecamp-Benouville",
28575
+ ["Flers"]="Flers",
28576
+ ["Ford"]="Ford",
28182
28577
  ["Friston"]="Friston",
28183
- ["Deanland "]="Deanland ",
28184
- ["Triqueville"]="Triqueville",
28185
- ["Poix"]="Poix",
28578
+ ["Funtington"]="Funtington",
28579
+ ["Goulet"]="Goulet",
28580
+ ["Gravesend"]="Gravesend",
28581
+ ["Guyancourt"]="Guyancourt",
28582
+ ["Hauterive"]="Hauterive",
28583
+ ["Heathrow"]="Heathrow",
28584
+ ["High_Halden"]="High Halden",
28585
+ ["Kenley"]="Kenley",
28586
+ ["Lantheuil"]="Lantheuil",
28587
+ ["Le_Molay"]="Le Molay",
28588
+ ["Lessay"]="Lessay",
28589
+ ["Lignerolles"]="Lignerolles",
28590
+ ["Longues_sur_Mer"]="Longues-sur-Mer",
28591
+ ["Lonrai"]="Lonrai",
28592
+ ["Lymington"]="Lymington",
28593
+ ["Lympne"]="Lympne",
28594
+ ["Manston"]="Manston",
28595
+ ["Maupertus"]="Maupertus",
28596
+ ["Meautis"]="Meautis",
28597
+ ["Merville_Calonne"]="Merville Calonne",
28598
+ ["Needs_Oar_Point"]="Needs Oar Point",
28599
+ ["Odiham"]="Odiham",
28186
28600
  ["Orly"]="Orly",
28187
- ["Stoney_Cross"]="Stoney Cross",
28188
- ["Amiens_Glisy"]="Amiens-Glisy",
28601
+ ["Picauville"]="Picauville",
28602
+ ["Poix"]="Poix",
28189
28603
  ["Ronai"]="Ronai",
28190
28604
  ["Rouen_Boos"]="Rouen-Boos",
28191
- ["Deauville"]="Deauville",
28192
- ["Saint_Aubin"]="Saint-Aubin",
28193
- ["Flers"]="Flers",
28194
- ["Avranches_Le_Val_Saint_Pere"]="Avranches Le Val-Saint-Pere",
28195
- ["Gravesend"]="Gravesend",
28196
- ["Beaumont_le_Roger"]="Beaumont-le-Roger",
28197
- ["Broglie"]="Broglie",
28198
- ["Bernay_Saint_Martin"]="Bernay Saint Martin",
28605
+ ["Rucqueville"]="Rucqueville",
28199
28606
  ["Saint_Andre_de_lEure"]="Saint-Andre-de-lEure",
28200
- ["Biggin_Hill"]="Biggin Hill",
28201
- ["Manston"]="Manston",
28202
- ["Detling"]="Detling",
28203
- ["Lympne"]="Lympne",
28204
- ["Abbeville_Drucat"]="Abbeville Drucat",
28205
- ["Merville_Calonne"]="Merville Calonne",
28607
+ ["Saint_Aubin"]="Saint-Aubin",
28206
28608
  ["Saint_Omer_Wizernes"]="Saint-Omer Wizernes",
28609
+ ["Saint_Pierre_du_Mont"]="Saint Pierre du Mont",
28610
+ ["Sainte_Croix_sur_Mer"]="Sainte-Croix-sur-Mer",
28611
+ ["Sainte_Laurent_sur_Mer"]="Sainte-Laurent-sur-Mer",
28612
+ ["Sommervieu"]="Sommervieu",
28613
+ ["Stoney_Cross"]="Stoney Cross",
28614
+ ["Tangmere"]="Tangmere",
28615
+ ["Triqueville"]="Triqueville",
28616
+ ["Villacoublay"]="Villacoublay",
28617
+ ["Vrigny"]="Vrigny",
28618
+ ["West_Malling"]="West Malling",
28207
28619
  }
28208
28620
  AIRBASE.PersianGulf={
28209
- ["Abu_Dhabi_International_Airport"]="Abu Dhabi Intl",
28210
- ["Abu_Musa_Island_Airport"]="Abu Musa Island",
28211
- ["Al_Ain_International_Airport"]="Al Ain Intl",
28212
- ["Al_Bateen_Airport"]="Al-Bateen",
28213
- ["Al_Dhafra_AB"]="Al Dhafra AFB",
28621
+ ["Abu_Dhabi_Intl"]="Abu Dhabi Intl",
28622
+ ["Abu_Musa_Island"]="Abu Musa Island",
28623
+ ["Al_Ain_Intl"]="Al Ain Intl",
28624
+ ["Al_Bateen"]="Al-Bateen",
28625
+ ["Al_Dhafra_AFB"]="Al Dhafra AFB",
28214
28626
  ["Al_Maktoum_Intl"]="Al Maktoum Intl",
28215
- ["Al_Minhad_AB"]="Al Minhad AFB",
28627
+ ["Al_Minhad_AFB"]="Al Minhad AFB",
28216
28628
  ["Bandar_Abbas_Intl"]="Bandar Abbas Intl",
28217
28629
  ["Bandar_Lengeh"]="Bandar Lengeh",
28218
- ["Bandar_e_Jask_airfield"]="Bandar-e-Jask",
28630
+ ["Bandar_e_Jask"]="Bandar-e-Jask",
28219
28631
  ["Dubai_Intl"]="Dubai Intl",
28220
28632
  ["Fujairah_Intl"]="Fujairah Intl",
28221
28633
  ["Havadarya"]="Havadarya",
28222
- ["Jiroft_Airport"]="Jiroft",
28223
- ["Kerman_Airport"]="Kerman",
28634
+ ["Jiroft"]="Jiroft",
28635
+ ["Kerman"]="Kerman",
28224
28636
  ["Khasab"]="Khasab",
28225
- ["Kish_International_Airport"]="Kish Intl",
28226
- ["Lar_Airbase"]="Lar",
28227
- ["Lavan_Island_Airport"]="Lavan Island",
28228
- ["Liwa_Airbase"]="Liwa AFB",
28637
+ ["Kish_Intl"]="Kish Intl",
28638
+ ["Lar"]="Lar",
28639
+ ["Lavan_Island"]="Lavan Island",
28640
+ ["Liwa_AFB"]="Liwa AFB",
28229
28641
  ["Qeshm_Island"]="Qeshm Island",
28230
- ["Ras_Al_Khaimah"]="Ras Al Khaimah Intl",
28231
- ["Sas_Al_Nakheel_Airport"]="Sas Al Nakheel",
28642
+ ["Quasoura_airport"]="Quasoura_airport",
28643
+ ["Ras_Al_Khaimah_Intl"]="Ras Al Khaimah Intl",
28644
+ ["Sas_Al_Nakheel"]="Sas Al Nakheel",
28232
28645
  ["Sharjah_Intl"]="Sharjah Intl",
28233
- ["Shiraz_International_Airport"]="Shiraz Intl",
28646
+ ["Shiraz_Intl"]="Shiraz Intl",
28234
28647
  ["Sir_Abu_Nuayr"]="Sir Abu Nuayr",
28235
28648
  ["Sirri_Island"]="Sirri Island",
28236
28649
  ["Tunb_Island_AFB"]="Tunb Island AFB",
@@ -28238,156 +28651,178 @@ AIRBASE.PersianGulf={
28238
28651
  }
28239
28652
  AIRBASE.TheChannel={
28240
28653
  ["Abbeville_Drucat"]="Abbeville Drucat",
28241
- ["Merville_Calonne"]="Merville Calonne",
28242
- ["Saint_Omer_Longuenesse"]="Saint Omer Longuenesse",
28243
- ["Dunkirk_Mardyck"]="Dunkirk Mardyck",
28244
- ["Manston"]="Manston",
28245
- ["Hawkinge"]="Hawkinge",
28246
- ["Lympne"]="Lympne",
28247
- ["Detling"]="Detling",
28248
- ["High_Halden"]="High Halden",
28249
28654
  ["Biggin_Hill"]="Biggin Hill",
28655
+ ["Detling"]="Detling",
28656
+ ["Dunkirk_Mardyck"]="Dunkirk Mardyck",
28250
28657
  ["Eastchurch"]="Eastchurch",
28658
+ ["Hawkinge"]="Hawkinge",
28251
28659
  ["Headcorn"]="Headcorn",
28660
+ ["High_Halden"]="High Halden",
28661
+ ["Lympne"]="Lympne",
28662
+ ["Manston"]="Manston",
28663
+ ["Merville_Calonne"]="Merville Calonne",
28664
+ ["Saint_Omer_Longuenesse"]="Saint Omer Longuenesse",
28252
28665
  }
28253
28666
  AIRBASE.Syria={
28254
- ["Kuweires"]="Kuweires",
28255
- ["Marj_Ruhayyil"]="Marj Ruhayyil",
28256
- ["Kiryat_Shmona"]="Kiryat Shmona",
28257
- ["Marj_as_Sultan_North"]="Marj as Sultan North",
28258
- ["Eyn_Shemer"]="Eyn Shemer",
28259
- ["Incirlik"]="Incirlik",
28260
- ["Damascus"]="Damascus",
28261
- ["Bassel_Al_Assad"]="Bassel Al-Assad",
28262
- ["Rosh_Pina"]="Rosh Pina",
28263
- ["Aleppo"]="Aleppo",
28264
- ["Al_Qusayr"]="Al Qusayr",
28265
- ["Wujah_Al_Hajar"]="Wujah Al Hajar",
28667
+ ["Abu_al_Duhur"]="Abu al-Duhur",
28668
+ ["Adana_Sakirpasa"]="Adana Sakirpasa",
28669
+ ["Akrotiri"]="Akrotiri",
28266
28670
  ["Al_Dumayr"]="Al-Dumayr",
28671
+ ["Al_Qusayr"]="Al Qusayr",
28672
+ ["Aleppo"]="Aleppo",
28673
+ ["Amman"]="Amman",
28674
+ ["An_Nasiriyah"]="An Nasiriyah",
28675
+ ["At_Tanf"]="At Tanf",
28676
+ ["Bassel_Al_Assad"]="Bassel Al-Assad",
28677
+ ["Beirut_Rafic_Hariri"]="Beirut-Rafic Hariri",
28678
+ ["Damascus"]="Damascus",
28679
+ ["Deir_ez_Zor"]="Deir ez-Zor",
28680
+ ["Ercan"]="Ercan",
28681
+ ["Eyn_Shemer"]="Eyn Shemer",
28682
+ ["Gaziantep"]="Gaziantep",
28267
28683
  ["Gazipasa"]="Gazipasa",
28268
- ["Hatay"]="Hatay",
28269
- ["Pinarbashi"]="Pinarbashi",
28270
- ["Paphos"]="Paphos",
28271
- ["Kingsfield"]="Kingsfield",
28272
- ["Thalah"]="Tha'lah",
28684
+ ["Gecitkale"]="Gecitkale",
28685
+ ["H3"]="H3",
28686
+ ["H3_Northwest"]="H3 Northwest",
28687
+ ["H3_Southwest"]="H3 Southwest",
28688
+ ["H4"]="H4",
28273
28689
  ["Haifa"]="Haifa",
28690
+ ["Hama"]="Hama",
28691
+ ["Hatay"]="Hatay",
28692
+ ["Herzliya"]="Herzliya",
28693
+ ["Incirlik"]="Incirlik",
28694
+ ["Jirah"]="Jirah",
28274
28695
  ["Khalkhalah"]="Khalkhalah",
28275
- ["Megiddo"]="Megiddo",
28696
+ ["Kharab_Ishk"]="Kharab Ishk",
28697
+ ["King_Abdullah_II"]="King Abdullah II",
28698
+ ["King_Hussein_Air_College"]="King Hussein Air College",
28699
+ ["Kingsfield"]="Kingsfield",
28700
+ ["Kiryat_Shmona"]="Kiryat Shmona",
28701
+ ["Kuweires"]="Kuweires",
28276
28702
  ["Lakatamia"]="Lakatamia",
28277
- ["Rayak"]="Rayak",
28278
28703
  ["Larnaca"]="Larnaca",
28704
+ ["Marj_Ruhayyil"]="Marj Ruhayyil",
28705
+ ["Marj_as_Sultan_North"]="Marj as Sultan North",
28706
+ ["Marj_as_Sultan_South"]="Marj as Sultan South",
28707
+ ["Megiddo"]="Megiddo",
28279
28708
  ["Mezzeh"]="Mezzeh",
28280
- ["Gecitkale"]="Gecitkale",
28281
- ["Akrotiri"]="Akrotiri",
28282
- ["Naqoura"]="Naqoura",
28283
- ["Gaziantep"]="Gaziantep",
28284
- ["Sayqal"]="Sayqal",
28285
- ["Tiyas"]="Tiyas",
28286
- ["Shayrat"]="Shayrat",
28287
- ["Taftanaz"]="Taftanaz",
28288
- ["H4"]="H4",
28289
- ["King_Hussein_Air_College"]="King Hussein Air College",
28290
- ["Rene_Mouawad"]="Rene Mouawad",
28291
- ["Jirah"]="Jirah",
28292
- ["Ramat_David"]="Ramat David",
28293
- ["Qabr_as_Sitt"]="Qabr as Sitt",
28294
28709
  ["Minakh"]="Minakh",
28295
- ["Adana_Sakirpasa"]="Adana Sakirpasa",
28710
+ ["Muwaffaq_Salti"]="Muwaffaq Salti",
28711
+ ["Naqoura"]="Naqoura",
28712
+ ["Nicosia"]="Nicosia",
28296
28713
  ["Palmyra"]="Palmyra",
28297
- ["Hama"]="Hama",
28298
- ["Ercan"]="Ercan",
28299
- ["Marj_as_Sultan_South"]="Marj as Sultan South",
28300
- ["Tabqa"]="Tabqa",
28301
- ["Beirut_Rafic_Hariri"]="Beirut-Rafic Hariri",
28302
- ["An_Nasiriyah"]="An Nasiriyah",
28303
- ["Abu_al_Duhur"]="Abu al-Duhur",
28304
- ["At_Tanf"]="At Tanf",
28305
- ["H3"]="H3",
28306
- ["H3_Northwest"]="H3 Northwest",
28307
- ["H3_Southwest"]="H3 Southwest",
28308
- ["Kharab_Ishk"]="Kharab Ishk",
28714
+ ["Paphos"]="Paphos",
28715
+ ["Pinarbashi"]="Pinarbashi",
28716
+ ["Prince_Hassan"]="Prince Hassan",
28717
+ ["Qabr_as_Sitt"]="Qabr as Sitt",
28718
+ ["Ramat_David"]="Ramat David",
28719
+ ["Rayak"]="Rayak",
28720
+ ["Rene_Mouawad"]="Rene Mouawad",
28721
+ ["Rosh_Pina"]="Rosh Pina",
28309
28722
  ["Ruwayshid"]="Ruwayshid",
28310
28723
  ["Sanliurfa"]="Sanliurfa",
28724
+ ["Sayqal"]="Sayqal",
28725
+ ["Shayrat"]="Shayrat",
28726
+ ["Tabqa"]="Tabqa",
28727
+ ["Taftanaz"]="Taftanaz",
28311
28728
  ["Tal_Siman"]="Tal Siman",
28312
- ["Deir_ez_Zor"]="Deir ez-Zor",
28729
+ ["Tha_lah"]="Tha'lah",
28730
+ ["Tiyas"]="Tiyas",
28731
+ ["Wujah_Al_Hajar"]="Wujah Al Hajar",
28313
28732
  }
28314
28733
  AIRBASE.MarianaIslands={
28315
- ["Rota_Intl"]="Rota Intl",
28316
28734
  ["Andersen_AFB"]="Andersen AFB",
28317
28735
  ["Antonio_B_Won_Pat_Intl"]="Antonio B. Won Pat Intl",
28318
- ["Saipan_Intl"]="Saipan Intl",
28319
- ["Tinian_Intl"]="Tinian Intl",
28736
+ ["North_West_Field"]="North West Field",
28320
28737
  ["Olf_Orote"]="Olf Orote",
28321
28738
  ["Pagan_Airstrip"]="Pagan Airstrip",
28322
- ["North_West_Field"]="North West Field",
28739
+ ["Rota_Intl"]="Rota Intl",
28740
+ ["Saipan_Intl"]="Saipan Intl",
28741
+ ["Tinian_Intl"]="Tinian Intl",
28323
28742
  }
28324
28743
  AIRBASE.SouthAtlantic={
28325
- ["Port_Stanley"]="Port Stanley",
28744
+ ["Almirante_Schroeders"]="Almirante Schroeders",
28745
+ ["Caleta_Tortel"]="Caleta Tortel",
28746
+ ["Comandante_Luis_Piedrabuena"]="Comandante Luis Piedrabuena",
28747
+ ["Cullen"]="Cullen",
28748
+ ["El_Calafate"]="El Calafate",
28749
+ ["Franco_Bianco"]="Franco Bianco",
28750
+ ["Gobernador_Gregores"]="Gobernador Gregores",
28751
+ ["Goose_Green"]="Goose Green",
28752
+ ["Gull_Point"]="Gull Point",
28753
+ ["Hipico_Flying_Club"]="Hipico Flying Club",
28326
28754
  ["Mount_Pleasant"]="Mount Pleasant",
28327
- ["San_Carlos_FOB"]="San Carlos FOB",
28328
- ["Rio_Grande"]="Rio Grande",
28329
- ["Rio_Gallegos"]="Rio Gallegos",
28330
- ["Ushuaia"]="Ushuaia",
28331
- ["Ushuaia_Helo_Port"]="Ushuaia Helo Port",
28332
- ["Punta_Arenas"]="Punta Arenas",
28755
+ ["O_Higgins"]="O'Higgins",
28333
28756
  ["Pampa_Guanaco"]="Pampa Guanaco",
28334
- ["San_Julian"]="San Julian",
28335
- ["Puerto_Williams"]="Puerto Williams",
28757
+ ["Port_Stanley"]="Port Stanley",
28758
+ ["Porvenir"]="Porvenir",
28336
28759
  ["Puerto_Natales"]="Puerto Natales",
28337
- ["El_Calafate"]="El Calafate",
28338
28760
  ["Puerto_Santa_Cruz"]="Puerto Santa Cruz",
28339
- ["Comandante_Luis_Piedrabuena"]="Comandante Luis Piedrabuena",
28340
- ["Aerodromo_De_Tolhuin"]="Aerodromo De Tolhuin",
28341
- ["Porvenir_Airfield"]="Porvenir Airfield",
28342
- ["Almirante_Schroeders"]="Almirante Schroeders",
28343
- ["Rio_Turbio"]="Rio Turbio",
28761
+ ["Puerto_Williams"]="Puerto Williams",
28762
+ ["Punta_Arenas"]="Punta Arenas",
28344
28763
  ["Rio_Chico"]="Rio Chico",
28345
- ["Franco_Bianco"]="Franco Bianco",
28346
- ["Goose_Green"]="Goose Green",
28347
- ["Hipico_Flying_Club"]="Hipico Flying Club",
28348
- ["CaletaTortel"]="CaletaTortel",
28349
- ["Aeropuerto_de_Gobernador_Gregores"]="Aeropuerto de Gobernador Gregores",
28350
- ["Aerodromo_O_Higgins"]="Aerodromo O'Higgins",
28351
- ["Cullen_Airport"]="Cullen Airport",
28352
- ["Gull_Point"]="Gull Point",
28764
+ ["Rio_Gallegos"]="Rio Gallegos",
28765
+ ["Rio_Grande"]="Rio Grande",
28766
+ ["Rio_Turbio"]="Rio Turbio",
28767
+ ["San_Carlos_FOB"]="San Carlos FOB",
28768
+ ["San_Julian"]="San Julian",
28769
+ ["Tolhuin"]="Tolhuin",
28770
+ ["Ushuaia"]="Ushuaia",
28771
+ ["Ushuaia_Helo_Port"]="Ushuaia Helo Port",
28353
28772
  }
28354
28773
  AIRBASE.Sinai={
28355
- ["Hatzerim"]="Hatzerim",
28774
+ ["Abu_Rudeis"]="Abu Rudeis",
28356
28775
  ["Abu_Suwayr"]="Abu Suwayr",
28357
- ["Sde_Dov"]="Sde Dov",
28358
- ["AzZaqaziq"]="AzZaqaziq",
28359
- ["Hatzor"]="Hatzor",
28360
- ["Kedem"]="Kedem",
28361
- ["Nevatim"]="Nevatim",
28362
- ["Cairo_International_Airport"]="Cairo International Airport",
28363
28776
  ["Al_Ismailiyah"]="Al Ismailiyah",
28777
+ ["Al_Mansurah"]="Al Mansurah",
28364
28778
  ["As_Salihiyah"]="As Salihiyah",
28365
- ["Fayed"]="Fayed",
28779
+ ["AzZaqaziq"]="AzZaqaziq",
28780
+ ["Baluza"]="Baluza",
28781
+ ["Ben_Gurion"]="Ben-Gurion",
28366
28782
  ["Bilbeis_Air_Base"]="Bilbeis Air Base",
28367
- ["Ramon_Airbase"]="Ramon Airbase",
28368
- ["Kibrit_Air_Base"]="Kibrit Air Base",
28783
+ ["Bir_Hasanah"]="Bir Hasanah",
28784
+ ["Cairo_International_Airport"]="Cairo International Airport",
28785
+ ["Cairo_West"]="Cairo West",
28786
+ ["Difarsuwar_Airfield"]="Difarsuwar Airfield",
28369
28787
  ["El_Arish"]="El Arish",
28370
- ["Ovda"]="Ovda",
28788
+ ["El_Gora"]="El Gora",
28789
+ ["Fayed"]="Fayed",
28790
+ ["Hatzerim"]="Hatzerim",
28791
+ ["Hatzor"]="Hatzor",
28792
+ ["Inshas_Airbase"]="Inshas Airbase",
28793
+ ["Kedem"]="Kedem",
28794
+ ["Kibrit_Air_Base"]="Kibrit Air Base",
28371
28795
  ["Melez"]="Melez",
28372
- ["Al_Mansurah"]="Al Mansurah",
28796
+ ["Nevatim"]="Nevatim",
28797
+ ["Ovda"]="Ovda",
28373
28798
  ["Palmahim"]="Palmahim",
28374
- ["Baluza"]="Baluza",
28375
- ["El_Gora"]="El Gora",
28376
- ["Difarsuwar_Airfield"]="Difarsuwar Airfield",
28377
- ["Wadi_al_Jandali"]="Wadi al Jandali",
28799
+ ["Ramon_Airbase"]="Ramon Airbase",
28800
+ ["Sde_Dov"]="Sde Dov",
28378
28801
  ["St_Catherine"]="St Catherine",
28379
28802
  ["Tel_Nof"]="Tel Nof",
28380
- ["Abu_Rudeis"]="Abu Rudeis",
28381
- ["Inshas_Airbase"]="Inshas Airbase",
28382
- ["Ben_Gurion"]="Ben-Gurion",
28383
- ["Bir_Hasanah"]="Bir Hasanah",
28384
- ["Cairo_West"]="Cairo West",
28803
+ ["Wadi_al_Jandali"]="Wadi al Jandali",
28804
+ }
28805
+ AIRBASE.Kola={
28806
+ ["Bas_100"]="Bas 100",
28807
+ ["Bodo"]="Bodo",
28808
+ ["Jokkmokk"]="Jokkmokk",
28809
+ ["Kalixfors"]="Kalixfors",
28810
+ ["Kemi_Tornio"]="Kemi Tornio",
28811
+ ["Kiruna"]="Kiruna",
28812
+ ["Lakselv"]="Lakselv",
28813
+ ["Monchegorsk"]="Monchegorsk",
28814
+ ["Murmansk_International"]="Murmansk International",
28815
+ ["Olenegorsk"]="Olenegorsk",
28816
+ ["Rovaniemi"]="Rovaniemi",
28817
+ ["Severomorsk1"]="Severomorsk1",
28818
+ ["Severomorsk3"]="Severomorsk3",
28385
28819
  }
28386
28820
  AIRBASE.TerminalType={
28387
28821
  Runway=16,
28388
28822
  HelicopterOnly=40,
28389
28823
  Shelter=68,
28390
28824
  OpenMed=72,
28825
+ SmallSizeFighter=100,
28391
28826
  OpenBig=104,
28392
28827
  OpenMedOrBig=176,
28393
28828
  HelicopterUsable=216,
@@ -28946,7 +29381,7 @@ if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.Op
28946
29381
  match=true
28947
29382
  end
28948
29383
  elseif termtype==AIRBASE.TerminalType.FighterAircraft then
28949
- if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.OpenBig or Term_Type==AIRBASE.TerminalType.Shelter then
29384
+ if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.OpenBig or Term_Type==AIRBASE.TerminalType.Shelter or Term_Type==AIRBASE.TerminalType.SmallSizeFighter then
28950
29385
  match=true
28951
29386
  end
28952
29387
  end
@@ -29730,6 +30165,9 @@ self.desc=WeaponObject:getDesc()
29730
30165
  self.category=self.desc.category
29731
30166
  if self:IsMissile()and self.desc.missileCategory then
29732
30167
  self.categoryMissile=self.desc.missileCategory
30168
+ if self.desc.guidance then
30169
+ self.guidance=self.desc.guidance
30170
+ end
29733
30171
  end
29734
30172
  self.typeName=WeaponObject:getTypeName()or"Unknown Type"
29735
30173
  self.name=WeaponObject:getName()
@@ -29944,6 +30382,15 @@ end
29944
30382
  function WEAPON:IsTorpedo()
29945
30383
  return self.category==Weapon.Category.TORPEDO
29946
30384
  end
30385
+ function WEAPON:IsFoxOne()
30386
+ return self.guidance==Weapon.GuidanceType.RADAR_SEMI_ACTIVE
30387
+ end
30388
+ function WEAPON:IsFoxTwo()
30389
+ return self.guidance==Weapon.GuidanceType.IR
30390
+ end
30391
+ function WEAPON:IsFoxThree()
30392
+ return self.guidance==Weapon.GuidanceType.RADAR_ACTIVE
30393
+ end
29947
30394
  function WEAPON:Destroy(Delay)
29948
30395
  if Delay and Delay>0 then
29949
30396
  self:ScheduleOnce(Delay,WEAPON.Destroy,self,0)
@@ -30409,7 +30856,7 @@ end
30409
30856
  function NET.Lua2Json(Lua)
30410
30857
  return net.lua2json(Lua)
30411
30858
  end
30412
- function NET.Lua2Json(Json)
30859
+ function NET.Json2Lua(Json)
30413
30860
  return net.json2lua(Json)
30414
30861
  end
30415
30862
  function NET:DoStringIn(State,DoString)
@@ -31959,7 +32406,7 @@ ClassName="SCORING",
31959
32406
  ClassID=0,
31960
32407
  Players={},
31961
32408
  AutoSave=true,
31962
- version="1.17.1"
32409
+ version="1.18.4"
31963
32410
  }
31964
32411
  local _SCORINGCoalition={
31965
32412
  [1]="Red",
@@ -31972,7 +32419,7 @@ local _SCORINGCategory={
31972
32419
  [Unit.Category.SHIP]="Ship",
31973
32420
  [Unit.Category.STRUCTURE]="Structure",
31974
32421
  }
31975
- function SCORING:New(GameName)
32422
+ function SCORING:New(GameName,SavePath,AutoSave)
31976
32423
  local self=BASE:Inherit(self,BASE:New())
31977
32424
  if GameName then
31978
32425
  self.GameName=GameName
@@ -32005,7 +32452,8 @@ self:_AddPlayerFromUnit(PlayerUnit)
32005
32452
  self:SetScoringMenu(PlayerUnit:GetGroup())
32006
32453
  end
32007
32454
  end)
32008
- self.AutoSave=true
32455
+ self.AutoSavePath=SavePath
32456
+ self.AutoSave=AutoSave or true
32009
32457
  self:OpenCSV(GameName)
32010
32458
  return self
32011
32459
  end
@@ -32049,6 +32497,21 @@ self.ScoringObjects[UnitName]=Score
32049
32497
  end
32050
32498
  return self
32051
32499
  end
32500
+ function SCORING:AddScoreSetGroup(Set,Score)
32501
+ local set=Set:GetSetObjects()
32502
+ for _,_group in pairs(set)do
32503
+ if _group and _group:IsAlive()then
32504
+ self:AddScoreGroup(_group,Score)
32505
+ end
32506
+ end
32507
+ local function AddScore(group)
32508
+ self:AddScoreGroup(group,Score)
32509
+ end
32510
+ function Set:OnAfterAdded(From,Event,To,ObjectName,Object)
32511
+ AddScore(Object)
32512
+ end
32513
+ return self
32514
+ end
32052
32515
  function SCORING:AddZoneScore(ScoreZone,Score)
32053
32516
  local ZoneName=ScoreZone:GetName()
32054
32517
  self.ScoringZones[ZoneName]={}
@@ -32380,7 +32843,7 @@ PlayerHit.TimeStamp=PlayerHit.TimeStamp or 0
32380
32843
  PlayerHit.UNIT=PlayerHit.UNIT or TargetUNIT
32381
32844
  if PlayerHit.UNIT.ThreatType==nil then
32382
32845
  PlayerHit.ThreatLevel,PlayerHit.ThreatType=PlayerHit.UNIT:GetThreatLevel()
32383
- if PlayerHit.ThreatType==nil then
32846
+ if PlayerHit.ThreatType==nil or PlayerHit.ThreatType==""then
32384
32847
  PlayerHit.ThreatLevel=1
32385
32848
  PlayerHit.ThreatType="Unknown"
32386
32849
  end
@@ -32572,16 +33035,15 @@ self:F({ThreatLevel=ThreatPenalty,ThreatLevelTarget=ThreatLevelTarget,ThreatType
32572
33035
  Player.Penalty=Player.Penalty+ThreatPenalty
32573
33036
  TargetDestroy.Penalty=TargetDestroy.Penalty+ThreatPenalty
32574
33037
  TargetDestroy.PenaltyDestroy=TargetDestroy.PenaltyDestroy+1
32575
- self:OnKillPvP(Player,TargetPlayerName,true,TargetThreatLevel,Player.ThreatLevel,ThreatPenalty)
32576
33038
  if Player.HitPlayers[TargetPlayerName]then
32577
- self:OnKillPvP(Player,TargetPlayerName,true)
33039
+ self:OnKillPvP(PlayerName,TargetPlayerName,true)
32578
33040
  MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed friendly player '"..TargetPlayerName.."' "..TargetUnitCategory.." ( "..ThreatTypeTarget.." ) "..
32579
33041
  "Penalty: -"..ThreatPenalty.." = "..Player.Score-Player.Penalty,
32580
33042
  MESSAGE.Type.Information)
32581
33043
  :ToAllIf(self:IfMessagesDestroy()and self:IfMessagesToAll())
32582
33044
  :ToCoalitionIf(InitCoalition,self:IfMessagesDestroy()and self:IfMessagesToCoalition())
32583
33045
  else
32584
- self:OnKillPvE(Player,TargetUnitName,true,TargetThreatLevel,Player.ThreatLevel,ThreatPenalty)
33046
+ self:OnKillPvE(PlayerName,TargetUnitName,true,TargetThreatLevel,Player.ThreatLevel,ThreatPenalty)
32585
33047
  MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed friendly target "..TargetUnitCategory.." ( "..ThreatTypeTarget.." ) "..
32586
33048
  "Penalty: -"..ThreatPenalty.." = "..Player.Score-Player.Penalty,
32587
33049
  MESSAGE.Type.Information)
@@ -32605,14 +33067,14 @@ Player.PlayerKills=Player.PlayerKills+1
32605
33067
  else
32606
33068
  Player.PlayerKills=1
32607
33069
  end
32608
- self:OnKillPvP(Player,TargetPlayerName,false,TargetThreatLevel,Player.ThreatLevel,ThreatScore)
33070
+ self:OnKillPvP(PlayerName,TargetPlayerName,false,TargetThreatLevel,Player.ThreatLevel,ThreatScore)
32609
33071
  MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed enemy player '"..TargetPlayerName.."' "..TargetUnitCategory.." ( "..ThreatTypeTarget.." ) "..
32610
33072
  "Score: +"..ThreatScore.." = "..Player.Score-Player.Penalty,
32611
33073
  MESSAGE.Type.Information)
32612
33074
  :ToAllIf(self:IfMessagesDestroy()and self:IfMessagesToAll())
32613
33075
  :ToCoalitionIf(InitCoalition,self:IfMessagesDestroy()and self:IfMessagesToCoalition())
32614
33076
  else
32615
- self:OnKillPvE(Player,TargetUnitName,false,TargetThreatLevel,Player.ThreatLevel,ThreatScore)
33077
+ self:OnKillPvE(PlayerName,TargetUnitName,false,TargetThreatLevel,Player.ThreatLevel,ThreatScore)
32616
33078
  MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed enemy "..TargetUnitCategory.." ( "..ThreatTypeTarget.." ) "..
32617
33079
  "Score: +"..ThreatScore.." = "..Player.Score-Player.Penalty,
32618
33080
  MESSAGE.Type.Information)
@@ -32954,10 +33416,11 @@ end
32954
33416
  end
32955
33417
  function SCORING:OpenCSV(ScoringCSV)
32956
33418
  self:F(ScoringCSV)
32957
- if lfs and io and os and self.AutoSave then
33419
+ if lfs and io and os and self.AutoSave==true then
32958
33420
  if ScoringCSV then
32959
33421
  self.ScoringCSV=ScoringCSV
32960
- local fdir=lfs.writedir()..[[Logs\]]..self.ScoringCSV.." "..os.date("%Y-%m-%d %H-%M-%S")..".csv"
33422
+ local path=self.AutoSavePath or lfs.writedir()..[[Logs\]]
33423
+ local fdir=path..self.ScoringCSV.." "..os.date("%Y-%m-%d %H-%M-%S")..".csv"
32961
33424
  self.CSVFile,self.err=io.open(fdir,"w+")
32962
33425
  if not self.CSVFile then
32963
33426
  error("Error: Cannot open CSV file in "..lfs.writedir())
@@ -33036,9 +33499,9 @@ function SCORING:SwitchAutoSave(OnOff)
33036
33499
  self.AutoSave=OnOff
33037
33500
  return self
33038
33501
  end
33039
- function SCORING:OnKillPvP(Player,TargetPlayerName,IsTeamKill,TargetThreatLevel,PlayerThreatLevel,Score)
33502
+ function SCORING:OnKillPvP(PlayerName,TargetPlayerName,IsTeamKill,TargetThreatLevel,PlayerThreatLevel,Score)
33040
33503
  end
33041
- function SCORING:OnKillPvE(Player,TargetUnitName,IsTeamKill,TargetThreatLevel,PlayerThreatLevel,Score)
33504
+ function SCORING:OnKillPvE(PlayerName,TargetUnitName,IsTeamKill,TargetThreatLevel,PlayerThreatLevel,Score)
33042
33505
  end
33043
33506
  CLEANUP_AIRBASE={
33044
33507
  ClassName="CLEANUP_AIRBASE",
@@ -33528,7 +33991,6 @@ predpos:MarkToAll(string.format("height=%dm | heading=%d | velocity=%ddeg | Ropt
33528
33991
  targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true)
33529
33992
  end
33530
33993
  local seadset=SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterZones({targetzone}):FilterOnce()
33531
- local tgtcoord=targetzone:GetRandomPointVec2()
33532
33994
  local tgtgrp=seadset:GetRandom()
33533
33995
  local _targetgroup=nil
33534
33996
  local _targetgroupname="none"
@@ -57204,7 +57666,7 @@ local rho=groovedata.Rho
57204
57666
  local lineupError=groovedata.LUE
57205
57667
  local glideslopeError=groovedata.GSE
57206
57668
  local AoA=groovedata.AoA
57207
- if rho<=RXX and playerData.step==AIRBOSS.PatternStep.GROOVE_XX and(math.abs(groovedata.Roll)<=4.0 or playerData.unit:IsInZone(self:_GetZoneLineup()))then
57669
+ if rho<=RXX and playerData.step==AIRBOSS.PatternStep.GROOVE_XX and(math.abs(groovedata.Roll)<=4.0 and playerData.unit:IsInZone(self:_GetZoneLineup()))then
57208
57670
  playerData.TIG0=timer.getTime()
57209
57671
  self:RadioTransmission(self.LSORadio,self.LSOCall.CALLTHEBALL,nil,nil,nil,true)
57210
57672
  playerData.Tlso=timer.getTime()
@@ -64426,6 +64888,8 @@ HasBeenDropped=false,
64426
64888
  PerCrateMass=0,
64427
64889
  Stock=nil,
64428
64890
  Mark=nil,
64891
+ DontShowInMenu=false,
64892
+ Location=nil,
64429
64893
  }
64430
64894
  CTLD_CARGO.Enum={
64431
64895
  VEHICLE="Vehicle",
@@ -64436,7 +64900,7 @@ REPAIR="Repair",
64436
64900
  ENGINEERS="Engineers",
64437
64901
  STATIC="Static",
64438
64902
  }
64439
- function CTLD_CARGO:New(ID,Name,Templates,Sorte,HasBeenMoved,LoadDirectly,CratesNeeded,Positionable,Dropped,PerCrateMass,Stock,Subcategory)
64903
+ function CTLD_CARGO:New(ID,Name,Templates,Sorte,HasBeenMoved,LoadDirectly,CratesNeeded,Positionable,Dropped,PerCrateMass,Stock,Subcategory,DontShowInMenu,Location)
64440
64904
  local self=BASE:Inherit(self,BASE:New())
64441
64905
  self:T({ID,Name,Templates,Sorte,HasBeenMoved,LoadDirectly,CratesNeeded,Positionable,Dropped})
64442
64906
  self.ID=ID or math.random(100000,1000000)
@@ -64452,8 +64916,16 @@ self.PerCrateMass=PerCrateMass or 0
64452
64916
  self.Stock=Stock or nil
64453
64917
  self.Mark=nil
64454
64918
  self.Subcategory=Subcategory or"Other"
64919
+ self.DontShowInMenu=DontShowInMenu or false
64920
+ if type(Location)=="string"then
64921
+ Location=ZONE:New(Location)
64922
+ end
64923
+ self.Location=Location
64455
64924
  return self
64456
64925
  end
64926
+ function CTLD_CARGO:GetLocation()
64927
+ return self.Location
64928
+ end
64457
64929
  function CTLD_CARGO:GetID()
64458
64930
  return self.ID
64459
64931
  end
@@ -64763,10 +65235,13 @@ CTLD.UnitTypeCapabilities={
64763
65235
  ["Mi-24V"]={type="Mi-24V",crates=true,troops=true,cratelimit=2,trooplimit=8,length=18,cargoweightlimit=700},
64764
65236
  ["Hercules"]={type="Hercules",crates=true,troops=true,cratelimit=7,trooplimit=64,length=25,cargoweightlimit=19000},
64765
65237
  ["UH-60L"]={type="UH-60L",crates=true,troops=true,cratelimit=2,trooplimit=20,length=16,cargoweightlimit=3500},
65238
+ ["MH-60R"]={type="MH-60R",crates=true,troops=true,cratelimit=2,trooplimit=20,length=16,cargoweightlimit=3500},
65239
+ ["SH-60B"]={type="SH-60B",crates=true,troops=true,cratelimit=2,trooplimit=20,length=16,cargoweightlimit=3500},
64766
65240
  ["AH-64D_BLK_II"]={type="AH-64D_BLK_II",crates=false,troops=true,cratelimit=0,trooplimit=2,length=17,cargoweightlimit=200},
64767
65241
  ["Bronco-OV-10A"]={type="Bronco-OV-10A",crates=false,troops=true,cratelimit=0,trooplimit=5,length=13,cargoweightlimit=1450},
65242
+ ["OH-6A"]={type="OH-6A",crates=false,troops=true,cratelimit=0,trooplimit=4,length=7,cargoweightlimit=550},
64768
65243
  }
64769
- CTLD.version="1.0.45"
65244
+ CTLD.version="1.0.52"
64770
65245
  function CTLD:New(Coalition,Prefixes,Alias)
64771
65246
  local self=BASE:Inherit(self,FSM:New())
64772
65247
  BASE:T({Coalition,Prefixes,Alias})
@@ -65269,7 +65744,9 @@ local distancekeys={}
65269
65744
  local extractdistance=self.CrateDistance*self.ExtractFactor
65270
65745
  for k,v in pairs(self.DroppedTroops)do
65271
65746
  local distance=self:_GetDistance(v:GetCoordinate(),unitcoord)
65272
- if distance<=extractdistance and distance~=-1 then
65747
+ local TNow=timer.getTime()
65748
+ local vtime=v.ExtractTime or TNow-310
65749
+ if distance<=extractdistance and distance~=-1 and(TNow-vtime>300)then
65273
65750
  nearestGroup=v
65274
65751
  nearestGroupIndex=k
65275
65752
  nearestDistance=distance
@@ -65312,22 +65789,36 @@ loaded.Cargo={}
65312
65789
  end
65313
65790
  if troopsize+numberonboard>trooplimit then
65314
65791
  self:_SendMessage("Sorry, we\'re crammed already!",10,false,Group)
65792
+ nearestGroup.ExtractTime=0
65315
65793
  else
65316
65794
  self.CargoCounter=self.CargoCounter+1
65795
+ nearestGroup.ExtractTime=timer.getTime()
65317
65796
  local loadcargotype=CTLD_CARGO:New(self.CargoCounter,Cargotype.Name,Cargotype.Templates,Cargotype.CargoType,true,true,Cargotype.CratesNeeded,nil,nil,Cargotype.PerCrateMass)
65318
65797
  self:T({cargotype=loadcargotype})
65798
+ local running=math.floor(nearestDistance/4)+10
65319
65799
  loaded.Troopsloaded=loaded.Troopsloaded+troopsize
65320
65800
  table.insert(loaded.Cargo,loadcargotype)
65321
65801
  self.Loaded_Cargo[unitname]=loaded
65322
- self:_SendMessage("Troops boarded!",10,false,Group)
65802
+ self:ScheduleOnce(running,self._SendMessage,self,"Troops boarded!",10,false,Group)
65803
+ self:_SendMessage("Troops boarding!",10,false,Group)
65323
65804
  self:_UpdateUnitCargoMass(Unit)
65324
- self:__TroopsExtracted(1,Group,Unit,nearestGroup)
65805
+ self:__TroopsExtracted(running,Group,Unit,nearestGroup)
65806
+ local coord=Unit:GetCoordinate()or Group:GetCoordinate()
65807
+ local Point
65808
+ if coord then
65809
+ local heading=unit:GetHeading()or 0
65810
+ local Angle=math.floor((heading+160)%360)
65811
+ Point=coord:Translate(8,Angle):GetVec2()
65812
+ if Point then
65813
+ nearestGroup:RouteToVec2(Point,4)
65814
+ end
65815
+ end
65325
65816
  if type(Cargotype.Templates)=="table"and Cargotype.Templates[2]then
65326
65817
  for _,_key in pairs(Cargotype.Templates)do
65327
65818
  table.insert(secondarygroups,_key)
65328
65819
  end
65329
65820
  end
65330
- nearestGroup:Destroy(false)
65821
+ nearestGroup:Destroy(false,running)
65331
65822
  end
65332
65823
  end
65333
65824
  end
@@ -65336,7 +65827,7 @@ for _,_group in pairs(nearestList)do
65336
65827
  if _group and _group:IsAlive()then
65337
65828
  local groupname=string.match(_group:GetName(),"(.+)-(.+)$")
65338
65829
  if _name==groupname then
65339
- _group:Destroy(false)
65830
+ _group:Destroy(false,15)
65340
65831
  end
65341
65832
  end
65342
65833
  end
@@ -65378,6 +65869,16 @@ if not inzone then
65378
65869
  self:_SendMessage("You are not close enough to a logistics zone!",10,false,Group)
65379
65870
  if not self.debug then return self end
65380
65871
  end
65872
+ local location=Cargo:GetLocation()
65873
+ if location then
65874
+ local unitcoord=Unit:GetCoordinate()or Group:GetCoordinate()
65875
+ if unitcoord then
65876
+ if not location:IsCoordinateInZone(unitcoord)then
65877
+ self:_SendMessage("The requested cargo is not available in this zone!",10,false,Group)
65878
+ if not self.debug then return self end
65879
+ end
65880
+ end
65881
+ end
65381
65882
  local capabilities=self:_GetUnitCapabilities(Unit)
65382
65883
  local canloadcratesno=capabilities.cratelimit
65383
65884
  local loaddist=self.CrateDistance or 35
@@ -65928,9 +66429,9 @@ end
65928
66429
  function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
65929
66430
  local Positions={}
65930
66431
  local template=_DATABASE:GetGroupTemplate(Template)
65931
- UTILS.PrintTableToLog(template)
65932
66432
  local numbertroops=#template.units
65933
- local newcenter=Coordinate:Translate(Radius,((Heading+270)%360))
66433
+ local slightshift=math.abs(math.random(0,200)/100)
66434
+ local newcenter=Coordinate:Translate(Radius+slightshift,((Heading+270)%360))
65934
66435
  for i=1,360,math.floor(360/numbertroops)do
65935
66436
  local phead=((Heading+270+i)%360)
65936
66437
  local post=newcenter:Translate(Radius,phead)
@@ -65942,7 +66443,6 @@ heading=phead,
65942
66443
  }
65943
66444
  table.insert(Positions,p1t)
65944
66445
  end
65945
- UTILS.PrintTableToLog(Positions)
65946
66446
  return Positions
65947
66447
  end
65948
66448
  function CTLD:_UnloadTroops(Group,Unit)
@@ -66479,16 +66979,22 @@ end
66479
66979
  for _,_entry in pairs(self.Cargo_Troops)do
66480
66980
  local entry=_entry
66481
66981
  local subcat=entry.Subcategory
66982
+ local noshow=entry.DontShowInMenu
66983
+ if not noshow then
66482
66984
  menucount=menucount+1
66483
66985
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,entry.Name,subcatmenus[subcat],self._LoadTroops,self,_group,_unit,entry)
66484
66986
  end
66987
+ end
66485
66988
  else
66486
66989
  for _,_entry in pairs(self.Cargo_Troops)do
66487
66990
  local entry=_entry
66991
+ local noshow=entry.DontShowInMenu
66992
+ if not noshow then
66488
66993
  menucount=menucount+1
66489
66994
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,entry.Name,troopsmenu,self._LoadTroops,self,_group,_unit,entry)
66490
66995
  end
66491
66996
  end
66997
+ end
66492
66998
  local unloadmenu1=MENU_GROUP_COMMAND:New(_group,"Drop troops",toptroops,self._UnloadTroops,self,_group,_unit):Refresh()
66493
66999
  local extractMenu1=MENU_GROUP_COMMAND:New(_group,"Extract troops",toptroops,self._ExtractTroops,self,_group,_unit):Refresh()
66494
67000
  end
@@ -66505,33 +67011,61 @@ end
66505
67011
  for _,_entry in pairs(self.Cargo_Crates)do
66506
67012
  local entry=_entry
66507
67013
  local subcat=entry.Subcategory
67014
+ local noshow=entry.DontShowInMenu
67015
+ local zone=entry.Location
67016
+ if not noshow then
66508
67017
  menucount=menucount+1
66509
67018
  local menutext=string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
67019
+ if zone then
67020
+ menutext=string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
67021
+ end
66510
67022
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates,self,_group,_unit,entry)
66511
67023
  end
67024
+ end
66512
67025
  for _,_entry in pairs(self.Cargo_Statics)do
66513
67026
  local entry=_entry
66514
67027
  local subcat=entry.Subcategory
67028
+ local noshow=entry.DontShowInMenu
67029
+ local zone=entry.Location
67030
+ if not noshow then
66515
67031
  menucount=menucount+1
66516
67032
  local menutext=string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
67033
+ if zone then
67034
+ menutext=string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
67035
+ end
66517
67036
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates,self,_group,_unit,entry)
66518
67037
  end
67038
+ end
66519
67039
  else
66520
67040
  for _,_entry in pairs(self.Cargo_Crates)do
66521
67041
  local entry=_entry
67042
+ local noshow=entry.DontShowInMenu
67043
+ local zone=entry.Location
67044
+ if not noshow then
66522
67045
  menucount=menucount+1
66523
67046
  local menutext=string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
67047
+ if zone then
67048
+ menutext=string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
67049
+ end
66524
67050
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates,self,_group,_unit,entry)
66525
67051
  end
67052
+ end
66526
67053
  for _,_entry in pairs(self.Cargo_Statics)do
66527
67054
  local entry=_entry
67055
+ local noshow=entry.DontShowInMenu
67056
+ local zone=entry.Location
67057
+ if not noshow then
66528
67058
  menucount=menucount+1
66529
67059
  local menutext=string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
67060
+ if zone then
67061
+ menutext=string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
67062
+ end
66530
67063
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates,self,_group,_unit,entry)
66531
67064
  end
66532
67065
  end
67066
+ end
66533
67067
  listmenu=MENU_GROUP_COMMAND:New(_group,"List crates nearby",topcrates,self._ListCratesNearby,self,_group,_unit)
66534
- removecrates=MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",removecratesmenu,self._RemoveCratesNearby,self,_group,_unit)
67068
+ local removecrates=MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",removecratesmenu,self._RemoveCratesNearby,self,_group,_unit)
66535
67069
  local unloadmenu=MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates,self._UnloadCrates,self,_group,_unit)
66536
67070
  if not self.nobuildmenu then
66537
67071
  local buildmenu=MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates,self._BuildCrates,self,_group,_unit)
@@ -66580,23 +67114,23 @@ local cargo=CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,true,NoTr
66580
67114
  table.insert(self.Cargo_Troops,cargo)
66581
67115
  return self
66582
67116
  end
66583
- function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory)
67117
+ function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
66584
67118
  self:T(self.lid.." AddCratesCargo")
66585
67119
  if not self:_CheckTemplates(Templates)then
66586
67120
  self:E(self.lid.."Crates Cargo for "..Name.." has missing template(s)!")
66587
67121
  return self
66588
67122
  end
66589
67123
  self.CargoCounter=self.CargoCounter+1
66590
- local cargo=CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory)
67124
+ local cargo=CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
66591
67125
  table.insert(self.Cargo_Crates,cargo)
66592
67126
  return self
66593
67127
  end
66594
- function CTLD:AddStaticsCargo(Name,Mass,Stock,SubCategory)
67128
+ function CTLD:AddStaticsCargo(Name,Mass,Stock,SubCategory,DontShowInMenu,Location)
66595
67129
  self:T(self.lid.." AddStaticsCargo")
66596
67130
  self.CargoCounter=self.CargoCounter+1
66597
67131
  local type=CTLD_CARGO.Enum.STATIC
66598
67132
  local template=STATIC:FindByName(Name,true):GetTypeName()
66599
- local cargo=CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,Stock,SubCategory)
67133
+ local cargo=CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,Stock,SubCategory,DontShowInMenu,Location)
66600
67134
  table.insert(self.Cargo_Statics,cargo)
66601
67135
  return self
66602
67136
  end
@@ -66608,14 +67142,14 @@ local template=STATIC:FindByName(Name,true):GetTypeName()
66608
67142
  local cargo=CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,1)
66609
67143
  return cargo
66610
67144
  end
66611
- function CTLD:AddCratesRepair(Name,Template,Type,NoCrates,PerCrateMass,Stock,SubCategory)
67145
+ function CTLD:AddCratesRepair(Name,Template,Type,NoCrates,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
66612
67146
  self:T(self.lid.." AddCratesRepair")
66613
67147
  if not self:_CheckTemplates(Template)then
66614
67148
  self:E(self.lid.."Repair Cargo for "..Name.." has a missing template!")
66615
67149
  return self
66616
67150
  end
66617
67151
  self.CargoCounter=self.CargoCounter+1
66618
- local cargo=CTLD_CARGO:New(self.CargoCounter,Name,Template,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory)
67152
+ local cargo=CTLD_CARGO:New(self.CargoCounter,Name,Template,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
66619
67153
  table.insert(self.Cargo_Crates,cargo)
66620
67154
  return self
66621
67155
  end
@@ -68437,7 +68971,9 @@ CSAR.AircraftType["Bell-47"]=2
68437
68971
  CSAR.AircraftType["UH-60L"]=10
68438
68972
  CSAR.AircraftType["AH-64D_BLK_II"]=2
68439
68973
  CSAR.AircraftType["Bronco-OV-10A"]=2
68440
- CSAR.version="1.0.19"
68974
+ CSAR.AircraftType["MH-60R"]=10
68975
+ CSAR.AircraftType["OH-6A"]=2
68976
+ CSAR.version="1.0.22"
68441
68977
  function CSAR:New(Coalition,Template,Alias)
68442
68978
  local self=BASE:Inherit(self,FSM:New())
68443
68979
  BASE:T({Coalition,Template,Alias})
@@ -68549,7 +69085,7 @@ self.SRSchannel=300
68549
69085
  self.SRSModulation=radio.modulation.AM
68550
69086
  self.SRSport=5002
68551
69087
  self.SRSCulture="en-GB"
68552
- self.SRSVoice=nil
69088
+ self.SRSVoice=MSRS.Voices.Google.Standard.en_GB_Standard_B
68553
69089
  self.SRSGPathToCredentials=nil
68554
69090
  self.SRSVolume=1.0
68555
69091
  self.SRSGender="male"
@@ -68925,7 +69461,7 @@ return self
68925
69461
  end
68926
69462
  if _place:GetCoalition()==self.coalition or _place:GetCoalition()==coalition.side.NEUTRAL then
68927
69463
  self:__Landed(2,_event.IniUnitName,_place)
68928
- self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true)
69464
+ self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true)
68929
69465
  else
68930
69466
  self:T(string.format("Airfield %d, Unit %d",_place:GetCoalition(),_unit:GetCoalition()))
68931
69467
  end
@@ -69148,6 +69684,7 @@ local _found,_pilotable=self:_CheckNameInDownedPilots(_woundedGroupName)
69148
69684
  local _pilotName=_pilotable.desc
69149
69685
  local _reset=true
69150
69686
  if(_distance<500)then
69687
+ self:T(self.lid.."[Pickup Debug] Helo closer than 500m: ".._lookupKeyHeli)
69151
69688
  if self.heliCloseMessage[_lookupKeyHeli]==nil then
69152
69689
  if self.autosmoke==true then
69153
69690
  self:_DisplayMessageToSAR(_heliUnit,string.format("%s: %s. You\'re close now! Land or hover at the smoke.",self:_GetCustomCallSign(_heliName),_pilotName),self.messageTime,false,true)
@@ -69156,11 +69693,15 @@ self:_DisplayMessageToSAR(_heliUnit,string.format("%s: %s. You\'re close now! La
69156
69693
  end
69157
69694
  self.heliCloseMessage[_lookupKeyHeli]=true
69158
69695
  end
69696
+ self:T(self.lid.."[Pickup Debug] Checking landed vs Hover for ".._lookupKeyHeli)
69159
69697
  if not _heliUnit:InAir()then
69698
+ self:T(self.lid.."[Pickup Debug] Helo landed: ".._lookupKeyHeli)
69160
69699
  if self.pilotRuntoExtractPoint==true then
69161
69700
  if(_distance<self.extractDistance)then
69162
69701
  local _time=self.landedStatus[_lookupKeyHeli]
69702
+ self:T(self.lid.."[Pickup Debug] Check pilot running or arrived ".._lookupKeyHeli)
69163
69703
  if _time==nil then
69704
+ self:T(self.lid.."[Pickup Debug] Pilot running not arrived yet ".._lookupKeyHeli)
69164
69705
  self.landedStatus[_lookupKeyHeli]=math.floor((_distance-self.loadDistance)/3.6)
69165
69706
  _time=self.landedStatus[_lookupKeyHeli]
69166
69707
  _woundedGroup:OptionAlarmStateGreen()
@@ -69170,11 +69711,15 @@ else
69170
69711
  _time=self.landedStatus[_lookupKeyHeli]-10
69171
69712
  self.landedStatus[_lookupKeyHeli]=_time
69172
69713
  end
69714
+ self:T(self.lid.."[Pickup Debug] Pilot close enough? ".._lookupKeyHeli)
69173
69715
  if _distance<self.loadDistance+5 or _distance<=13 then
69716
+ self:T(self.lid.."[Pickup Debug] Pilot close enough - YES ".._lookupKeyHeli)
69174
69717
  if self.pilotmustopendoors and(self:_IsLoadingDoorOpen(_heliName)==false)then
69175
69718
  self:_DisplayMessageToSAR(_heliUnit,"Open the door to let me in!",self.messageTime,true,true)
69719
+ self:T(self.lid.."[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
69176
69720
  return false
69177
69721
  else
69722
+ self:T(self.lid.."[Pickup Debug] Pick up Pilot ".._lookupKeyHeli)
69178
69723
  self.landedStatus[_lookupKeyHeli]=nil
69179
69724
  self:_PickupUnit(_heliUnit,_pilotName,_woundedGroup,_woundedGroupName)
69180
69725
  return true
@@ -69182,28 +69727,36 @@ end
69182
69727
  end
69183
69728
  end
69184
69729
  else
69730
+ self:T(self.lid.."[Pickup Debug] Helo landed, pilot NOT set to run to helo ".._lookupKeyHeli)
69185
69731
  if(_distance<self.loadDistance)then
69732
+ self:T(self.lid.."[Pickup Debug] Helo close enough, door check ".._lookupKeyHeli)
69186
69733
  if self.pilotmustopendoors and(self:_IsLoadingDoorOpen(_heliName)==false)then
69734
+ self:T(self.lid.."[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
69187
69735
  self:_DisplayMessageToSAR(_heliUnit,"Open the door to let me in!",self.messageTime,true,true)
69188
69736
  return false
69189
69737
  else
69738
+ self:T(self.lid.."[Pickup Debug] Pick up Pilot ".._lookupKeyHeli)
69190
69739
  self:_PickupUnit(_heliUnit,_pilotName,_woundedGroup,_woundedGroupName)
69191
69740
  return true
69192
69741
  end
69193
69742
  end
69194
69743
  end
69195
69744
  else
69745
+ self:T(self.lid.."[Pickup Debug] Helo hovering".._lookupKeyHeli)
69196
69746
  local _unitsInHelicopter=self:_PilotsOnboard(_heliName)
69197
69747
  local _maxUnits=self.AircraftType[_heliUnit:GetTypeName()]
69198
69748
  if _maxUnits==nil then
69199
69749
  _maxUnits=self.max_units
69200
69750
  end
69751
+ self:T(self.lid.."[Pickup Debug] Check capacity and close enough for winching ".._lookupKeyHeli)
69201
69752
  if _heliUnit:InAir()and _unitsInHelicopter+1<=_maxUnits then
69202
69753
  if _distance<self.rescuehoverdistance then
69754
+ self:T(self.lid.."[Pickup Debug] Helo hovering close enough ".._lookupKeyHeli)
69203
69755
  local leaderheight=_woundedLeader:GetHeight()
69204
69756
  if leaderheight<0 then leaderheight=0 end
69205
69757
  local _height=_heliUnit:GetHeight()-leaderheight
69206
69758
  if _height<=self.rescuehoverheight then
69759
+ self:T(self.lid.."[Pickup Debug] Helo hovering low enough ".._lookupKeyHeli)
69207
69760
  local _time=self.hoverStatus[_lookupKeyHeli]
69208
69761
  if _time==nil then
69209
69762
  self.hoverStatus[_lookupKeyHeli]=10
@@ -69212,21 +69765,28 @@ else
69212
69765
  _time=self.hoverStatus[_lookupKeyHeli]-10
69213
69766
  self.hoverStatus[_lookupKeyHeli]=_time
69214
69767
  end
69768
+ self:T(self.lid.."[Pickup Debug] Check hover timer ".._lookupKeyHeli)
69215
69769
  if _time>0 then
69770
+ self:T(self.lid.."[Pickup Debug] Helo hovering not long enough ".._lookupKeyHeli)
69216
69771
  self:_DisplayMessageToSAR(_heliUnit,"Hovering above ".._pilotName..". \n\nHold hover for ".._time.." seconds to winch them up. \n\nIf the countdown stops you\'re too far away!",self.messageTime,true)
69217
69772
  else
69773
+ self:T(self.lid.."[Pickup Debug] Helo hovering long enough - door check ".._lookupKeyHeli)
69218
69774
  if self.pilotmustopendoors and(self:_IsLoadingDoorOpen(_heliName)==false)then
69219
69775
  self:_DisplayMessageToSAR(_heliUnit,"Open the door to let me in!",self.messageTime,true,true)
69776
+ self:T(self.lid.."[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
69220
69777
  return false
69221
69778
  else
69222
69779
  self.hoverStatus[_lookupKeyHeli]=nil
69223
69780
  self:_PickupUnit(_heliUnit,_pilotName,_woundedGroup,_woundedGroupName)
69781
+ self:T(self.lid.."[Pickup Debug] Pilot picked up ".._lookupKeyHeli)
69224
69782
  return true
69225
69783
  end
69226
69784
  end
69227
69785
  _reset=false
69228
69786
  else
69787
+ self:T(self.lid.."[Pickup Debug] Helo hovering too high ".._lookupKeyHeli)
69229
69788
  self:_DisplayMessageToSAR(_heliUnit,"Too high to winch ".._pilotName.." \nReduce height and hover for 10 seconds!",self.messageTime,true,true)
69789
+ self:T(self.lid.."[Pickup Debug] Hovering too high, try again next loop ".._lookupKeyHeli)
69230
69790
  return false
69231
69791
  end
69232
69792
  end
@@ -69242,7 +69802,7 @@ else
69242
69802
  return false
69243
69803
  end
69244
69804
  end
69245
- function CSAR:_ScheduledSARFlight(heliname,groupname,isairport)
69805
+ function CSAR:_ScheduledSARFlight(heliname,groupname,isairport,noreschedule)
69246
69806
  self:T(self.lid.." _ScheduledSARFlight")
69247
69807
  self:T({heliname,groupname})
69248
69808
  local _heliUnit=self:_GetSARHeli(heliname)
@@ -69256,17 +69816,25 @@ return
69256
69816
  end
69257
69817
  local _dist=self:_GetClosestMASH(_heliUnit)
69258
69818
  if _dist==-1 then
69819
+ self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance can not be determined!")
69259
69820
  return
69260
69821
  end
69822
+ self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance km: "..math.floor(_dist/1000))
69261
69823
  if(_dist<self.FARPRescueDistance or isairport)and _heliUnit:InAir()==false then
69824
+ self:T(self.lid.."[Drop off debug] Distance ok, door check")
69262
69825
  if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname)==false then
69263
69826
  self:_DisplayMessageToSAR(_heliUnit,"Open the door to let me out!",self.messageTime,true,true)
69827
+ self:T(self.lid.."[Drop off debug] Door closed, try again next loop")
69264
69828
  else
69829
+ self:T(self.lid.."[Drop off debug] Rescued!")
69265
69830
  self:_RescuePilots(_heliUnit)
69266
69831
  return
69267
69832
  end
69268
69833
  end
69269
- self:__Returning(-5,heliname,_woundedGroupName,isairport)
69834
+ if not noreschedule then
69835
+ self:__Returning(5,heliname,_woundedGroupName,isairport)
69836
+ self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname,isairport,noreschedule)
69837
+ end
69270
69838
  return self
69271
69839
  end
69272
69840
  function CSAR:_RescuePilots(_heliUnit)
@@ -69308,7 +69876,6 @@ self.msrs:SetCoordinate(coord)
69308
69876
  end
69309
69877
  _text=string.gsub(_text,"km"," kilometer")
69310
69878
  _text=string.gsub(_text,"nm"," nautical miles")
69311
- self:I("Voice = "..self.SRSVoice)
69312
69879
  self.SRSQueue:NewTransmission(_text,duration,self.msrs,tstart,2,subgroups,subtitle,subduration,self.SRSchannel,self.SRSModulation,gender,culture,self.SRSVoice,volume,label,coord)
69313
69880
  end
69314
69881
  return self
@@ -69670,7 +70237,7 @@ self:T(self.lid.." _RefreshRadioBeacons")
69670
70237
  if self:_CountActiveDownedPilots()>0 then
69671
70238
  local PilotTable=self.downedPilots
69672
70239
  for _,_pilot in pairs(PilotTable)do
69673
- self:T({_pilot})
70240
+ self:T({_pilot.name})
69674
70241
  local pilot=_pilot
69675
70242
  local group=pilot.group
69676
70243
  local frequency=pilot.frequency or 0
@@ -69872,7 +70439,6 @@ return self
69872
70439
  end
69873
70440
  function CSAR:onbeforeReturning(From,Event,To,Heliname,Woundedgroupname,IsAirPort)
69874
70441
  self:T({From,Event,To,Heliname,Woundedgroupname})
69875
- self:_ScheduledSARFlight(Heliname,Woundedgroupname,IsAirPort)
69876
70442
  return self
69877
70443
  end
69878
70444
  function CSAR:onbeforeRescued(From,Event,To,HeliUnit,HeliName,PilotsSaved)
@@ -70279,7 +70845,7 @@ local DistanceFromHomeBase=self.HomeAirbase:GetCoordinate():Get2DDistance(self.C
70279
70845
  if not self:Is("Holding")and not self:Is("Returning")then
70280
70846
  local DistanceFromHomeBase=self.HomeAirbase:GetCoordinate():Get2DDistance(self.Controllable:GetCoordinate())
70281
70847
  if DistanceFromHomeBase>self.DisengageRadius then
70282
- self:I(self.Controllable:GetName().." is too far from home base, RTB!")
70848
+ self:T(self.Controllable:GetName().." is too far from home base, RTB!")
70283
70849
  self:Hold(300)
70284
70850
  RTB=false
70285
70851
  end
@@ -70288,10 +70854,10 @@ if not self:Is("Fuel")and not self:Is("Home")and not self:is("Refuelling")then
70288
70854
  local Fuel=self.Controllable:GetFuelMin()
70289
70855
  if Fuel<self.FuelThresholdPercentage then
70290
70856
  if self.TankerName then
70291
- self:I(self.Controllable:GetName().." is out of fuel: "..Fuel.." ... Refuelling at Tanker!")
70857
+ self:T(self.Controllable:GetName().." is out of fuel: "..Fuel.." ... Refuelling at Tanker!")
70292
70858
  self:Refuel()
70293
70859
  else
70294
- self:I(self.Controllable:GetName().." is out of fuel: "..Fuel.." ... RTB!")
70860
+ self:T(self.Controllable:GetName().." is out of fuel: "..Fuel.." ... RTB!")
70295
70861
  local OldAIControllable=self.Controllable
70296
70862
  local OrbitTask=OldAIControllable:TaskOrbitCircle(math.random(self.PatrolFloorAltitude,self.PatrolCeilingAltitude),self.PatrolMinSpeed)
70297
70863
  local TimedOrbitTask=OldAIControllable:TaskControlled(OrbitTask,OldAIControllable:TaskCondition(nil,nil,nil,nil,self.OutOfFuelOrbitTime,nil))
@@ -70308,7 +70874,7 @@ end
70308
70874
  local Damage=self.Controllable:GetLife()
70309
70875
  local InitialLife=self.Controllable:GetLife0()
70310
70876
  if(Damage/InitialLife)<self.PatrolDamageThreshold then
70311
- self:I(self.Controllable:GetName().." is damaged: "..Damage.." ... RTB!")
70877
+ self:T(self.Controllable:GetName().." is damaged: "..Damage.." ... RTB!")
70312
70878
  self:Damaged()
70313
70879
  RTB=true
70314
70880
  self:SetStatusOff()
@@ -70323,7 +70889,7 @@ if self.IdleCount>=10 then
70323
70889
  if Damage~=InitialLife then
70324
70890
  self:Damaged()
70325
70891
  else
70326
- self:I(self.Controllable:GetName().." control lost! ")
70892
+ self:T(self.Controllable:GetName().." control lost! ")
70327
70893
  self:LostControl()
70328
70894
  end
70329
70895
  else
@@ -70369,6 +70935,7 @@ self:ClearTargetDistance()
70369
70935
  AIGroup:OptionProhibitAfterburner(true)
70370
70936
  local EngageRoute={}
70371
70937
  local FromCoord=AIGroup:GetCoordinate()
70938
+ if not FromCoord then return end
70372
70939
  local ToTargetCoord=self.HomeAirbase:GetCoordinate()
70373
70940
  local ToTargetVec3=ToTargetCoord:GetVec3()
70374
70941
  ToTargetVec3.y=ToTargetCoord:GetLandHeight()+3000
@@ -70383,12 +70950,12 @@ local RTBSpeed=math.random(self.RTBMinSpeed,self.RTBMaxSpeed)
70383
70950
  local Distance=FromCoord:Get2DDistance(ToTargetCoord2)
70384
70951
  local ToAirbaseCoord=ToTargetCoord2
70385
70952
  if Distance<5000 then
70386
- self:I("RTB and near the airbase!")
70953
+ self:T("RTB and near the airbase!")
70387
70954
  self:Home()
70388
70955
  return
70389
70956
  end
70390
70957
  if not AIGroup:InAir()==true then
70391
- self:I("Not anymore in the air, considered Home.")
70958
+ self:T("Not anymore in the air, considered Home.")
70392
70959
  self:Home()
70393
70960
  return
70394
70961
  end
@@ -70418,15 +70985,17 @@ end
70418
70985
  end
70419
70986
  function AI_AIR:onafterHome(AIGroup,From,Event,To)
70420
70987
  self:F({AIGroup,From,Event,To})
70421
- self:I("Group "..self.Controllable:GetName().." ... Home! ( "..self:GetState().." )")
70988
+ self:T("Group "..self.Controllable:GetName().." ... Home! ( "..self:GetState().." )")
70422
70989
  if AIGroup and AIGroup:IsAlive()then
70423
70990
  end
70424
70991
  end
70425
70992
  function AI_AIR:onafterHold(AIGroup,From,Event,To,HoldTime)
70426
70993
  self:F({AIGroup,From,Event,To})
70427
- self:I("Group "..self.Controllable:GetName().." ... Holding! ( "..self:GetState().." )")
70994
+ self:T("Group "..self.Controllable:GetName().." ... Holding! ( "..self:GetState().." )")
70428
70995
  if AIGroup and AIGroup:IsAlive()then
70429
- local OrbitTask=AIGroup:TaskOrbitCircle(math.random(self.PatrolFloorAltitude,self.PatrolCeilingAltitude),self.PatrolMinSpeed)
70996
+ local Coordinate=AIGroup:GetCoordinate()
70997
+ if Coordinate==nil then return end
70998
+ local OrbitTask=AIGroup:TaskOrbitCircle(math.random(self.PatrolFloorAltitude,self.PatrolCeilingAltitude),self.PatrolMinSpeed,Coordinate)
70430
70999
  local TimedOrbitTask=AIGroup:TaskControlled(OrbitTask,AIGroup:TaskCondition(nil,nil,nil,nil,HoldTime,nil))
70431
71000
  local RTBTask=AIGroup:TaskFunction("AI_AIR.RTBHold",self)
70432
71001
  local OrbitHoldTask=AIGroup:TaskOrbitCircle(4000,self.PatrolMinSpeed)
@@ -70434,7 +71003,7 @@ AIGroup:SetTask(AIGroup:TaskCombo({TimedOrbitTask,RTBTask,OrbitHoldTask}),1)
70434
71003
  end
70435
71004
  end
70436
71005
  function AI_AIR.Resume(AIGroup,Fsm)
70437
- AIGroup:I({"AI_AIR.Resume:",AIGroup:GetName()})
71006
+ AIGroup:T({"AI_AIR.Resume:",AIGroup:GetName()})
70438
71007
  if AIGroup:IsAlive()then
70439
71008
  Fsm:__RTB(Fsm.TaskDelay)
70440
71009
  end
@@ -70444,7 +71013,7 @@ self:F({AIGroup,From,Event,To})
70444
71013
  if AIGroup and AIGroup:IsAlive()then
70445
71014
  local Tanker=GROUP:FindByName(self.TankerName)
70446
71015
  if Tanker and Tanker:IsAlive()and Tanker:IsAirPlane()then
70447
- self:I("Group "..self.Controllable:GetName().." ... Refuelling! State="..self:GetState()..", Refuelling tanker "..self.TankerName)
71016
+ self:T("Group "..self.Controllable:GetName().." ... Refuelling! State="..self:GetState()..", Refuelling tanker "..self.TankerName)
70448
71017
  local RefuelRoute={}
70449
71018
  local FromRefuelCoord=AIGroup:GetCoordinate()
70450
71019
  local ToRefuelCoord=Tanker:GetCoordinate()
@@ -70657,13 +71226,13 @@ end
70657
71226
  end
70658
71227
  end
70659
71228
  function AI_AIR_ENGAGE.___EngageRoute(AIGroup,Fsm,AttackSetUnit)
70660
- Fsm:I(string.format("AI_AIR_ENGAGE.___EngageRoute: %s",tostring(AIGroup:GetName())))
71229
+ Fsm:T(string.format("AI_AIR_ENGAGE.___EngageRoute: %s",tostring(AIGroup:GetName())))
70661
71230
  if AIGroup and AIGroup:IsAlive()then
70662
71231
  Fsm:__EngageRoute(Fsm.TaskDelay or 0.1,AttackSetUnit)
70663
71232
  end
70664
71233
  end
70665
71234
  function AI_AIR_ENGAGE:onafterEngageRoute(DefenderGroup,From,Event,To,AttackSetUnit)
70666
- self:I({DefenderGroup,From,Event,To,AttackSetUnit})
71235
+ self:T({DefenderGroup,From,Event,To,AttackSetUnit})
70667
71236
  local DefenderGroupName=DefenderGroup:GetName()
70668
71237
  self.AttackSetUnit=AttackSetUnit
70669
71238
  local AttackCount=AttackSetUnit:CountAlive()
@@ -70673,7 +71242,11 @@ local EngageAltitude=math.random(self.EngageFloorAltitude,self.EngageCeilingAlti
70673
71242
  local EngageSpeed=math.random(self.EngageMinSpeed,self.EngageMaxSpeed)
70674
71243
  local DefenderCoord=DefenderGroup:GetPointVec3()
70675
71244
  DefenderCoord:SetY(EngageAltitude)
70676
- local TargetCoord=AttackSetUnit:GetFirst():GetPointVec3()
71245
+ local TargetCoord=AttackSetUnit:GetRandomSurely():GetPointVec3()
71246
+ if TargetCoord==nil then
71247
+ self:Return()
71248
+ return
71249
+ end
70677
71250
  TargetCoord:SetY(EngageAltitude)
70678
71251
  local TargetDistance=DefenderCoord:Get2DDistance(TargetCoord)
70679
71252
  local EngageDistance=(DefenderGroup:IsHelicopter()and 5000)or(DefenderGroup:IsAirPlane()and 10000)
@@ -70697,12 +71270,12 @@ DefenderGroup:Route(EngageRoute,self.TaskDelay or 0.1)
70697
71270
  end
70698
71271
  end
70699
71272
  else
70700
- self:I(DefenderGroupName..": No targets found -> Going RTB")
71273
+ self:T(DefenderGroupName..": No targets found -> Going RTB")
70701
71274
  self:Return()
70702
71275
  end
70703
71276
  end
70704
71277
  function AI_AIR_ENGAGE.___Engage(AIGroup,Fsm,AttackSetUnit)
70705
- Fsm:I(string.format("AI_AIR_ENGAGE.___Engage: %s",tostring(AIGroup:GetName())))
71278
+ Fsm:T(string.format("AI_AIR_ENGAGE.___Engage: %s",tostring(AIGroup:GetName())))
70706
71279
  if AIGroup and AIGroup:IsAlive()then
70707
71280
  local delay=Fsm.TaskDelay or 0.1
70708
71281
  Fsm:__Engage(delay,AttackSetUnit)
@@ -70720,7 +71293,7 @@ local EngageAltitude=math.random(self.EngageFloorAltitude or 500,self.EngageCeil
70720
71293
  local EngageSpeed=math.random(self.EngageMinSpeed,self.EngageMaxSpeed)
70721
71294
  local DefenderCoord=DefenderGroup:GetPointVec3()
70722
71295
  DefenderCoord:SetY(EngageAltitude)
70723
- local TargetCoord=AttackSetUnit:GetFirst():GetPointVec3()
71296
+ local TargetCoord=AttackSetUnit:GetRandomSurely():GetPointVec3()
70724
71297
  if not TargetCoord then
70725
71298
  self:Return()
70726
71299
  return
@@ -70740,12 +71313,12 @@ EngageRoute[#EngageRoute+1]=ToWP
70740
71313
  if TargetDistance<=EngageDistance*9 then
70741
71314
  local AttackUnitTasks=self:CreateAttackUnitTasks(AttackSetUnit,DefenderGroup,EngageAltitude)
70742
71315
  if#AttackUnitTasks==0 then
70743
- self:I(DefenderGroupName..": No valid targets found -> Going RTB")
71316
+ self:T(DefenderGroupName..": No valid targets found -> Going RTB")
70744
71317
  self:Return()
70745
71318
  return
70746
71319
  else
70747
71320
  local text=string.format("%s: Engaging targets at distance %.2f NM",DefenderGroupName,UTILS.MetersToNM(TargetDistance))
70748
- self:I(text)
71321
+ self:T(text)
70749
71322
  DefenderGroup:OptionROEOpenFire()
70750
71323
  DefenderGroup:OptionROTEvadeFire()
70751
71324
  DefenderGroup:OptionKeepWeaponsOnThreat()
@@ -70757,7 +71330,7 @@ EngageRoute[#EngageRoute].task=DefenderGroup:TaskCombo(AttackTasks)
70757
71330
  DefenderGroup:Route(EngageRoute,self.TaskDelay or 0.1)
70758
71331
  end
70759
71332
  else
70760
- self:I(DefenderGroupName..": No targets found -> returning.")
71333
+ self:T(DefenderGroupName..": No targets found -> returning.")
70761
71334
  self:Return()
70762
71335
  return
70763
71336
  end
@@ -71018,12 +71591,12 @@ end
71018
71591
  end
71019
71592
  function AI_A2A_DISPATCHER:OnEventBaseCaptured(EventData)
71020
71593
  local AirbaseName=EventData.PlaceName
71021
- self:I("Captured "..AirbaseName)
71594
+ self:T("Captured "..AirbaseName)
71022
71595
  for SquadronName,Squadron in pairs(self.DefenderSquadrons)do
71023
71596
  if Squadron.AirbaseName==AirbaseName then
71024
71597
  Squadron.ResourceCount=-999
71025
71598
  Squadron.Captured=true
71026
- self:I("Squadron "..SquadronName.." captured.")
71599
+ self:T("Squadron "..SquadronName.." captured.")
71027
71600
  end
71028
71601
  end
71029
71602
  end
@@ -71260,7 +71833,7 @@ Cap.PatrolCeilingAltitude=PatrolCeilingAltitude
71260
71833
  Cap.PatrolAltType=PatrolAltType
71261
71834
  Cap.EngageAltType=EngageAltType
71262
71835
  self:SetSquadronCapInterval(SquadronName,self.DefenderDefault.CapLimit,self.DefenderDefault.CapMinSeconds,self.DefenderDefault.CapMaxSeconds,1)
71263
- self:I({CAP={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,Zone,PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageAltType}})
71836
+ self:T({CAP={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,Zone,PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageAltType}})
71264
71837
  local RecceSet=self.Detection:GetDetectionSet()
71265
71838
  RecceSet:FilterPrefixes(DefenderSquadron.TemplatePrefixes)
71266
71839
  RecceSet:FilterStart()
@@ -71378,7 +71951,7 @@ Intercept.EngageMaxSpeed=EngageMaxSpeed
71378
71951
  Intercept.EngageFloorAltitude=EngageFloorAltitude
71379
71952
  Intercept.EngageCeilingAltitude=EngageCeilingAltitude
71380
71953
  Intercept.EngageAltType=EngageAltType
71381
- self:I({GCI={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
71954
+ self:T({GCI={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
71382
71955
  end
71383
71956
  function AI_A2A_DISPATCHER:SetSquadronGci(SquadronName,EngageMinSpeed,EngageMaxSpeed)
71384
71957
  self.DefenderSquadrons[SquadronName]=self.DefenderSquadrons[SquadronName]or{}
@@ -72255,22 +72828,22 @@ table.insert(AirbaseNames,AirbaseName)
72255
72828
  end
72256
72829
  end
72257
72830
  self.Templates=SET_GROUP:New():FilterPrefixes(TemplatePrefixes):FilterOnce()
72258
- self:I({Airbases=AirbaseNames})
72259
- self:I("Defining Templates for Airbases ...")
72831
+ self:T({Airbases=AirbaseNames})
72832
+ self:T("Defining Templates for Airbases ...")
72260
72833
  for AirbaseID,AirbaseName in pairs(AirbaseNames)do
72261
72834
  local Airbase=_DATABASE:FindAirbase(AirbaseName)
72262
72835
  local AirbaseName=Airbase:GetName()
72263
72836
  local AirbaseCoord=Airbase:GetCoordinate()
72264
72837
  local AirbaseZone=ZONE_RADIUS:New("Airbase",AirbaseCoord:GetVec2(),3000)
72265
72838
  local Templates=nil
72266
- self:I({Airbase=AirbaseName})
72839
+ self:T({Airbase=AirbaseName})
72267
72840
  for TemplateID,Template in pairs(self.Templates:GetSet())do
72268
72841
  local Template=Template
72269
72842
  local TemplateCoord=Template:GetCoordinate()
72270
72843
  if AirbaseZone:IsVec2InZone(TemplateCoord:GetVec2())then
72271
72844
  Templates=Templates or{}
72272
72845
  table.insert(Templates,Template:GetName())
72273
- self:I({Template=Template:GetName()})
72846
+ self:T({Template=Template:GetName()})
72274
72847
  end
72275
72848
  end
72276
72849
  if Templates then
@@ -72280,12 +72853,12 @@ end
72280
72853
  self.CAPTemplates=SET_GROUP:New()
72281
72854
  self.CAPTemplates:FilterPrefixes(CapPrefixes)
72282
72855
  self.CAPTemplates:FilterOnce()
72283
- self:I("Setting up CAP ...")
72856
+ self:T("Setting up CAP ...")
72284
72857
  for CAPID,CAPTemplate in pairs(self.CAPTemplates:GetSet())do
72285
72858
  local CAPZone=ZONE_POLYGON:New(CAPTemplate:GetName(),CAPTemplate)
72286
72859
  local AirbaseDistance=99999999
72287
72860
  local AirbaseClosest=nil
72288
- self:I({CAPZoneGroup=CAPID})
72861
+ self:T({CAPZoneGroup=CAPID})
72289
72862
  for AirbaseID,AirbaseName in pairs(AirbaseNames)do
72290
72863
  local Airbase=_DATABASE:FindAirbase(AirbaseName)
72291
72864
  local AirbaseName=Airbase:GetName()
@@ -72293,7 +72866,7 @@ local AirbaseCoord=Airbase:GetCoordinate()
72293
72866
  local Squadron=self.DefenderSquadrons[AirbaseName]
72294
72867
  if Squadron then
72295
72868
  local Distance=AirbaseCoord:Get2DDistance(CAPZone:GetCoordinate())
72296
- self:I({AirbaseDistance=Distance})
72869
+ self:T({AirbaseDistance=Distance})
72297
72870
  if Distance<AirbaseDistance then
72298
72871
  AirbaseDistance=Distance
72299
72872
  AirbaseClosest=Airbase
@@ -72301,19 +72874,19 @@ end
72301
72874
  end
72302
72875
  end
72303
72876
  if AirbaseClosest then
72304
- self:I({CAPAirbase=AirbaseClosest:GetName()})
72877
+ self:T({CAPAirbase=AirbaseClosest:GetName()})
72305
72878
  self:SetSquadronCap(AirbaseClosest:GetName(),CAPZone,6000,10000,500,800,800,1200,"RADIO")
72306
72879
  self:SetSquadronCapInterval(AirbaseClosest:GetName(),CapLimit,300,600,1)
72307
72880
  end
72308
72881
  end
72309
- self:I("Setting up GCI ...")
72882
+ self:T("Setting up GCI ...")
72310
72883
  for AirbaseID,AirbaseName in pairs(AirbaseNames)do
72311
72884
  local Airbase=_DATABASE:FindAirbase(AirbaseName)
72312
72885
  local AirbaseName=Airbase:GetName()
72313
72886
  local Squadron=self.DefenderSquadrons[AirbaseName]
72314
72887
  self:F({Airbase=AirbaseName})
72315
72888
  if Squadron then
72316
- self:I({GCIAirbase=AirbaseName})
72889
+ self:T({GCIAirbase=AirbaseName})
72317
72890
  self:SetSquadronGci(AirbaseName,800,1200)
72318
72891
  end
72319
72892
  end
@@ -72476,7 +73049,7 @@ DefenderSquadron.Resource={}
72476
73049
  for Resource=1,DefenderSquadron.ResourceCount or 0 do
72477
73050
  self:ResourcePark(DefenderSquadron)
72478
73051
  end
72479
- self:I("Parked resources for squadron "..DefenderSquadron.Name)
73052
+ self:T("Parked resources for squadron "..DefenderSquadron.Name)
72480
73053
  end
72481
73054
  end
72482
73055
  function AI_A2G_DISPATCHER:Lock(DetectedItemIndex)
@@ -72520,12 +73093,12 @@ end
72520
73093
  end
72521
73094
  function AI_A2G_DISPATCHER:OnEventBaseCaptured(EventData)
72522
73095
  local AirbaseName=EventData.PlaceName
72523
- self:I("Captured "..AirbaseName)
73096
+ self:T("Captured "..AirbaseName)
72524
73097
  for SquadronName,Squadron in pairs(self.DefenderSquadrons)do
72525
73098
  if Squadron.AirbaseName==AirbaseName then
72526
73099
  Squadron.ResourceCount=-999
72527
73100
  Squadron.Captured=true
72528
- self:I("Squadron "..SquadronName.." captured.")
73101
+ self:T("Squadron "..SquadronName.." captured.")
72529
73102
  end
72530
73103
  end
72531
73104
  end
@@ -72546,7 +73119,7 @@ if DefenderSize==1 then
72546
73119
  self:RemoveDefenderFromSquadron(Squadron,Defender)
72547
73120
  end
72548
73121
  DefenderUnit:Destroy()
72549
- self:ResourcePark(Squadron,Defender)
73122
+ self:ResourcePark(Squadron)
72550
73123
  return
72551
73124
  end
72552
73125
  if DefenderUnit:GetLife()~=DefenderUnit:GetLife0()then
@@ -72569,7 +73142,7 @@ if DefenderSize==1 then
72569
73142
  self:RemoveDefenderFromSquadron(Squadron,Defender)
72570
73143
  end
72571
73144
  DefenderUnit:Destroy()
72572
- self:ResourcePark(Squadron,Defender)
73145
+ self:ResourcePark(Squadron)
72573
73146
  end
72574
73147
  end
72575
73148
  end
@@ -72592,7 +73165,7 @@ self.DisengageRadius=DisengageRadius or 300000
72592
73165
  return self
72593
73166
  end
72594
73167
  function AI_A2G_DISPATCHER:SetDefenseRadius(DefenseRadius)
72595
- self.DefenseRadius=DefenseRadius or 100000
73168
+ self.DefenseRadius=DefenseRadius or 40000
72596
73169
  self.Detection:SetAcceptRange(self.DefenseRadius)
72597
73170
  return self
72598
73171
  end
@@ -72861,7 +73434,7 @@ Sead.EngageFloorAltitude=EngageFloorAltitude or 500
72861
73434
  Sead.EngageCeilingAltitude=EngageCeilingAltitude or 1000
72862
73435
  Sead.EngageAltType=EngageAltType
72863
73436
  Sead.Defend=true
72864
- self:I({SEAD={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
73437
+ self:T({SEAD={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72865
73438
  return self
72866
73439
  end
72867
73440
  function AI_A2G_DISPATCHER:SetSquadronSead(SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude)
@@ -72888,7 +73461,7 @@ SeadPatrol.PatrolAltType=PatrolAltType
72888
73461
  SeadPatrol.EngageAltType=EngageAltType
72889
73462
  SeadPatrol.Patrol=true
72890
73463
  self:SetSquadronPatrolInterval(SquadronName,self.DefenderDefault.PatrolLimit,self.DefenderDefault.PatrolMinSeconds,self.DefenderDefault.PatrolMaxSeconds,1,"SEAD")
72891
- self:I({SEAD={Zone:GetName(),PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
73464
+ self:T({SEAD={Zone:GetName(),PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72892
73465
  end
72893
73466
  function AI_A2G_DISPATCHER:SetSquadronSeadPatrol(SquadronName,Zone,FloorAltitude,CeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,EngageMinSpeed,EngageMaxSpeed,AltType)
72894
73467
  self:SetSquadronSeadPatrol2(SquadronName,Zone,PatrolMinSpeed,PatrolMaxSpeed,FloorAltitude,CeilingAltitude,AltType,EngageMinSpeed,EngageMaxSpeed,FloorAltitude,CeilingAltitude,AltType)
@@ -72904,7 +73477,7 @@ Cas.EngageFloorAltitude=EngageFloorAltitude or 500
72904
73477
  Cas.EngageCeilingAltitude=EngageCeilingAltitude or 1000
72905
73478
  Cas.EngageAltType=EngageAltType
72906
73479
  Cas.Defend=true
72907
- self:I({CAS={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
73480
+ self:T({CAS={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72908
73481
  return self
72909
73482
  end
72910
73483
  function AI_A2G_DISPATCHER:SetSquadronCas(SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude)
@@ -72931,7 +73504,7 @@ CasPatrol.PatrolAltType=PatrolAltType
72931
73504
  CasPatrol.EngageAltType=EngageAltType
72932
73505
  CasPatrol.Patrol=true
72933
73506
  self:SetSquadronPatrolInterval(SquadronName,self.DefenderDefault.PatrolLimit,self.DefenderDefault.PatrolMinSeconds,self.DefenderDefault.PatrolMaxSeconds,1,"CAS")
72934
- self:I({CAS={Zone:GetName(),PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
73507
+ self:T({CAS={Zone:GetName(),PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72935
73508
  end
72936
73509
  function AI_A2G_DISPATCHER:SetSquadronCasPatrol(SquadronName,Zone,FloorAltitude,CeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,EngageMinSpeed,EngageMaxSpeed,AltType)
72937
73510
  self:SetSquadronCasPatrol2(SquadronName,Zone,PatrolMinSpeed,PatrolMaxSpeed,FloorAltitude,CeilingAltitude,AltType,EngageMinSpeed,EngageMaxSpeed,FloorAltitude,CeilingAltitude,AltType)
@@ -72947,7 +73520,7 @@ Bai.EngageFloorAltitude=EngageFloorAltitude or 500
72947
73520
  Bai.EngageCeilingAltitude=EngageCeilingAltitude or 1000
72948
73521
  Bai.EngageAltType=EngageAltType
72949
73522
  Bai.Defend=true
72950
- self:I({BAI={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
73523
+ self:T({BAI={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72951
73524
  return self
72952
73525
  end
72953
73526
  function AI_A2G_DISPATCHER:SetSquadronBai(SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude)
@@ -72974,7 +73547,7 @@ BaiPatrol.PatrolAltType=PatrolAltType
72974
73547
  BaiPatrol.EngageAltType=EngageAltType
72975
73548
  BaiPatrol.Patrol=true
72976
73549
  self:SetSquadronPatrolInterval(SquadronName,self.DefenderDefault.PatrolLimit,self.DefenderDefault.PatrolMinSeconds,self.DefenderDefault.PatrolMaxSeconds,1,"BAI")
72977
- self:I({BAI={Zone:GetName(),PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
73550
+ self:T({BAI={Zone:GetName(),PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72978
73551
  end
72979
73552
  function AI_A2G_DISPATCHER:SetSquadronBaiPatrol(SquadronName,Zone,FloorAltitude,CeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,EngageMinSpeed,EngageMaxSpeed,AltType)
72980
73553
  self:SetSquadronBaiPatrol2(SquadronName,Zone,PatrolMinSpeed,PatrolMaxSpeed,FloorAltitude,CeilingAltitude,AltType,EngageMinSpeed,EngageMaxSpeed,FloorAltitude,CeilingAltitude,AltType)
@@ -73514,7 +74087,7 @@ local DefenderName=DefenderGroup:GetCallsign()
73514
74087
  local Dispatcher=AI_A2G_Fsm:GetDispatcher()
73515
74088
  local Squadron=Dispatcher:GetSquadronFromDefender(DefenderGroup)
73516
74089
  if Squadron then
73517
- local FirstUnit=AttackSetUnit:GetFirst()
74090
+ local FirstUnit=AttackSetUnit:GetRandomSurely()
73518
74091
  local Coordinate=FirstUnit:GetCoordinate()
73519
74092
  if self.SetSendPlayerMessages then
73520
74093
  Dispatcher:MessageToPlayers(Squadron,DefenderName..", on route to ground target at "..Coordinate:ToStringA2G(DefenderGroup),DefenderGroup)
@@ -74333,7 +74906,7 @@ if self.Controllable and self.Controllable:IsAlive()then
74333
74906
  local RTB=false
74334
74907
  local Fuel=self.Controllable:GetFuelMin()
74335
74908
  if Fuel<self.PatrolFuelThresholdPercentage then
74336
- self:I(self.Controllable:GetName().." is out of fuel:"..Fuel..", RTB!")
74909
+ self:T(self.Controllable:GetName().." is out of fuel:"..Fuel..", RTB!")
74337
74910
  local OldAIControllable=self.Controllable
74338
74911
  local OrbitTask=OldAIControllable:TaskOrbitCircle(math.random(self.PatrolFloorAltitude,self.PatrolCeilingAltitude),self.PatrolMinSpeed)
74339
74912
  local TimedOrbitTask=OldAIControllable:TaskControlled(OrbitTask,OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil))
@@ -74343,7 +74916,7 @@ else
74343
74916
  end
74344
74917
  local Damage=self.Controllable:GetLife()
74345
74918
  if Damage<=self.PatrolDamageThreshold then
74346
- self:I(self.Controllable:GetName().." is damaged:"..Damage..", RTB!")
74919
+ self:T(self.Controllable:GetName().." is damaged:"..Damage..", RTB!")
74347
74920
  RTB=true
74348
74921
  end
74349
74922
  if RTB==true then
@@ -76509,11 +77082,11 @@ function AI_ESCORT_DISPATCHER:OnEventExit(EventData)
76509
77082
  local PlayerGroupName=EventData.IniGroupName
76510
77083
  local PlayerGroup=EventData.IniGroup
76511
77084
  local PlayerUnit=EventData.IniUnit
76512
- self:I({EscortAirbase=self.EscortAirbase})
76513
- self:I({PlayerGroupName=PlayerGroupName})
76514
- self:I({PlayerGroup=PlayerGroup})
76515
- self:I({FirstGroup=self.CarrierSet:GetFirst()})
76516
- self:I({FindGroup=self.CarrierSet:FindGroup(PlayerGroupName)})
77085
+ self:T({EscortAirbase=self.EscortAirbase})
77086
+ self:T({PlayerGroupName=PlayerGroupName})
77087
+ self:T({PlayerGroup=PlayerGroup})
77088
+ self:T({FirstGroup=self.CarrierSet:GetFirst()})
77089
+ self:T({FindGroup=self.CarrierSet:FindGroup(PlayerGroupName)})
76517
77090
  if self.CarrierSet:FindGroup(PlayerGroupName)then
76518
77091
  if self.AI_Escorts[PlayerGroupName]then
76519
77092
  self.AI_Escorts[PlayerGroupName]:Stop()
@@ -76525,16 +77098,16 @@ function AI_ESCORT_DISPATCHER:OnEventBirth(EventData)
76525
77098
  local PlayerGroupName=EventData.IniGroupName
76526
77099
  local PlayerGroup=EventData.IniGroup
76527
77100
  local PlayerUnit=EventData.IniUnit
76528
- self:I({EscortAirbase=self.EscortAirbase})
76529
- self:I({PlayerGroupName=PlayerGroupName})
76530
- self:I({PlayerGroup=PlayerGroup})
76531
- self:I({FirstGroup=self.CarrierSet:GetFirst()})
76532
- self:I({FindGroup=self.CarrierSet:FindGroup(PlayerGroupName)})
77101
+ self:T({EscortAirbase=self.EscortAirbase})
77102
+ self:T({PlayerGroupName=PlayerGroupName})
77103
+ self:T({PlayerGroup=PlayerGroup})
77104
+ self:T({FirstGroup=self.CarrierSet:GetFirst()})
77105
+ self:T({FindGroup=self.CarrierSet:FindGroup(PlayerGroupName)})
76533
77106
  if self.CarrierSet:FindGroup(PlayerGroupName)then
76534
77107
  if not self.AI_Escorts[PlayerGroupName]then
76535
77108
  local LeaderUnit=PlayerUnit
76536
77109
  local EscortGroup=self.EscortSpawn:SpawnAtAirbase(self.EscortAirbase,SPAWN.Takeoff.Hot)
76537
- self:I({EscortGroup=EscortGroup})
77110
+ self:T({EscortGroup=EscortGroup})
76538
77111
  self:ScheduleOnce(1,
76539
77112
  function(EscortGroup)
76540
77113
  local EscortSet=SET_GROUP:New()
@@ -76833,7 +77406,7 @@ if Carrier and Carrier:IsAlive()then
76833
77406
  for _,CarrierUnit in pairs(Carrier:GetUnits())do
76834
77407
  local CarrierUnit=CarrierUnit
76835
77408
  local IsEmpty=CarrierUnit:IsCargoEmpty()
76836
- self:I({IsEmpty=IsEmpty})
77409
+ self:T({IsEmpty=IsEmpty})
76837
77410
  if not IsEmpty then
76838
77411
  AllUnloaded=false
76839
77412
  break
@@ -77921,7 +78494,7 @@ break
77921
78494
  else
77922
78495
  local text=string.format("WARNING: Cargo %s is too heavy to be loaded into transport. Cargo weight %.1f > %.1f load capacity of carrier %s.",
77923
78496
  tostring(Cargo:GetName()),Cargo:GetWeight(),LargestLoadCapacity,tostring(Carrier:GetName()))
77924
- self:I(text)
78497
+ self:T(text)
77925
78498
  end
77926
78499
  end
77927
78500
  end
@@ -78527,6 +79100,954 @@ end
78527
79100
  )
78528
79101
  end
78529
79102
  end
79103
+ SHAPE_BASE={
79104
+ ClassName="SHAPE_BASE",
79105
+ Name="",
79106
+ CenterVec2=nil,
79107
+ Points={},
79108
+ Coords={},
79109
+ MarkIDs={},
79110
+ ColorString="",
79111
+ ColorRGBA={}
79112
+ }
79113
+ function SHAPE_BASE:New()
79114
+ local self=BASE:Inherit(self,BASE:New())
79115
+ return self
79116
+ end
79117
+ function SHAPE_BASE:FindOnMap(shape_name)
79118
+ local self=BASE:Inherit(self,BASE:New())
79119
+ local found=false
79120
+ for _,layer in pairs(env.mission.drawings.layers)do
79121
+ for _,object in pairs(layer["objects"])do
79122
+ if object["name"]==shape_name then
79123
+ self.Name=object["name"]
79124
+ self.CenterVec2={x=object["mapX"],y=object["mapY"]}
79125
+ self.ColorString=object["colorString"]
79126
+ self.ColorRGBA=UTILS.HexToRGBA(self.ColorString)
79127
+ found=true
79128
+ end
79129
+ end
79130
+ end
79131
+ if not found then
79132
+ self:E("Can't find a shape with name "..shape_name)
79133
+ end
79134
+ return self
79135
+ end
79136
+ function SHAPE_BASE:GetAllShapes(filter)
79137
+ filter=filter or""
79138
+ local return_shapes={}
79139
+ for _,layer in pairs(env.mission.drawings.layers)do
79140
+ for _,object in pairs(layer["objects"])do
79141
+ if string.contains(object["name"],filter)then
79142
+ table.add(return_shapes,object)
79143
+ end
79144
+ end
79145
+ end
79146
+ return return_shapes
79147
+ end
79148
+ function SHAPE_BASE:Offset(new_vec2)
79149
+ local offset_vec2=UTILS.Vec2Subtract(new_vec2,self.CenterVec2)
79150
+ self.CenterVec2=new_vec2
79151
+ if self.ClassName=="POLYGON"then
79152
+ for _,point in pairs(self.Points)do
79153
+ point.x=point.x+offset_vec2.x
79154
+ point.y=point.y+offset_vec2.y
79155
+ end
79156
+ end
79157
+ end
79158
+ function SHAPE_BASE:GetName()
79159
+ return self.Name
79160
+ end
79161
+ function SHAPE_BASE:GetColorString()
79162
+ return self.ColorString
79163
+ end
79164
+ function SHAPE_BASE:GetColorRGBA()
79165
+ return self.ColorRGBA
79166
+ end
79167
+ function SHAPE_BASE:GetColorRed()
79168
+ return self.ColorRGBA.R
79169
+ end
79170
+ function SHAPE_BASE:GetColorGreen()
79171
+ return self.ColorRGBA.G
79172
+ end
79173
+ function SHAPE_BASE:GetColorBlue()
79174
+ return self.ColorRGBA.B
79175
+ end
79176
+ function SHAPE_BASE:GetColorAlpha()
79177
+ return self.ColorRGBA.A
79178
+ end
79179
+ function SHAPE_BASE:GetCenterVec2()
79180
+ return self.CenterVec2
79181
+ end
79182
+ function SHAPE_BASE:GetCenterCoordinate()
79183
+ return COORDINATE:NewFromVec2(self.CenterVec2)
79184
+ end
79185
+ function SHAPE_BASE:GetCoordinate()
79186
+ return self:GetCenterCoordinate()
79187
+ end
79188
+ function SHAPE_BASE:ContainsPoint(_)
79189
+ self:E("This needs to be set in the derived class")
79190
+ end
79191
+ function SHAPE_BASE:ContainsUnit(unit_name)
79192
+ local unit=UNIT:FindByName(unit_name)
79193
+ if unit==nil or not unit:IsAlive()then
79194
+ return false
79195
+ end
79196
+ if self:ContainsPoint(unit:GetVec2())then
79197
+ return true
79198
+ end
79199
+ return false
79200
+ end
79201
+ function SHAPE_BASE:ContainsAnyOfGroup(group_name)
79202
+ local group=GROUP:FindByName(group_name)
79203
+ if group==nil or not group:IsAlive()then
79204
+ return false
79205
+ end
79206
+ for _,unit in pairs(group:GetUnits())do
79207
+ if self:ContainsPoint(unit:GetVec2())then
79208
+ return true
79209
+ end
79210
+ end
79211
+ return false
79212
+ end
79213
+ function SHAPE_BASE:ContainsAllOfGroup(group_name)
79214
+ local group=GROUP:FindByName(group_name)
79215
+ if group==nil or not group:IsAlive()then
79216
+ return false
79217
+ end
79218
+ for _,unit in pairs(group:GetUnits())do
79219
+ if not self:ContainsPoint(unit:GetVec2())then
79220
+ return false
79221
+ end
79222
+ end
79223
+ return true
79224
+ end
79225
+ CIRCLE={
79226
+ ClassName="CIRCLE",
79227
+ Radius=nil,
79228
+ }
79229
+ function CIRCLE:FindOnMap(shape_name)
79230
+ local self=BASE:Inherit(self,SHAPE_BASE:FindOnMap(shape_name))
79231
+ for _,layer in pairs(env.mission.drawings.layers)do
79232
+ for _,object in pairs(layer["objects"])do
79233
+ if string.find(object["name"],shape_name,1,true)then
79234
+ if object["polygonMode"]=="circle"then
79235
+ self.Radius=object["radius"]
79236
+ end
79237
+ end
79238
+ end
79239
+ end
79240
+ return self
79241
+ end
79242
+ function CIRCLE:Find(shape_name)
79243
+ return _DATABASE:FindShape(shape_name)
79244
+ end
79245
+ function CIRCLE:New(vec2,radius)
79246
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
79247
+ self.CenterVec2=vec2
79248
+ self.Radius=radius
79249
+ return self
79250
+ end
79251
+ function CIRCLE:GetRadius()
79252
+ return self.Radius
79253
+ end
79254
+ function CIRCLE:ContainsPoint(point)
79255
+ if((point.x-self.CenterVec2.x)^2+(point.y-self.CenterVec2.y)^2)^0.5<=self.Radius then
79256
+ return true
79257
+ end
79258
+ return false
79259
+ end
79260
+ function CIRCLE:PointInSector(point,sector_start,sector_end,center,radius)
79261
+ center=center or self.CenterVec2
79262
+ radius=radius or self.Radius
79263
+ local function are_clockwise(v1,v2)
79264
+ return-v1.x*v2.y+v1.y*v2.x>0
79265
+ end
79266
+ local function is_in_radius(rp)
79267
+ return rp.x*rp.x+rp.y*rp.y<=radius^2
79268
+ end
79269
+ local rel_pt={
79270
+ x=point.x-center.x,
79271
+ y=point.y-center.y
79272
+ }
79273
+ local rel_sector_start={
79274
+ x=sector_start.x-center.x,
79275
+ y=sector_start.y-center.y,
79276
+ }
79277
+ local rel_sector_end={
79278
+ x=sector_end.x-center.x,
79279
+ y=sector_end.y-center.y,
79280
+ }
79281
+ return not are_clockwise(rel_sector_start,rel_pt)and
79282
+ are_clockwise(rel_sector_end,rel_pt)and
79283
+ is_in_radius(rel_pt,radius)
79284
+ end
79285
+ function CIRCLE:UnitInSector(unit_name,sector_start,sector_end,center,radius)
79286
+ center=center or self.CenterVec2
79287
+ radius=radius or self.Radius
79288
+ if self:PointInSector(UNIT:FindByName(unit_name):GetVec2(),sector_start,sector_end,center,radius)then
79289
+ return true
79290
+ end
79291
+ return false
79292
+ end
79293
+ function CIRCLE:AnyOfGroupInSector(group_name,sector_start,sector_end,center,radius)
79294
+ center=center or self.CenterVec2
79295
+ radius=radius or self.Radius
79296
+ for _,unit in pairs(GROUP:FindByName(group_name):GetUnits())do
79297
+ if self:PointInSector(unit:GetVec2(),sector_start,sector_end,center,radius)then
79298
+ return true
79299
+ end
79300
+ end
79301
+ return false
79302
+ end
79303
+ function CIRCLE:AllOfGroupInSector(group_name,sector_start,sector_end,center,radius)
79304
+ center=center or self.CenterVec2
79305
+ radius=radius or self.Radius
79306
+ for _,unit in pairs(GROUP:FindByName(group_name):GetUnits())do
79307
+ if not self:PointInSector(unit:GetVec2(),sector_start,sector_end,center,radius)then
79308
+ return false
79309
+ end
79310
+ end
79311
+ return true
79312
+ end
79313
+ function CIRCLE:UnitInRadius(unit_name,center,radius)
79314
+ center=center or self.CenterVec2
79315
+ radius=radius or self.Radius
79316
+ if UTILS.IsInRadius(center,UNIT:FindByName(unit_name):GetVec2(),radius)then
79317
+ return true
79318
+ end
79319
+ return false
79320
+ end
79321
+ function CIRCLE:AnyOfGroupInRadius(group_name,center,radius)
79322
+ center=center or self.CenterVec2
79323
+ radius=radius or self.Radius
79324
+ for _,unit in pairs(GROUP:FindByName(group_name):GetUnits())do
79325
+ if UTILS.IsInRadius(center,unit:GetVec2(),radius)then
79326
+ return true
79327
+ end
79328
+ end
79329
+ return false
79330
+ end
79331
+ function CIRCLE:AllOfGroupInRadius(group_name,center,radius)
79332
+ center=center or self.CenterVec2
79333
+ radius=radius or self.Radius
79334
+ for _,unit in pairs(GROUP:FindByName(group_name):GetUnits())do
79335
+ if not UTILS.IsInRadius(center,unit:GetVec2(),radius)then
79336
+ return false
79337
+ end
79338
+ end
79339
+ return true
79340
+ end
79341
+ function CIRCLE:GetRandomVec2()
79342
+ local angle=math.random()*2*math.pi
79343
+ local rx=math.random(0,self.Radius)*math.cos(angle)+self.CenterVec2.x
79344
+ local ry=math.random(0,self.Radius)*math.sin(angle)+self.CenterVec2.y
79345
+ return{x=rx,y=ry}
79346
+ end
79347
+ function CIRCLE:GetRandomVec2OnBorder()
79348
+ local angle=math.random()*2*math.pi
79349
+ local rx=self.Radius*math.cos(angle)+self.CenterVec2.x
79350
+ local ry=self.Radius*math.sin(angle)+self.CenterVec2.y
79351
+ return{x=rx,y=ry}
79352
+ end
79353
+ function CIRCLE:GetBoundingBox()
79354
+ local min_x=self.CenterVec2.x-self.Radius
79355
+ local min_y=self.CenterVec2.y-self.Radius
79356
+ local max_x=self.CenterVec2.x+self.Radius
79357
+ local max_y=self.CenterVec2.y+self.Radius
79358
+ return{
79359
+ {x=min_x,y=min_x},{x=max_x,y=min_y},{x=max_x,y=max_y},{x=min_x,y=max_y}
79360
+ }
79361
+ end
79362
+ CUBE={
79363
+ ClassName="CUBE",
79364
+ Points={},
79365
+ Coords={}
79366
+ }
79367
+ function CUBE:New(p1,p2,p3,p4,p5,p6,p7,p8)
79368
+ local self=BASE:Inherit(self,SHAPE_BASE)
79369
+ self.Points={p1,p2,p3,p4,p5,p6,p7,p8}
79370
+ for _,point in spairs(self.Points)do
79371
+ table.insert(self.Coords,COORDINATE:NewFromVec3(point))
79372
+ end
79373
+ return self
79374
+ end
79375
+ function CUBE:GetCenter()
79376
+ local center={x=0,y=0,z=0}
79377
+ for _,point in pairs(self.Points)do
79378
+ center.x=center.x+point.x
79379
+ center.y=center.y+point.y
79380
+ center.z=center.z+point.z
79381
+ end
79382
+ center.x=center.x/8
79383
+ center.y=center.y/8
79384
+ center.z=center.z/8
79385
+ return center
79386
+ end
79387
+ function CUBE:ContainsPoint(point,cube_points)
79388
+ cube_points=cube_points or self.Points
79389
+ local min_x,min_y,min_z=math.huge,math.huge,math.huge
79390
+ local max_x,max_y,max_z=-math.huge,-math.huge,-math.huge
79391
+ for _,p in ipairs(cube_points)do
79392
+ if p.x<min_x then min_x=p.x end
79393
+ if p.y<min_y then min_y=p.y end
79394
+ if p.z<min_z then min_z=p.z end
79395
+ if p.x>max_x then max_x=p.x end
79396
+ if p.y>max_y then max_y=p.y end
79397
+ if p.z>max_z then max_z=p.z end
79398
+ end
79399
+ return point.x>=min_x and point.x<=max_x and point.y>=min_y and point.y<=max_y and point.z>=min_z and point.z<=max_z
79400
+ end
79401
+ LINE={
79402
+ ClassName="LINE",
79403
+ Points={},
79404
+ Coords={},
79405
+ }
79406
+ function LINE:FindOnMap(line_name)
79407
+ local self=BASE:Inherit(self,SHAPE_BASE:FindOnMap(line_name))
79408
+ for _,layer in pairs(env.mission.drawings.layers)do
79409
+ for _,object in pairs(layer["objects"])do
79410
+ if object["name"]==line_name then
79411
+ if object["primitiveType"]=="Line"then
79412
+ for _,point in UTILS.spairs(object["points"])do
79413
+ local p={x=object["mapX"]+point["x"],
79414
+ y=object["mapY"]+point["y"]}
79415
+ local coord=COORDINATE:NewFromVec2(p)
79416
+ table.insert(self.Points,p)
79417
+ table.insert(self.Coords,coord)
79418
+ end
79419
+ end
79420
+ end
79421
+ end
79422
+ end
79423
+ self:I(#self.Points)
79424
+ if#self.Points==0 then
79425
+ return nil
79426
+ end
79427
+ self.MarkIDs={}
79428
+ return self
79429
+ end
79430
+ function LINE:Find(shape_name)
79431
+ return _DATABASE:FindShape(shape_name)
79432
+ end
79433
+ function LINE:New(...)
79434
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
79435
+ self.Points={...}
79436
+ self:I(self.Points)
79437
+ for _,point in UTILS.spairs(self.Points)do
79438
+ table.insert(self.Coords,COORDINATE:NewFromVec2(point))
79439
+ end
79440
+ return self
79441
+ end
79442
+ function LINE:NewFromCircle(center_point,radius,angle_degrees)
79443
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
79444
+ self.CenterVec2=center_point
79445
+ local angleRadians=math.rad(angle_degrees)
79446
+ local point1={
79447
+ x=center_point.x+radius*math.cos(angleRadians),
79448
+ y=center_point.y+radius*math.sin(angleRadians)
79449
+ }
79450
+ local point2={
79451
+ x=center_point.x+radius*math.cos(angleRadians+math.pi),
79452
+ y=center_point.y+radius*math.sin(angleRadians+math.pi)
79453
+ }
79454
+ for _,point in pairs{point1,point2}do
79455
+ table.insert(self.Points,point)
79456
+ table.insert(self.Coords,COORDINATE:NewFromVec2(point))
79457
+ end
79458
+ return self
79459
+ end
79460
+ function LINE:Coordinates()
79461
+ return self.Coords
79462
+ end
79463
+ function LINE:GetStartCoordinate()
79464
+ return self.Coords[1]
79465
+ end
79466
+ function LINE:GetEndCoordinate()
79467
+ return self.Coords[#self.Coords]
79468
+ end
79469
+ function LINE:GetStartPoint()
79470
+ return self.Points[1]
79471
+ end
79472
+ function LINE:GetEndPoint()
79473
+ return self.Points[#self.Points]
79474
+ end
79475
+ function LINE:GetLength()
79476
+ local total_length=0
79477
+ for i=1,#self.Points-1 do
79478
+ local x1,y1=self.Points[i]["x"],self.Points[i]["y"]
79479
+ local x2,y2=self.Points[i+1]["x"],self.Points[i+1]["y"]
79480
+ local segment_length=math.sqrt((x2-x1)^2+(y2-y1)^2)
79481
+ total_length=total_length+segment_length
79482
+ end
79483
+ return total_length
79484
+ end
79485
+ function LINE:GetRandomPoint(points)
79486
+ points=points or self.Points
79487
+ local rand=math.random()
79488
+ local random_x=points[1].x+rand*(points[2].x-points[1].x)
79489
+ local random_y=points[1].y+rand*(points[2].y-points[1].y)
79490
+ return{x=random_x,y=random_y}
79491
+ end
79492
+ function LINE:GetHeading(points)
79493
+ points=points or self.Points
79494
+ local angle=math.atan2(points[2].y-points[1].y,points[2].x-points[1].x)
79495
+ angle=math.deg(angle)
79496
+ if angle<0 then
79497
+ angle=angle+360
79498
+ end
79499
+ return angle
79500
+ end
79501
+ function LINE:GetIndividualParts()
79502
+ local parts={}
79503
+ if#self.Points==2 then
79504
+ parts={self}
79505
+ end
79506
+ for i=1,#self.Points-1 do
79507
+ local p1=self.Points[i]
79508
+ local p2=self.Points[i%#self.Points+1]
79509
+ table.add(parts,LINE:New(p1,p2))
79510
+ end
79511
+ return parts
79512
+ end
79513
+ function LINE:GetPointsInbetween(amount,start_point,end_point)
79514
+ start_point=start_point or self:GetStartPoint()
79515
+ end_point=end_point or self:GetEndPoint()
79516
+ if amount==0 then return{start_point,end_point}end
79517
+ amount=amount+1
79518
+ local points={}
79519
+ local difference={x=end_point.x-start_point.x,y=end_point.y-start_point.y}
79520
+ local divided={x=difference.x/amount,y=difference.y/amount}
79521
+ for j=0,amount do
79522
+ local part_pos={x=divided.x*j,y=divided.y*j}
79523
+ local point={x=start_point.x+part_pos.x,y=start_point.y+part_pos.y}
79524
+ table.insert(points,point)
79525
+ end
79526
+ return points
79527
+ end
79528
+ function LINE:GetCoordinatesInBetween(amount,start_point,end_point)
79529
+ local coords={}
79530
+ for _,pt in pairs(self:GetPointsInbetween(amount,start_point,end_point))do
79531
+ table.add(coords,COORDINATE:NewFromVec2(pt))
79532
+ end
79533
+ return coords
79534
+ end
79535
+ function LINE:GetRandomPoint(start_point,end_point)
79536
+ start_point=start_point or self:GetStartPoint()
79537
+ end_point=end_point or self:GetEndPoint()
79538
+ local fraction=math.random()
79539
+ local difference={x=end_point.x-start_point.x,y=end_point.y-start_point.y}
79540
+ local part_pos={x=difference.x*fraction,y=difference.y*fraction}
79541
+ local random_point={x=start_point.x+part_pos.x,y=start_point.y+part_pos.y}
79542
+ return random_point
79543
+ end
79544
+ function LINE:GetRandomCoordinate(start_point,end_point)
79545
+ start_point=start_point or self:GetStartPoint()
79546
+ end_point=end_point or self:GetEndPoint()
79547
+ return COORDINATE:NewFromVec2(self:GetRandomPoint(start_point,end_point))
79548
+ end
79549
+ function LINE:GetPointsBetweenAsSineWave(amount,start_point,end_point,frequency,phase,amplitude)
79550
+ amount=amount or 20
79551
+ start_point=start_point or self:GetStartPoint()
79552
+ end_point=end_point or self:GetEndPoint()
79553
+ frequency=frequency or 1
79554
+ phase=phase or 0
79555
+ amplitude=amplitude or 100
79556
+ local points={}
79557
+ local function sine_wave(x)
79558
+ return amplitude*math.sin(2*math.pi*frequency*(x-start_point.x)+phase)
79559
+ end
79560
+ local x=start_point.x
79561
+ local step=(end_point.x-start_point.x)/20
79562
+ for _=1,amount do
79563
+ local y=sine_wave(x)
79564
+ x=x+step
79565
+ table.add(points,{x=x,y=y})
79566
+ end
79567
+ return points
79568
+ end
79569
+ function LINE:GetBoundingBox()
79570
+ local min_x,min_y,max_x,max_y=self.Points[1].x,self.Points[1].y,self.Points[2].x,self.Points[2].y
79571
+ for i=2,#self.Points do
79572
+ local x,y=self.Points[i].x,self.Points[i].y
79573
+ if x<min_x then
79574
+ min_x=x
79575
+ end
79576
+ if y<min_y then
79577
+ min_y=y
79578
+ end
79579
+ if x>max_x then
79580
+ max_x=x
79581
+ end
79582
+ if y>max_y then
79583
+ max_y=y
79584
+ end
79585
+ end
79586
+ return{
79587
+ {x=min_x,y=min_x},{x=max_x,y=min_y},{x=max_x,y=max_y},{x=min_x,y=max_y}
79588
+ }
79589
+ end
79590
+ function LINE:Draw()
79591
+ for i=1,#self.Coords-1 do
79592
+ local c1=self.Coords[i]
79593
+ local c2=self.Coords[i%#self.Coords+1]
79594
+ table.add(self.MarkIDs,c1:LineToAll(c2))
79595
+ end
79596
+ end
79597
+ function LINE:RemoveDraw()
79598
+ for _,mark_id in pairs(self.MarkIDs)do
79599
+ UTILS.RemoveMark(mark_id)
79600
+ end
79601
+ end
79602
+ OVAL={
79603
+ ClassName="OVAL",
79604
+ MajorAxis=nil,
79605
+ MinorAxis=nil,
79606
+ Angle=0,
79607
+ DrawPoly=nil
79608
+ }
79609
+ function OVAL:FindOnMap(shape_name)
79610
+ local self=BASE:Inherit(self,SHAPE_BASE:FindOnMap(shape_name))
79611
+ for _,layer in pairs(env.mission.drawings.layers)do
79612
+ for _,object in pairs(layer["objects"])do
79613
+ if string.find(object["name"],shape_name,1,true)then
79614
+ if object["polygonMode"]=="oval"then
79615
+ self.CenterVec2={x=object["mapX"],y=object["mapY"]}
79616
+ self.MajorAxis=object["r1"]
79617
+ self.MinorAxis=object["r2"]
79618
+ self.Angle=object["angle"]
79619
+ end
79620
+ end
79621
+ end
79622
+ end
79623
+ return self
79624
+ end
79625
+ function OVAL:Find(shape_name)
79626
+ return _DATABASE:FindShape(shape_name)
79627
+ end
79628
+ function OVAL:New(vec2,major_axis,minor_axis,angle)
79629
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
79630
+ self.CenterVec2=vec2
79631
+ self.MajorAxis=major_axis
79632
+ self.MinorAxis=minor_axis
79633
+ self.Angle=angle or 0
79634
+ return self
79635
+ end
79636
+ function OVAL:GetMajorAxis()
79637
+ return self.MajorAxis
79638
+ end
79639
+ function OVAL:GetMinorAxis()
79640
+ return self.MinorAxis
79641
+ end
79642
+ function OVAL:GetAngle()
79643
+ return self.Angle
79644
+ end
79645
+ function OVAL:SetMajorAxis(value)
79646
+ self.MajorAxis=value
79647
+ end
79648
+ function OVAL:SetMinorAxis(value)
79649
+ self.MinorAxis=value
79650
+ end
79651
+ function OVAL:SetAngle(value)
79652
+ self.Angle=value
79653
+ end
79654
+ function OVAL:ContainsPoint(point)
79655
+ local cos,sin=math.cos,math.sin
79656
+ local dx=point.x-self.CenterVec2.x
79657
+ local dy=point.y-self.CenterVec2.y
79658
+ local rx=dx*cos(self.Angle)+dy*sin(self.Angle)
79659
+ local ry=-dx*sin(self.Angle)+dy*cos(self.Angle)
79660
+ return rx*rx/(self.MajorAxis*self.MajorAxis)+ry*ry/(self.MinorAxis*self.MinorAxis)<=1
79661
+ end
79662
+ function OVAL:GetRandomVec2()
79663
+ local theta=math.rad(self.Angle)
79664
+ local random_point=math.sqrt(math.random())
79665
+ local phi=math.random()*2*math.pi
79666
+ local x_c=random_point*math.cos(phi)
79667
+ local y_c=random_point*math.sin(phi)
79668
+ local x_e=x_c*self.MajorAxis
79669
+ local y_e=y_c*self.MinorAxis
79670
+ local rx=(x_e*math.cos(theta)-y_e*math.sin(theta))+self.CenterVec2.x
79671
+ local ry=(x_e*math.sin(theta)+y_e*math.cos(theta))+self.CenterVec2.y
79672
+ return{x=rx,y=ry}
79673
+ end
79674
+ function OVAL:GetBoundingBox()
79675
+ local min_x=self.CenterVec2.x-self.MajorAxis
79676
+ local min_y=self.CenterVec2.y-self.MinorAxis
79677
+ local max_x=self.CenterVec2.x+self.MajorAxis
79678
+ local max_y=self.CenterVec2.y+self.MinorAxis
79679
+ return{
79680
+ {x=min_x,y=min_x},{x=max_x,y=min_y},{x=max_x,y=max_y},{x=min_x,y=max_y}
79681
+ }
79682
+ end
79683
+ function OVAL:Draw()
79684
+ self.DrawPoly=POLYGON:NewFromPoints(self:PointsOnEdge(20))
79685
+ self.DrawPoly:Draw(true)
79686
+ end
79687
+ function OVAL:RemoveDraw()
79688
+ self.DrawPoly:RemoveDraw()
79689
+ end
79690
+ function OVAL:PointsOnEdge(num_points)
79691
+ num_points=num_points or 20
79692
+ local points={}
79693
+ local dtheta=2*math.pi/num_points
79694
+ for i=0,num_points-1 do
79695
+ local theta=i*dtheta
79696
+ local x=self.CenterVec2.x+self.MajorAxis*math.cos(theta)*math.cos(self.Angle)-self.MinorAxis*math.sin(theta)*math.sin(self.Angle)
79697
+ local y=self.CenterVec2.y+self.MajorAxis*math.cos(theta)*math.sin(self.Angle)+self.MinorAxis*math.sin(theta)*math.cos(self.Angle)
79698
+ table.insert(points,{x=x,y=y})
79699
+ end
79700
+ return points
79701
+ end
79702
+ POLYGON={
79703
+ ClassName="POLYGON",
79704
+ Points={},
79705
+ Coords={},
79706
+ Triangles={},
79707
+ SurfaceArea=0,
79708
+ TriangleMarkIDs={},
79709
+ OutlineMarkIDs={},
79710
+ Angle=nil,
79711
+ Heading=nil
79712
+ }
79713
+ function POLYGON:FindOnMap(shape_name)
79714
+ local self=BASE:Inherit(self,SHAPE_BASE:FindOnMap(shape_name))
79715
+ for _,layer in pairs(env.mission.drawings.layers)do
79716
+ for _,object in pairs(layer["objects"])do
79717
+ if object["name"]==shape_name then
79718
+ if(object["primitiveType"]=="Line"and object["closed"]==true)or(object["polygonMode"]=="free")then
79719
+ for _,point in UTILS.spairs(object["points"])do
79720
+ local p={x=object["mapX"]+point["x"],
79721
+ y=object["mapY"]+point["y"]}
79722
+ local coord=COORDINATE:NewFromVec2(p)
79723
+ self.Points[#self.Points+1]=p
79724
+ self.Coords[#self.Coords+1]=coord
79725
+ end
79726
+ elseif object["polygonMode"]=="rect"then
79727
+ local angle=object["angle"]
79728
+ local half_width=object["width"]/2
79729
+ local half_height=object["height"]/2
79730
+ local p1=UTILS.RotatePointAroundPivot({x=self.CenterVec2.x-half_height,y=self.CenterVec2.y+half_width},self.CenterVec2,angle)
79731
+ local p2=UTILS.RotatePointAroundPivot({x=self.CenterVec2.x+half_height,y=self.CenterVec2.y+half_width},self.CenterVec2,angle)
79732
+ local p3=UTILS.RotatePointAroundPivot({x=self.CenterVec2.x+half_height,y=self.CenterVec2.y-half_width},self.CenterVec2,angle)
79733
+ local p4=UTILS.RotatePointAroundPivot({x=self.CenterVec2.x-half_height,y=self.CenterVec2.y-half_width},self.CenterVec2,angle)
79734
+ self.Points={p1,p2,p3,p4}
79735
+ for _,point in pairs(self.Points)do
79736
+ self.Coords[#self.Coords+1]=COORDINATE:NewFromVec2(point)
79737
+ end
79738
+ elseif object["polygonMode"]=="arrow"then
79739
+ for _,point in UTILS.spairs(object["points"])do
79740
+ local p={x=object["mapX"]+point["x"],
79741
+ y=object["mapY"]+point["y"]}
79742
+ local coord=COORDINATE:NewFromVec2(p)
79743
+ self.Points[#self.Points+1]=p
79744
+ self.Coords[#self.Coords+1]=coord
79745
+ end
79746
+ self.Angle=object["angle"]
79747
+ self.Heading=UTILS.ClampAngle(self.Angle+90)
79748
+ end
79749
+ end
79750
+ end
79751
+ end
79752
+ if#self.Points==0 then
79753
+ return nil
79754
+ end
79755
+ self.CenterVec2=self:GetCentroid()
79756
+ self.Triangles=self:Triangulate()
79757
+ self.SurfaceArea=self:__CalculateSurfaceArea()
79758
+ self.TriangleMarkIDs={}
79759
+ self.OutlineMarkIDs={}
79760
+ return self
79761
+ end
79762
+ function POLYGON:FromZone(zone_name)
79763
+ for _,zone in pairs(env.mission.triggers.zones)do
79764
+ if zone["name"]==zone_name then
79765
+ return POLYGON:New(unpack(zone["verticies"]or{}))
79766
+ end
79767
+ end
79768
+ end
79769
+ function POLYGON:Find(shape_name)
79770
+ return _DATABASE:FindShape(shape_name)
79771
+ end
79772
+ function POLYGON:New(...)
79773
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
79774
+ self.Points={...}
79775
+ self.Coords={}
79776
+ for _,point in UTILS.spairs(self.Points)do
79777
+ table.insert(self.Coords,COORDINATE:NewFromVec2(point))
79778
+ end
79779
+ self.Triangles=self:Triangulate()
79780
+ self.SurfaceArea=self:__CalculateSurfaceArea()
79781
+ return self
79782
+ end
79783
+ function POLYGON:GetCentroid()
79784
+ local function sum(t)
79785
+ local total=0
79786
+ for _,value in pairs(t)do
79787
+ total=total+value
79788
+ end
79789
+ return total
79790
+ end
79791
+ local x_values={}
79792
+ local y_values={}
79793
+ local length=table.length(self.Points)
79794
+ for _,point in pairs(self.Points)do
79795
+ table.insert(x_values,point.x)
79796
+ table.insert(y_values,point.y)
79797
+ end
79798
+ local x=sum(x_values)/length
79799
+ local y=sum(y_values)/length
79800
+ return{
79801
+ ["x"]=x,
79802
+ ["y"]=y
79803
+ }
79804
+ end
79805
+ function POLYGON:GetCoordinates()
79806
+ return self.Coords
79807
+ end
79808
+ function POLYGON:GetStartCoordinate()
79809
+ return self.Coords[1]
79810
+ end
79811
+ function POLYGON:GetEndCoordinate()
79812
+ return self.Coords[#self.Coords]
79813
+ end
79814
+ function POLYGON:GetStartPoint()
79815
+ return self.Points[1]
79816
+ end
79817
+ function POLYGON:GetEndPoint()
79818
+ return self.Points[#self.Points]
79819
+ end
79820
+ function POLYGON:GetPoints()
79821
+ return self.Points
79822
+ end
79823
+ function POLYGON:GetSurfaceArea()
79824
+ return self.SurfaceArea
79825
+ end
79826
+ function POLYGON:GetBoundingBox()
79827
+ local min_x,min_y,max_x,max_y=self.Points[1].x,self.Points[1].y,self.Points[1].x,self.Points[1].y
79828
+ for i=2,#self.Points do
79829
+ local x,y=self.Points[i].x,self.Points[i].y
79830
+ if x<min_x then
79831
+ min_x=x
79832
+ end
79833
+ if y<min_y then
79834
+ min_y=y
79835
+ end
79836
+ if x>max_x then
79837
+ max_x=x
79838
+ end
79839
+ if y>max_y then
79840
+ max_y=y
79841
+ end
79842
+ end
79843
+ return{
79844
+ {x=min_x,y=min_x},{x=max_x,y=min_y},{x=max_x,y=max_y},{x=min_x,y=max_y}
79845
+ }
79846
+ end
79847
+ function POLYGON:Triangulate(points)
79848
+ points=points or self.Points
79849
+ local triangles={}
79850
+ local function get_orientation(shape_points)
79851
+ local sum=0
79852
+ for i=1,#shape_points do
79853
+ local j=i%#shape_points+1
79854
+ sum=sum+(shape_points[j].x-shape_points[i].x)*(shape_points[j].y+shape_points[i].y)
79855
+ end
79856
+ return sum>=0 and"clockwise"or"counter-clockwise"
79857
+ end
79858
+ local function ensure_clockwise(shape_points)
79859
+ local orientation=get_orientation(shape_points)
79860
+ if orientation=="counter-clockwise"then
79861
+ local reversed={}
79862
+ for i=#shape_points,1,-1 do
79863
+ table.insert(reversed,shape_points[i])
79864
+ end
79865
+ return reversed
79866
+ end
79867
+ return shape_points
79868
+ end
79869
+ local function is_clockwise(p1,p2,p3)
79870
+ local cross_product=(p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x)
79871
+ return cross_product<0
79872
+ end
79873
+ local function divide_recursively(shape_points)
79874
+ if#shape_points==3 then
79875
+ table.insert(triangles,TRIANGLE:New(shape_points[1],shape_points[2],shape_points[3]))
79876
+ elseif#shape_points>3 then
79877
+ for i,p1 in ipairs(shape_points)do
79878
+ local p2=shape_points[(i%#shape_points)+1]
79879
+ local p3=shape_points[(i+1)%#shape_points+1]
79880
+ local triangle=TRIANGLE:New(p1,p2,p3)
79881
+ local is_ear=true
79882
+ if not is_clockwise(p1,p2,p3)then
79883
+ is_ear=false
79884
+ else
79885
+ for _,point in ipairs(shape_points)do
79886
+ if point~=p1 and point~=p2 and point~=p3 and triangle:ContainsPoint(point)then
79887
+ is_ear=false
79888
+ break
79889
+ end
79890
+ end
79891
+ end
79892
+ if is_ear then
79893
+ local is_valid_triangle=true
79894
+ for _,point in ipairs(points)do
79895
+ if point~=p1 and point~=p2 and point~=p3 and triangle:ContainsPoint(point)then
79896
+ is_valid_triangle=false
79897
+ break
79898
+ end
79899
+ end
79900
+ if is_valid_triangle then
79901
+ table.insert(triangles,triangle)
79902
+ local remaining_points={}
79903
+ for j,point in ipairs(shape_points)do
79904
+ if point~=p2 then
79905
+ table.insert(remaining_points,point)
79906
+ end
79907
+ end
79908
+ divide_recursively(remaining_points)
79909
+ break
79910
+ end
79911
+ end
79912
+ end
79913
+ end
79914
+ end
79915
+ points=ensure_clockwise(points)
79916
+ divide_recursively(points)
79917
+ return triangles
79918
+ end
79919
+ function POLYGON:CovarianceMatrix()
79920
+ local cx,cy=self:GetCentroid()
79921
+ local covXX,covYY,covXY=0,0,0
79922
+ for _,p in ipairs(self.points)do
79923
+ covXX=covXX+(p.x-cx)^2
79924
+ covYY=covYY+(p.y-cy)^2
79925
+ covXY=covXY+(p.x-cx)*(p.y-cy)
79926
+ end
79927
+ covXX=covXX/(#self.points-1)
79928
+ covYY=covYY/(#self.points-1)
79929
+ covXY=covXY/(#self.points-1)
79930
+ return covXX,covYY,covXY
79931
+ end
79932
+ function POLYGON:Direction()
79933
+ local covXX,covYY,covXY=self:CovarianceMatrix()
79934
+ local theta=0.5*math.atan2(2*covXY,covXX-covYY)
79935
+ return math.cos(theta),math.sin(theta)
79936
+ end
79937
+ function POLYGON:GetRandomVec2()
79938
+ local weights={}
79939
+ for _,triangle in pairs(self.Triangles)do
79940
+ weights[triangle]=triangle.SurfaceArea/self.SurfaceArea
79941
+ end
79942
+ local random_weight=math.random()
79943
+ local accumulated_weight=0
79944
+ for triangle,weight in pairs(weights)do
79945
+ accumulated_weight=accumulated_weight+weight
79946
+ if accumulated_weight>=random_weight then
79947
+ return triangle:GetRandomVec2()
79948
+ end
79949
+ end
79950
+ end
79951
+ function POLYGON:GetRandomNonWeightedVec2()
79952
+ return self.Triangles[math.random(1,#self.Triangles)]:GetRandomVec2()
79953
+ end
79954
+ function POLYGON:ContainsPoint(point,polygon_points)
79955
+ local x=point.x
79956
+ local y=point.y
79957
+ polygon_points=polygon_points or self.Points
79958
+ local counter=0
79959
+ local num_points=#polygon_points
79960
+ for current_index=1,num_points do
79961
+ local next_index=(current_index%num_points)+1
79962
+ local current_x,current_y=polygon_points[current_index].x,polygon_points[current_index].y
79963
+ local next_x,next_y=polygon_points[next_index].x,polygon_points[next_index].y
79964
+ if((current_y>y)~=(next_y>y))and(x<(next_x-current_x)*(y-current_y)/(next_y-current_y)+current_x)then
79965
+ counter=counter+1
79966
+ end
79967
+ end
79968
+ return counter%2==1
79969
+ end
79970
+ function POLYGON:Draw(include_inner_triangles)
79971
+ include_inner_triangles=include_inner_triangles or false
79972
+ for i=1,#self.Coords do
79973
+ local c1=self.Coords[i]
79974
+ local c2=self.Coords[i%#self.Coords+1]
79975
+ table.add(self.OutlineMarkIDs,c1:LineToAll(c2))
79976
+ end
79977
+ if include_inner_triangles then
79978
+ for _,triangle in ipairs(self.Triangles)do
79979
+ triangle:Draw()
79980
+ end
79981
+ end
79982
+ end
79983
+ function POLYGON:RemoveDraw()
79984
+ for _,triangle in pairs(self.Triangles)do
79985
+ triangle:RemoveDraw()
79986
+ end
79987
+ for _,mark_id in pairs(self.OutlineMarkIDs)do
79988
+ UTILS.RemoveMark(mark_id)
79989
+ end
79990
+ end
79991
+ function POLYGON:__CalculateSurfaceArea()
79992
+ local area=0
79993
+ for _,triangle in pairs(self.Triangles)do
79994
+ area=area+triangle.SurfaceArea
79995
+ end
79996
+ return area
79997
+ end
79998
+ TRIANGLE={
79999
+ ClassName="TRIANGLE",
80000
+ Points={},
80001
+ Coords={},
80002
+ SurfaceArea=0
80003
+ }
80004
+ function TRIANGLE:New(p1,p2,p3)
80005
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
80006
+ self.Points={p1,p2,p3}
80007
+ local center_x=(p1.x+p2.x+p3.x)/3
80008
+ local center_y=(p1.y+p2.y+p3.y)/3
80009
+ self.CenterVec2={x=center_x,y=center_y}
80010
+ for _,pt in pairs({p1,p2,p3})do
80011
+ table.add(self.Coords,COORDINATE:NewFromVec2(pt))
80012
+ end
80013
+ self.SurfaceArea=math.abs((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))*0.5
80014
+ self.MarkIDs={}
80015
+ return self
80016
+ end
80017
+ function TRIANGLE:ContainsPoint(pt,points)
80018
+ points=points or self.Points
80019
+ local function sign(p1,p2,p3)
80020
+ return(p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y)
80021
+ end
80022
+ local d1=sign(pt,self.Points[1],self.Points[2])
80023
+ local d2=sign(pt,self.Points[2],self.Points[3])
80024
+ local d3=sign(pt,self.Points[3],self.Points[1])
80025
+ local has_neg=(d1<0)or(d2<0)or(d3<0)
80026
+ local has_pos=(d1>0)or(d2>0)or(d3>0)
80027
+ return not(has_neg and has_pos)
80028
+ end
80029
+ function TRIANGLE:GetRandomVec2(points)
80030
+ points=points or self.Points
80031
+ local pt={math.random(),math.random()}
80032
+ table.sort(pt)
80033
+ local s=pt[1]
80034
+ local t=pt[2]-pt[1]
80035
+ local u=1-pt[2]
80036
+ return{x=s*points[1].x+t*points[2].x+u*points[3].x,
80037
+ y=s*points[1].y+t*points[2].y+u*points[3].y}
80038
+ end
80039
+ function TRIANGLE:Draw()
80040
+ for i=1,#self.Coords do
80041
+ local c1=self.Coords[i]
80042
+ local c2=self.Coords[i%#self.Coords+1]
80043
+ table.add(self.MarkIDs,c1:LineToAll(c2))
80044
+ end
80045
+ end
80046
+ function TRIANGLE:RemoveDraw()
80047
+ for _,mark_id in pairs(self.MarkIDs)do
80048
+ UTILS.RemoveMark(mark_id)
80049
+ end
80050
+ end
78530
80051
  do
78531
80052
  USERSOUND={
78532
80053
  ClassName="USERSOUND",
@@ -79788,7 +81309,7 @@ end
79788
81309
  function MSRS:SetVoiceProvider(Voice,Provider)
79789
81310
  self:F({Voice=Voice,Provider=Provider})
79790
81311
  self.poptions=self.poptions or{}
79791
- self.poptions[Provider or self:GetProvider()]=Voice
81312
+ self.poptions[Provider or self:GetProvider()].voice=Voice
79792
81313
  return self
79793
81314
  end
79794
81315
  function MSRS:SetVoiceWindows(Voice)
@@ -82636,7 +84157,7 @@ local ActRouteTarget=ProcessUnit:GetProcess("Engaging","RouteToTargetZone")
82636
84157
  return ActRouteTarget:GetZone()
82637
84158
  end
82638
84159
  function TASK_A2G:SetGoalTotal()
82639
- self.GoalTotal=self.TargetSetUnit:Count()
84160
+ self.GoalTotal=self.TargetSetUnit:CountAlive()
82640
84161
  end
82641
84162
  function TASK_A2G:GetGoalTotal()
82642
84163
  return self.GoalTotal
@@ -82649,7 +84170,7 @@ return Distance
82649
84170
  end
82650
84171
  function TASK_A2G:onafterGoal(TaskUnit,From,Event,To)
82651
84172
  local TargetSetUnit=self.TargetSetUnit
82652
- if TargetSetUnit:Count()==0 then
84173
+ if TargetSetUnit:CountAlive()==0 then
82653
84174
  self:Success()
82654
84175
  end
82655
84176
  self:__Goal(-10)
@@ -82667,7 +84188,7 @@ ThreatLevel,ThreatText=self.TargetSetUnit:CalculateThreatLevelA2G()
82667
84188
  end
82668
84189
  self.TaskInfo:AddThreat(ThreatText,ThreatLevel,10,"MOD",true)
82669
84190
  if self.Detection then
82670
- local DetectedItemsCount=self.TargetSetUnit:Count()
84191
+ local DetectedItemsCount=self.TargetSetUnit:CountAlive()
82671
84192
  local ReportTypes=REPORT:New()
82672
84193
  local TargetTypes={}
82673
84194
  for TargetUnitName,TargetUnit in pairs(self.TargetSetUnit:GetSet())do
@@ -82680,7 +84201,7 @@ end
82680
84201
  self.TaskInfo:AddTargetCount(DetectedItemsCount,11,"O",true)
82681
84202
  self.TaskInfo:AddTargets(DetectedItemsCount,ReportTypes:Text(", "),20,"D",true)
82682
84203
  else
82683
- local DetectedItemsCount=self.TargetSetUnit:Count()
84204
+ local DetectedItemsCount=self.TargetSetUnit:CountAlive()
82684
84205
  local DetectedItemsTypes=self.TargetSetUnit:GetTypeNames()
82685
84206
  self.TaskInfo:AddTargetCount(DetectedItemsCount,11,"O",true)
82686
84207
  self.TaskInfo:AddTargets(DetectedItemsCount,DetectedItemsTypes,20,"D",true)