@jtff/miztemplate-lib 3.2.0 → 3.2.2

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-04-30T09:18:49+02:00-27d36f3e0d82fd46b94fb09e6ebb81b963bc40c0 ***')
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
@@ -18761,6 +19031,18 @@ function SPAWN:InitDelayOff()
18761
19031
  return self:InitDelayOnOff(false)
18762
19032
  end
18763
19033
  end
19034
+ function SPAWN:InitHiddenOnMap()
19035
+ self.SpawnHiddenOnMap=true
19036
+ return self
19037
+ end
19038
+ function SPAWN:InitHiddenOnMFD()
19039
+ self.SpawnHiddenOnMFD=true
19040
+ return self
19041
+ end
19042
+ function SPAWN:InitHiddenOnPlanner()
19043
+ self.SpawnHiddenOnPlanner=true
19044
+ return self
19045
+ end
18764
19046
  function SPAWN:Spawn()
18765
19047
  self:F({self.SpawnTemplatePrefix,self.SpawnIndex,self.AliveUnits})
18766
19048
  if self.SpawnInitAirbase then
@@ -18953,6 +19235,15 @@ end
18953
19235
  if self.SpawnInitModu then
18954
19236
  SpawnTemplate.modulation=self.SpawnInitModu
18955
19237
  end
19238
+ if self.SpawnHiddenOnPlanner then
19239
+ SpawnTemplate.hiddenOnPlanner=true
19240
+ end
19241
+ if self.SpawnHiddenOnMFD then
19242
+ SpawnTemplate.hiddenOnMFD=true
19243
+ end
19244
+ if self.SpawnHiddenOnMap then
19245
+ SpawnTemplate.hidden=true
19246
+ end
18956
19247
  SpawnTemplate.CategoryID=self.SpawnInitCategory or SpawnTemplate.CategoryID
18957
19248
  SpawnTemplate.CountryID=self.SpawnInitCountry or SpawnTemplate.CountryID
18958
19249
  SpawnTemplate.CoalitionID=self.SpawnInitCoalition or SpawnTemplate.CoalitionID
@@ -18981,6 +19272,7 @@ self.SpawnHookScheduler:Schedule(nil,self.SpawnFunctionHook,{self.SpawnGroups[se
18981
19272
  end
18982
19273
  end
18983
19274
  self.SpawnGroups[self.SpawnIndex].Spawned=true
19275
+ self.SpawnGroups[self.SpawnIndex].Group.TemplateDonor=self.SpawnTemplatePrefix
18984
19276
  return self.SpawnGroups[self.SpawnIndex].Group
18985
19277
  else
18986
19278
  end
@@ -19786,8 +20078,17 @@ SpawnTemplate.units[UnitID].unitId=nil
19786
20078
  end
19787
20079
  else
19788
20080
  for UnitID=1,#SpawnTemplate.units do
19789
- local UnitPrefix,Rest=string.match(SpawnTemplate.units[UnitID].name,"^([^#]+)#?"):gsub("^%s*(.-)%s*$","%1")
20081
+ local SpawnInitKeepUnitIFF=false
20082
+ if string.find(SpawnTemplate.units[UnitID].name,"#IFF_",1,true)then
20083
+ SpawnInitKeepUnitIFF=true
20084
+ end
20085
+ local UnitPrefix,Rest
20086
+ if SpawnInitKeepUnitIFF==false then
20087
+ UnitPrefix,Rest=string.match(SpawnTemplate.units[UnitID].name,"^([^#]+)#?"):gsub("^%s*(.-)%s*$","%1")
19790
20088
  self:T({UnitPrefix,Rest})
20089
+ else
20090
+ UnitPrefix=SpawnTemplate.units[UnitID].name
20091
+ end
19791
20092
  SpawnTemplate.units[UnitID].name=string.format('%s#%03d-%02d',UnitPrefix,SpawnIndex,UnitID)
19792
20093
  SpawnTemplate.units[UnitID].unitId=nil
19793
20094
  end
@@ -19859,32 +20160,54 @@ elseif type(Callsign)=="number"then
19859
20160
  SpawnTemplate.units[UnitID].callsign=Callsign+SpawnIndex
19860
20161
  end
19861
20162
  end
20163
+ if self.InitSpeed then
20164
+ SpawnTemplate.units[UnitID].speed=self.InitSpeed
20165
+ end
19862
20166
  local AddProps=SpawnTemplate.units[UnitID].AddPropAircraft
19863
20167
  if AddProps then
19864
20168
  if SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16 then
20169
+ if self.SpawnInitSTN then
20170
+ local octal=self.SpawnInitSTN
20171
+ if UnitID>1 then
20172
+ octal=_DATABASE:GetNextSTN(self.SpawnInitSTN,SpawnTemplate.units[UnitID].name)
20173
+ end
20174
+ SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16=string.format("%05d",octal)
20175
+ else
19865
20176
  if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16)~=nil then
19866
20177
  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))
20178
+ local num=UTILS.OctalToDecimal(octal)
20179
+ if _DATABASE.STNS[num]~=nil or UnitID>1 then
20180
+ octal=_DATABASE:GetNextSTN(octal,SpawnTemplate.units[UnitID].name)
20181
+ end
20182
+ SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16=string.format("%05d",octal)
19869
20183
  else
19870
- local STN=math.floor(UTILS.RandomGaussian(4088/2,nil,1000,4088))
19871
- STN=STN+UnitID-1
19872
- local OSTN=UTILS.DecimalToOctal(STN)
20184
+ local OSTN=_DATABASE:GetNextSTN(1,SpawnTemplate.units[UnitID].name)
19873
20185
  SpawnTemplate.units[UnitID].AddPropAircraft.STN_L16=string.format("%05d",OSTN)
19874
20186
  end
19875
20187
  end
20188
+ end
19876
20189
  if SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN then
20190
+ if self.SpawnInitSADL then
20191
+ local octal=self.SpawnInitSADL
20192
+ if UnitID>1 then
20193
+ octal=_DATABASE:GetNextSADL(self.SpawnInitSADL,SpawnTemplate.units[UnitID].name)
20194
+ end
20195
+ SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN=string.format("%04d",octal)
20196
+ else
19877
20197
  if tonumber(SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN)~=nil then
19878
20198
  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))
20199
+ local num=UTILS.OctalToDecimal(octal)
20200
+ self.SpawnInitSADL=num
20201
+ if _DATABASE.SADL[num]~=nil or UnitID>1 then
20202
+ octal=_DATABASE:GetNextSADL(self.SpawnInitSADL,SpawnTemplate.units[UnitID].name)
20203
+ end
20204
+ SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN=string.format("%04d",octal)
19881
20205
  else
19882
- local STN=math.floor(UTILS.RandomGaussian(504/2,nil,100,504))
19883
- STN=STN+UnitID-1
19884
- local OSTN=UTILS.DecimalToOctal(STN)
20206
+ local OSTN=_DATABASE:GetNextSADL(1,SpawnTemplate.units[UnitID].name)
19885
20207
  SpawnTemplate.units[UnitID].AddPropAircraft.SADL_TN=string.format("%04d",OSTN)
19886
20208
  end
19887
20209
  end
20210
+ end
19888
20211
  if SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignNumber and type(Callsign)~="number"then
19889
20212
  SpawnTemplate.units[UnitID].AddPropAircraft.VoiceCallsignNumber=SpawnTemplate.units[UnitID].callsign[2]..SpawnTemplate.units[UnitID].callsign[3]
19890
20213
  end
@@ -20648,7 +20971,7 @@ MARKEROPS_BASE={
20648
20971
  ClassName="MARKEROPS",
20649
20972
  Tag="mytag",
20650
20973
  Keywords={},
20651
- version="0.1.1",
20974
+ version="0.1.3",
20652
20975
  debug=false,
20653
20976
  Casesensitive=true,
20654
20977
  }
@@ -20688,26 +21011,27 @@ local coordtext=coord:ToStringLLDDM()
20688
21011
  local text=tostring(Event.text)
20689
21012
  local m=MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
20690
21013
  end
21014
+ local coalition=Event.MarkCoalition
20691
21015
  if Event.id==world.event.S_EVENT_MARK_ADDED then
20692
- self:T({event="S_EVENT_MARK_ADDED",carrier=self.groupname,vec3=Event.pos})
21016
+ self:T({event="S_EVENT_MARK_ADDED",carrier=Event.IniGroupName,vec3=Event.pos})
20693
21017
  local Eventtext=tostring(Event.text)
20694
21018
  if Eventtext~=nil then
20695
21019
  if self:_MatchTag(Eventtext)then
20696
21020
  local matchtable=self:_MatchKeywords(Eventtext)
20697
- self:MarkAdded(Eventtext,matchtable,coord)
21021
+ self:MarkAdded(Eventtext,matchtable,coord,Event.idx,coalition)
20698
21022
  end
20699
21023
  end
20700
21024
  elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
20701
- self:T({event="S_EVENT_MARK_CHANGE",carrier=self.groupname,vec3=Event.pos})
21025
+ self:T({event="S_EVENT_MARK_CHANGE",carrier=Event.IniGroupName,vec3=Event.pos})
20702
21026
  local Eventtext=tostring(Event.text)
20703
21027
  if Eventtext~=nil then
20704
21028
  if self:_MatchTag(Eventtext)then
20705
21029
  local matchtable=self:_MatchKeywords(Eventtext)
20706
- self:MarkChanged(Eventtext,matchtable,coord,Event.idx)
21030
+ self:MarkChanged(Eventtext,matchtable,coord,Event.idx,coalition)
20707
21031
  end
20708
21032
  end
20709
21033
  elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
20710
- self:T({event="S_EVENT_MARK_REMOVED",carrier=self.groupname,vec3=Event.pos})
21034
+ self:T({event="S_EVENT_MARK_REMOVED",carrier=Event.IniGroupName,vec3=Event.pos})
20711
21035
  local Eventtext=tostring(Event.text)
20712
21036
  if Eventtext~=nil then
20713
21037
  if self:_MatchTag(Eventtext)then
@@ -20741,10 +21065,10 @@ end
20741
21065
  end
20742
21066
  return matchtable
20743
21067
  end
20744
- function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord)
21068
+ function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord,MarkerID,CoalitionNumber)
20745
21069
  self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
20746
21070
  end
20747
- function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord)
21071
+ function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord,MarkerID,CoalitionNumber)
20748
21072
  self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
20749
21073
  end
20750
21074
  function MARKEROPS_BASE:onbeforeMarkDeleted(From,Event,To)
@@ -23225,7 +23549,7 @@ local TaskRoute=PatrolGroup:TaskFunction("CONTROLLABLE.PatrolRoute")
23225
23549
  self:F({Waypoints=Waypoints})
23226
23550
  local Waypoint=Waypoints[#Waypoints]
23227
23551
  PatrolGroup:SetTaskWaypoint(Waypoint,TaskRoute)
23228
- PatrolGroup:Route(Waypoints)
23552
+ PatrolGroup:Route(Waypoints,2)
23229
23553
  end
23230
23554
  end
23231
23555
  function CONTROLLABLE:PatrolRouteRandom(Speed,Formation,ToWaypoint)
@@ -24183,6 +24507,9 @@ return nil
24183
24507
  end
24184
24508
  function CONTROLLABLE:WayPointFunction(WayPoint,WayPointIndex,WayPointFunction,...)
24185
24509
  self:F2({WayPoint,WayPointIndex,WayPointFunction})
24510
+ if not self.WayPoints then
24511
+ self:WayPointInitialize()
24512
+ end
24186
24513
  table.insert(self.WayPoints[WayPoint].task.params.tasks,WayPointIndex)
24187
24514
  self.WayPoints[WayPoint].task.params.tasks[WayPointIndex]=self:TaskFunction(WayPointFunction,arg)
24188
24515
  return self
@@ -24306,6 +24633,49 @@ self:SetOption(AI.Option.Air.id.RADAR_USING,3)
24306
24633
  end
24307
24634
  return self
24308
24635
  end
24636
+ function CONTROLLABLE:SetOptionWaypointPassReport(OnOff)
24637
+ self:F2({self.ControllableName})
24638
+ local onoff=(OnOff==nil or OnOff==true)and false or true
24639
+ if self:IsAir()then
24640
+ self:SetOption(AI.Option.Air.id.PROHIBIT_WP_PASS_REPORT,onoff)
24641
+ end
24642
+ return self
24643
+ end
24644
+ function CONTROLLABLE:SetOptionRadioSilence(OnOff)
24645
+ local onoff=(OnOff==true or OnOff==nil)and true or false
24646
+ self:F2({self.ControllableName})
24647
+ if self:IsAir()then
24648
+ self:SetOption(AI.Option.Air.id.SILENCE,onoff)
24649
+ end
24650
+ return self
24651
+ end
24652
+ function CONTROLLABLE:SetOptionRadioContact(Objects)
24653
+ self:F2({self.ControllableName})
24654
+ if not Objects then Objects={"Air"}end
24655
+ if type(Objects)~="table"then Objects={Objects}end
24656
+ if self:IsAir()then
24657
+ self:SetOption(AI.Option.Air.id.OPTION_RADIO_USAGE_CONTACT,Objects)
24658
+ end
24659
+ return self
24660
+ end
24661
+ function CONTROLLABLE:SetOptionRadioEngage(Objects)
24662
+ self:F2({self.ControllableName})
24663
+ if not Objects then Objects={"Air"}end
24664
+ if type(Objects)~="table"then Objects={Objects}end
24665
+ if self:IsAir()then
24666
+ self:SetOption(AI.Option.Air.id.OPTION_RADIO_USAGE_ENGAGE,Objects)
24667
+ end
24668
+ return self
24669
+ end
24670
+ function CONTROLLABLE:SetOptionRadioKill(Objects)
24671
+ self:F2({self.ControllableName})
24672
+ if not Objects then Objects={"Air"}end
24673
+ if type(Objects)~="table"then Objects={Objects}end
24674
+ if self:IsAir()then
24675
+ self:SetOption(AI.Option.Air.id.OPTION_RADIO_USAGE_KILL,Objects)
24676
+ end
24677
+ return self
24678
+ end
24309
24679
  function CONTROLLABLE:RelocateGroundRandomInRadius(speed,radius,onroad,shortcut,formation,onland)
24310
24680
  self:F2({self.ControllableName})
24311
24681
  local _coord=self:GetCoordinate()
@@ -25377,7 +25747,7 @@ end
25377
25747
  function GROUP:IsActive()
25378
25748
  self:F2(self.GroupName)
25379
25749
  local DCSGroup=self:GetDCSObject()
25380
- if DCSGroup then
25750
+ if DCSGroup and DCSGroup:isExist()then
25381
25751
  local unit=DCSGroup:getUnit(1)
25382
25752
  if unit then
25383
25753
  local GroupIsActive=unit:isActive()
@@ -25835,7 +26205,7 @@ function GROUP:GetCoordinate()
25835
26205
  local Units=self:GetUnits()or{}
25836
26206
  for _,_unit in pairs(Units)do
25837
26207
  local FirstUnit=_unit
25838
- if FirstUnit then
26208
+ if FirstUnit and FirstUnit:IsAlive()then
25839
26209
  local FirstUnitCoordinate=FirstUnit:GetCoordinate()
25840
26210
  if FirstUnitCoordinate then
25841
26211
  local Heading=self:GetHeading()
@@ -25844,6 +26214,18 @@ return FirstUnitCoordinate
25844
26214
  end
25845
26215
  end
25846
26216
  end
26217
+ local DCSGroup=Group.getByName(self.GroupName)
26218
+ local DCSUnits=DCSGroup:getUnits()or{}
26219
+ for _,_unit in pairs(DCSUnits)do
26220
+ if Object.isExist(_unit)then
26221
+ local position=_unit:getPosition()
26222
+ local point=position.p~=nil and position.p or _unit:GetPoint()
26223
+ if point then
26224
+ local coord=COORDINATE:NewFromVec3(point)
26225
+ return coord
26226
+ end
26227
+ end
26228
+ end
25847
26229
  BASE:E({"Cannot GetCoordinate",Group=self,Alive=self:IsAlive()})
25848
26230
  end
25849
26231
  function GROUP:GetRandomVec3(Radius)
@@ -26705,6 +27087,9 @@ end
26705
27087
  return self
26706
27088
  end
26707
27089
  function GROUP:SetCommandInvisible(switch)
27090
+ return self:CommandSetInvisible(switch)
27091
+ end
27092
+ function GROUP:CommandSetInvisible(switch)
26708
27093
  self:F2(self.GroupName)
26709
27094
  if switch==nil then
26710
27095
  switch=false
@@ -26714,6 +27099,9 @@ self:SetCommand(SetInvisible)
26714
27099
  return self
26715
27100
  end
26716
27101
  function GROUP:SetCommandImmortal(switch)
27102
+ return self:CommandSetImmortal(switch)
27103
+ end
27104
+ function GROUP:CommandSetImmortal(switch)
26717
27105
  self:F2(self.GroupName)
26718
27106
  if switch==nil then
26719
27107
  switch=false
@@ -27445,7 +27833,9 @@ local ThreatLevels={
27445
27833
  }
27446
27834
  if Attributes["Fighters"]then ThreatLevel=10
27447
27835
  elseif Attributes["Multirole fighters"]then ThreatLevel=9
27836
+ elseif Attributes["Interceptors"]then ThreatLevel=9
27448
27837
  elseif Attributes["Battleplanes"]then ThreatLevel=8
27838
+ elseif Attributes["Battle airplanes"]then ThreatLevel=8
27449
27839
  elseif Attributes["Attack helicopters"]then ThreatLevel=7
27450
27840
  elseif Attributes["Strategic bombers"]then ThreatLevel=6
27451
27841
  elseif Attributes["Bombers"]then ThreatLevel=5
@@ -28075,6 +28465,25 @@ SpawnStatic:SpawnFromCoordinate(Coordinate,Heading,self.StaticName)
28075
28465
  end
28076
28466
  return self
28077
28467
  end
28468
+ function STATIC:FindByMatching(Pattern)
28469
+ local GroupFound=nil
28470
+ for name,static in pairs(_DATABASE.STATICS)do
28471
+ if string.match(name,Pattern)then
28472
+ GroupFound=static
28473
+ break
28474
+ end
28475
+ end
28476
+ return GroupFound
28477
+ end
28478
+ function STATIC:FindAllByMatching(Pattern)
28479
+ local GroupsFound={}
28480
+ for name,static in pairs(_DATABASE.STATICS)do
28481
+ if string.match(name,Pattern)then
28482
+ GroupsFound[#GroupsFound+1]=static
28483
+ end
28484
+ end
28485
+ return GroupsFound
28486
+ end
28078
28487
  AIRBASE={
28079
28488
  ClassName="AIRBASE",
28080
28489
  CategoryName={
@@ -28085,152 +28494,155 @@ CategoryName={
28085
28494
  activerwyno=nil,
28086
28495
  }
28087
28496
  AIRBASE.Caucasus={
28497
+ ["Anapa_Vityazevo"]="Anapa-Vityazevo",
28498
+ ["Batumi"]="Batumi",
28499
+ ["Beslan"]="Beslan",
28088
28500
  ["Gelendzhik"]="Gelendzhik",
28089
- ["Krasnodar_Pashkovsky"]="Krasnodar-Pashkovsky",
28090
- ["Sukhumi_Babushara"]="Sukhumi-Babushara",
28091
28501
  ["Gudauta"]="Gudauta",
28092
- ["Batumi"]="Batumi",
28093
- ["Senaki_Kolkhi"]="Senaki-Kolkhi",
28094
28502
  ["Kobuleti"]="Kobuleti",
28095
- ["Kutaisi"]="Kutaisi",
28096
- ["Tbilisi_Lochini"]="Tbilisi-Lochini",
28097
- ["Soganlug"]="Soganlug",
28098
- ["Vaziani"]="Vaziani",
28099
- ["Anapa_Vityazevo"]="Anapa-Vityazevo",
28100
28503
  ["Krasnodar_Center"]="Krasnodar-Center",
28101
- ["Novorossiysk"]="Novorossiysk",
28504
+ ["Krasnodar_Pashkovsky"]="Krasnodar-Pashkovsky",
28102
28505
  ["Krymsk"]="Krymsk",
28506
+ ["Kutaisi"]="Kutaisi",
28103
28507
  ["Maykop_Khanskaya"]="Maykop-Khanskaya",
28104
- ["Sochi_Adler"]="Sochi-Adler",
28105
28508
  ["Mineralnye_Vody"]="Mineralnye Vody",
28106
- ["Nalchik"]="Nalchik",
28107
28509
  ["Mozdok"]="Mozdok",
28108
- ["Beslan"]="Beslan",
28510
+ ["Nalchik"]="Nalchik",
28511
+ ["Novorossiysk"]="Novorossiysk",
28512
+ ["Senaki_Kolkhi"]="Senaki-Kolkhi",
28513
+ ["Sochi_Adler"]="Sochi-Adler",
28514
+ ["Soganlug"]="Soganlug",
28515
+ ["Sukhumi_Babushara"]="Sukhumi-Babushara",
28516
+ ["Tbilisi_Lochini"]="Tbilisi-Lochini",
28517
+ ["Vaziani"]="Vaziani",
28109
28518
  }
28110
28519
  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",
28520
+ ["Beatty"]="Beatty",
28521
+ ["Boulder_City"]="Boulder City",
28522
+ ["Creech"]="Creech",
28117
28523
  ["Echo_Bay"]="Echo Bay",
28118
- ["Henderson_Executive_Airport"]="Henderson Executive",
28119
- ["Jean_Airport"]="Jean",
28120
- ["Laughlin_Airport"]="Laughlin",
28524
+ ["Groom_Lake"]="Groom Lake",
28525
+ ["Henderson_Executive"]="Henderson Executive",
28526
+ ["Jean"]="Jean",
28527
+ ["Laughlin"]="Laughlin",
28121
28528
  ["Lincoln_County"]="Lincoln County",
28529
+ ["McCarran_International"]="McCarran International",
28122
28530
  ["Mesquite"]="Mesquite",
28123
- ["Mina_Airport"]="Mina",
28531
+ ["Mina"]="Mina",
28532
+ ["Nellis"]="Nellis",
28124
28533
  ["North_Las_Vegas"]="North Las Vegas",
28125
- ["Pahute_Mesa_Airstrip"]="Pahute Mesa",
28126
- ["Tonopah_Airport"]="Tonopah",
28127
- ["Tonopah_Test_Range_Airfield"]="Tonopah Test Range",
28534
+ ["Pahute_Mesa"]="Pahute Mesa",
28535
+ ["Tonopah"]="Tonopah",
28536
+ ["Tonopah_Test_Range"]="Tonopah Test Range",
28128
28537
  }
28129
28538
  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",
28539
+ ["Abbeville_Drucat"]="Abbeville Drucat",
28540
+ ["Amiens_Glisy"]="Amiens-Glisy",
28541
+ ["Argentan"]="Argentan",
28542
+ ["Avranches_Le_Val_Saint_Pere"]="Avranches Le Val-Saint-Pere",
28144
28543
  ["Azeville"]="Azeville",
28145
- ["Picauville"]="Picauville",
28146
- ["Le_Molay"]="Le Molay",
28147
- ["Longues_sur_Mer"]="Longues-sur-Mer",
28148
- ["Carpiquet"]="Carpiquet",
28544
+ ["Barville"]="Barville",
28149
28545
  ["Bazenville"]="Bazenville",
28150
- ["Sainte_Croix_sur_Mer"]="Sainte-Croix-sur-Mer",
28546
+ ["Beaumont_le_Roger"]="Beaumont-le-Roger",
28547
+ ["Beauvais_Tille"]="Beauvais-Tille",
28151
28548
  ["Beny_sur_Mer"]="Beny-sur-Mer",
28152
- ["Rucqueville"]="Rucqueville",
28153
- ["Sommervieu"]="Sommervieu",
28154
- ["Lantheuil"]="Lantheuil",
28155
- ["Evreux"]="Evreux",
28549
+ ["Bernay_Saint_Martin"]="Bernay Saint Martin",
28550
+ ["Beuzeville"]="Beuzeville",
28551
+ ["Biggin_Hill"]="Biggin Hill",
28552
+ ["Biniville"]="Biniville",
28553
+ ["Broglie"]="Broglie",
28554
+ ["Brucheville"]="Brucheville",
28555
+ ["Cardonville"]="Cardonville",
28556
+ ["Carpiquet"]="Carpiquet",
28156
28557
  ["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",
28558
+ ["Chippelle"]="Chippelle",
28169
28559
  ["Conches"]="Conches",
28170
- ["West_Malling"]="West Malling",
28171
- ["Villacoublay"]="Villacoublay",
28172
- ["Kenley"]="Kenley",
28173
- ["Beauvais_Tille"]="Beauvais-Tille",
28174
28560
  ["Cormeilles_en_Vexin"]="Cormeilles-en-Vexin",
28175
28561
  ["Creil"]="Creil",
28176
- ["Guyancourt"]="Guyancourt",
28177
- ["Lonrai"]="Lonrai",
28562
+ ["Cretteville"]="Cretteville",
28563
+ ["Cricqueville_en_Bessin"]="Cricqueville-en-Bessin",
28564
+ ["Deanland"]="Deanland",
28565
+ ["Deauville"]="Deauville",
28566
+ ["Detling"]="Detling",
28567
+ ["Deux_Jumeaux"]="Deux Jumeaux",
28178
28568
  ["Dinan_Trelivan"]="Dinan-Trelivan",
28179
- ["Heathrow"]="Heathrow",
28180
- ["Fecamp_Benouville"]="Fecamp-Benouville",
28569
+ ["Dunkirk_Mardyck"]="Dunkirk-Mardyck",
28570
+ ["Essay"]="Essay",
28571
+ ["Evreux"]="Evreux",
28181
28572
  ["Farnborough"]="Farnborough",
28573
+ ["Fecamp_Benouville"]="Fecamp-Benouville",
28574
+ ["Flers"]="Flers",
28575
+ ["Ford"]="Ford",
28182
28576
  ["Friston"]="Friston",
28183
- ["Deanland "]="Deanland ",
28184
- ["Triqueville"]="Triqueville",
28185
- ["Poix"]="Poix",
28577
+ ["Funtington"]="Funtington",
28578
+ ["Goulet"]="Goulet",
28579
+ ["Gravesend"]="Gravesend",
28580
+ ["Guyancourt"]="Guyancourt",
28581
+ ["Hauterive"]="Hauterive",
28582
+ ["Heathrow"]="Heathrow",
28583
+ ["High_Halden"]="High Halden",
28584
+ ["Kenley"]="Kenley",
28585
+ ["Lantheuil"]="Lantheuil",
28586
+ ["Le_Molay"]="Le Molay",
28587
+ ["Lessay"]="Lessay",
28588
+ ["Lignerolles"]="Lignerolles",
28589
+ ["Longues_sur_Mer"]="Longues-sur-Mer",
28590
+ ["Lonrai"]="Lonrai",
28591
+ ["Lymington"]="Lymington",
28592
+ ["Lympne"]="Lympne",
28593
+ ["Manston"]="Manston",
28594
+ ["Maupertus"]="Maupertus",
28595
+ ["Meautis"]="Meautis",
28596
+ ["Merville_Calonne"]="Merville Calonne",
28597
+ ["Needs_Oar_Point"]="Needs Oar Point",
28598
+ ["Odiham"]="Odiham",
28186
28599
  ["Orly"]="Orly",
28187
- ["Stoney_Cross"]="Stoney Cross",
28188
- ["Amiens_Glisy"]="Amiens-Glisy",
28600
+ ["Picauville"]="Picauville",
28601
+ ["Poix"]="Poix",
28189
28602
  ["Ronai"]="Ronai",
28190
28603
  ["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",
28604
+ ["Rucqueville"]="Rucqueville",
28199
28605
  ["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",
28606
+ ["Saint_Aubin"]="Saint-Aubin",
28206
28607
  ["Saint_Omer_Wizernes"]="Saint-Omer Wizernes",
28608
+ ["Saint_Pierre_du_Mont"]="Saint Pierre du Mont",
28609
+ ["Sainte_Croix_sur_Mer"]="Sainte-Croix-sur-Mer",
28610
+ ["Sainte_Laurent_sur_Mer"]="Sainte-Laurent-sur-Mer",
28611
+ ["Sommervieu"]="Sommervieu",
28612
+ ["Stoney_Cross"]="Stoney Cross",
28613
+ ["Tangmere"]="Tangmere",
28614
+ ["Triqueville"]="Triqueville",
28615
+ ["Villacoublay"]="Villacoublay",
28616
+ ["Vrigny"]="Vrigny",
28617
+ ["West_Malling"]="West Malling",
28207
28618
  }
28208
28619
  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",
28620
+ ["Abu_Dhabi_Intl"]="Abu Dhabi Intl",
28621
+ ["Abu_Musa_Island"]="Abu Musa Island",
28622
+ ["Al_Ain_Intl"]="Al Ain Intl",
28623
+ ["Al_Bateen"]="Al-Bateen",
28624
+ ["Al_Dhafra_AFB"]="Al Dhafra AFB",
28214
28625
  ["Al_Maktoum_Intl"]="Al Maktoum Intl",
28215
- ["Al_Minhad_AB"]="Al Minhad AFB",
28626
+ ["Al_Minhad_AFB"]="Al Minhad AFB",
28216
28627
  ["Bandar_Abbas_Intl"]="Bandar Abbas Intl",
28217
28628
  ["Bandar_Lengeh"]="Bandar Lengeh",
28218
- ["Bandar_e_Jask_airfield"]="Bandar-e-Jask",
28629
+ ["Bandar_e_Jask"]="Bandar-e-Jask",
28219
28630
  ["Dubai_Intl"]="Dubai Intl",
28220
28631
  ["Fujairah_Intl"]="Fujairah Intl",
28221
28632
  ["Havadarya"]="Havadarya",
28222
- ["Jiroft_Airport"]="Jiroft",
28223
- ["Kerman_Airport"]="Kerman",
28633
+ ["Jiroft"]="Jiroft",
28634
+ ["Kerman"]="Kerman",
28224
28635
  ["Khasab"]="Khasab",
28225
- ["Kish_International_Airport"]="Kish Intl",
28226
- ["Lar_Airbase"]="Lar",
28227
- ["Lavan_Island_Airport"]="Lavan Island",
28228
- ["Liwa_Airbase"]="Liwa AFB",
28636
+ ["Kish_Intl"]="Kish Intl",
28637
+ ["Lar"]="Lar",
28638
+ ["Lavan_Island"]="Lavan Island",
28639
+ ["Liwa_AFB"]="Liwa AFB",
28229
28640
  ["Qeshm_Island"]="Qeshm Island",
28230
- ["Ras_Al_Khaimah"]="Ras Al Khaimah Intl",
28231
- ["Sas_Al_Nakheel_Airport"]="Sas Al Nakheel",
28641
+ ["Quasoura_airport"]="Quasoura_airport",
28642
+ ["Ras_Al_Khaimah_Intl"]="Ras Al Khaimah Intl",
28643
+ ["Sas_Al_Nakheel"]="Sas Al Nakheel",
28232
28644
  ["Sharjah_Intl"]="Sharjah Intl",
28233
- ["Shiraz_International_Airport"]="Shiraz Intl",
28645
+ ["Shiraz_Intl"]="Shiraz Intl",
28234
28646
  ["Sir_Abu_Nuayr"]="Sir Abu Nuayr",
28235
28647
  ["Sirri_Island"]="Sirri Island",
28236
28648
  ["Tunb_Island_AFB"]="Tunb Island AFB",
@@ -28238,156 +28650,163 @@ AIRBASE.PersianGulf={
28238
28650
  }
28239
28651
  AIRBASE.TheChannel={
28240
28652
  ["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
28653
  ["Biggin_Hill"]="Biggin Hill",
28654
+ ["Detling"]="Detling",
28655
+ ["Dunkirk_Mardyck"]="Dunkirk Mardyck",
28250
28656
  ["Eastchurch"]="Eastchurch",
28657
+ ["Hawkinge"]="Hawkinge",
28251
28658
  ["Headcorn"]="Headcorn",
28659
+ ["High_Halden"]="High Halden",
28660
+ ["Lympne"]="Lympne",
28661
+ ["Manston"]="Manston",
28662
+ ["Merville_Calonne"]="Merville Calonne",
28663
+ ["Saint_Omer_Longuenesse"]="Saint Omer Longuenesse",
28252
28664
  }
28253
28665
  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",
28666
+ ["Abu_al_Duhur"]="Abu al-Duhur",
28667
+ ["Adana_Sakirpasa"]="Adana Sakirpasa",
28668
+ ["Akrotiri"]="Akrotiri",
28266
28669
  ["Al_Dumayr"]="Al-Dumayr",
28670
+ ["Al_Qusayr"]="Al Qusayr",
28671
+ ["Aleppo"]="Aleppo",
28672
+ ["Amman"]="Amman",
28673
+ ["An_Nasiriyah"]="An Nasiriyah",
28674
+ ["At_Tanf"]="At Tanf",
28675
+ ["Bassel_Al_Assad"]="Bassel Al-Assad",
28676
+ ["Beirut_Rafic_Hariri"]="Beirut-Rafic Hariri",
28677
+ ["Damascus"]="Damascus",
28678
+ ["Deir_ez_Zor"]="Deir ez-Zor",
28679
+ ["Ercan"]="Ercan",
28680
+ ["Eyn_Shemer"]="Eyn Shemer",
28681
+ ["Gaziantep"]="Gaziantep",
28267
28682
  ["Gazipasa"]="Gazipasa",
28268
- ["Hatay"]="Hatay",
28269
- ["Pinarbashi"]="Pinarbashi",
28270
- ["Paphos"]="Paphos",
28271
- ["Kingsfield"]="Kingsfield",
28272
- ["Thalah"]="Tha'lah",
28683
+ ["Gecitkale"]="Gecitkale",
28684
+ ["H3"]="H3",
28685
+ ["H3_Northwest"]="H3 Northwest",
28686
+ ["H3_Southwest"]="H3 Southwest",
28687
+ ["H4"]="H4",
28273
28688
  ["Haifa"]="Haifa",
28689
+ ["Hama"]="Hama",
28690
+ ["Hatay"]="Hatay",
28691
+ ["Herzliya"]="Herzliya",
28692
+ ["Incirlik"]="Incirlik",
28693
+ ["Jirah"]="Jirah",
28274
28694
  ["Khalkhalah"]="Khalkhalah",
28275
- ["Megiddo"]="Megiddo",
28695
+ ["Kharab_Ishk"]="Kharab Ishk",
28696
+ ["King_Abdullah_II"]="King Abdullah II",
28697
+ ["King_Hussein_Air_College"]="King Hussein Air College",
28698
+ ["Kingsfield"]="Kingsfield",
28699
+ ["Kiryat_Shmona"]="Kiryat Shmona",
28700
+ ["Kuweires"]="Kuweires",
28276
28701
  ["Lakatamia"]="Lakatamia",
28277
- ["Rayak"]="Rayak",
28278
28702
  ["Larnaca"]="Larnaca",
28703
+ ["Marj_Ruhayyil"]="Marj Ruhayyil",
28704
+ ["Marj_as_Sultan_North"]="Marj as Sultan North",
28705
+ ["Marj_as_Sultan_South"]="Marj as Sultan South",
28706
+ ["Megiddo"]="Megiddo",
28279
28707
  ["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
28708
  ["Minakh"]="Minakh",
28295
- ["Adana_Sakirpasa"]="Adana Sakirpasa",
28709
+ ["Muwaffaq_Salti"]="Muwaffaq Salti",
28710
+ ["Naqoura"]="Naqoura",
28711
+ ["Nicosia"]="Nicosia",
28296
28712
  ["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",
28713
+ ["Paphos"]="Paphos",
28714
+ ["Pinarbashi"]="Pinarbashi",
28715
+ ["Prince_Hassan"]="Prince Hassan",
28716
+ ["Qabr_as_Sitt"]="Qabr as Sitt",
28717
+ ["Ramat_David"]="Ramat David",
28718
+ ["Rayak"]="Rayak",
28719
+ ["Rene_Mouawad"]="Rene Mouawad",
28720
+ ["Rosh_Pina"]="Rosh Pina",
28309
28721
  ["Ruwayshid"]="Ruwayshid",
28310
28722
  ["Sanliurfa"]="Sanliurfa",
28723
+ ["Sayqal"]="Sayqal",
28724
+ ["Shayrat"]="Shayrat",
28725
+ ["Tabqa"]="Tabqa",
28726
+ ["Taftanaz"]="Taftanaz",
28311
28727
  ["Tal_Siman"]="Tal Siman",
28312
- ["Deir_ez_Zor"]="Deir ez-Zor",
28728
+ ["Tha_lah"]="Tha'lah",
28729
+ ["Tiyas"]="Tiyas",
28730
+ ["Wujah_Al_Hajar"]="Wujah Al Hajar",
28313
28731
  }
28314
28732
  AIRBASE.MarianaIslands={
28315
- ["Rota_Intl"]="Rota Intl",
28316
28733
  ["Andersen_AFB"]="Andersen AFB",
28317
28734
  ["Antonio_B_Won_Pat_Intl"]="Antonio B. Won Pat Intl",
28318
- ["Saipan_Intl"]="Saipan Intl",
28319
- ["Tinian_Intl"]="Tinian Intl",
28735
+ ["North_West_Field"]="North West Field",
28320
28736
  ["Olf_Orote"]="Olf Orote",
28321
28737
  ["Pagan_Airstrip"]="Pagan Airstrip",
28322
- ["North_West_Field"]="North West Field",
28738
+ ["Rota_Intl"]="Rota Intl",
28739
+ ["Saipan_Intl"]="Saipan Intl",
28740
+ ["Tinian_Intl"]="Tinian Intl",
28323
28741
  }
28324
28742
  AIRBASE.SouthAtlantic={
28325
- ["Port_Stanley"]="Port Stanley",
28743
+ ["Almirante_Schroeders"]="Almirante Schroeders",
28744
+ ["Caleta_Tortel"]="Caleta Tortel",
28745
+ ["Comandante_Luis_Piedrabuena"]="Comandante Luis Piedrabuena",
28746
+ ["Cullen"]="Cullen",
28747
+ ["El_Calafate"]="El Calafate",
28748
+ ["Franco_Bianco"]="Franco Bianco",
28749
+ ["Gobernador_Gregores"]="Gobernador Gregores",
28750
+ ["Goose_Green"]="Goose Green",
28751
+ ["Gull_Point"]="Gull Point",
28752
+ ["Hipico_Flying_Club"]="Hipico Flying Club",
28326
28753
  ["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",
28754
+ ["O_Higgins"]="O'Higgins",
28333
28755
  ["Pampa_Guanaco"]="Pampa Guanaco",
28334
- ["San_Julian"]="San Julian",
28335
- ["Puerto_Williams"]="Puerto Williams",
28756
+ ["Port_Stanley"]="Port Stanley",
28757
+ ["Porvenir"]="Porvenir",
28336
28758
  ["Puerto_Natales"]="Puerto Natales",
28337
- ["El_Calafate"]="El Calafate",
28338
28759
  ["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",
28760
+ ["Puerto_Williams"]="Puerto Williams",
28761
+ ["Punta_Arenas"]="Punta Arenas",
28344
28762
  ["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",
28763
+ ["Rio_Gallegos"]="Rio Gallegos",
28764
+ ["Rio_Grande"]="Rio Grande",
28765
+ ["Rio_Turbio"]="Rio Turbio",
28766
+ ["San_Carlos_FOB"]="San Carlos FOB",
28767
+ ["San_Julian"]="San Julian",
28768
+ ["Tolhuin"]="Tolhuin",
28769
+ ["Ushuaia"]="Ushuaia",
28770
+ ["Ushuaia_Helo_Port"]="Ushuaia Helo Port",
28353
28771
  }
28354
28772
  AIRBASE.Sinai={
28355
- ["Hatzerim"]="Hatzerim",
28773
+ ["Abu_Rudeis"]="Abu Rudeis",
28356
28774
  ["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
28775
  ["Al_Ismailiyah"]="Al Ismailiyah",
28776
+ ["Al_Mansurah"]="Al Mansurah",
28364
28777
  ["As_Salihiyah"]="As Salihiyah",
28365
- ["Fayed"]="Fayed",
28778
+ ["AzZaqaziq"]="AzZaqaziq",
28779
+ ["Baluza"]="Baluza",
28780
+ ["Ben_Gurion"]="Ben-Gurion",
28366
28781
  ["Bilbeis_Air_Base"]="Bilbeis Air Base",
28367
- ["Ramon_Airbase"]="Ramon Airbase",
28368
- ["Kibrit_Air_Base"]="Kibrit Air Base",
28782
+ ["Bir_Hasanah"]="Bir Hasanah",
28783
+ ["Cairo_International_Airport"]="Cairo International Airport",
28784
+ ["Cairo_West"]="Cairo West",
28785
+ ["Difarsuwar_Airfield"]="Difarsuwar Airfield",
28369
28786
  ["El_Arish"]="El Arish",
28370
- ["Ovda"]="Ovda",
28787
+ ["El_Gora"]="El Gora",
28788
+ ["Fayed"]="Fayed",
28789
+ ["Hatzerim"]="Hatzerim",
28790
+ ["Hatzor"]="Hatzor",
28791
+ ["Inshas_Airbase"]="Inshas Airbase",
28792
+ ["Kedem"]="Kedem",
28793
+ ["Kibrit_Air_Base"]="Kibrit Air Base",
28371
28794
  ["Melez"]="Melez",
28372
- ["Al_Mansurah"]="Al Mansurah",
28795
+ ["Nevatim"]="Nevatim",
28796
+ ["Ovda"]="Ovda",
28373
28797
  ["Palmahim"]="Palmahim",
28374
- ["Baluza"]="Baluza",
28375
- ["El_Gora"]="El Gora",
28376
- ["Difarsuwar_Airfield"]="Difarsuwar Airfield",
28377
- ["Wadi_al_Jandali"]="Wadi al Jandali",
28798
+ ["Ramon_Airbase"]="Ramon Airbase",
28799
+ ["Sde_Dov"]="Sde Dov",
28378
28800
  ["St_Catherine"]="St Catherine",
28379
28801
  ["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",
28802
+ ["Wadi_al_Jandali"]="Wadi al Jandali",
28385
28803
  }
28386
28804
  AIRBASE.TerminalType={
28387
28805
  Runway=16,
28388
28806
  HelicopterOnly=40,
28389
28807
  Shelter=68,
28390
28808
  OpenMed=72,
28809
+ SmallSizeFighter=100,
28391
28810
  OpenBig=104,
28392
28811
  OpenMedOrBig=176,
28393
28812
  HelicopterUsable=216,
@@ -28946,7 +29365,7 @@ if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.Op
28946
29365
  match=true
28947
29366
  end
28948
29367
  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
29368
+ 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
29369
  match=true
28951
29370
  end
28952
29371
  end
@@ -29730,6 +30149,9 @@ self.desc=WeaponObject:getDesc()
29730
30149
  self.category=self.desc.category
29731
30150
  if self:IsMissile()and self.desc.missileCategory then
29732
30151
  self.categoryMissile=self.desc.missileCategory
30152
+ if self.desc.guidance then
30153
+ self.guidance=self.desc.guidance
30154
+ end
29733
30155
  end
29734
30156
  self.typeName=WeaponObject:getTypeName()or"Unknown Type"
29735
30157
  self.name=WeaponObject:getName()
@@ -29944,6 +30366,15 @@ end
29944
30366
  function WEAPON:IsTorpedo()
29945
30367
  return self.category==Weapon.Category.TORPEDO
29946
30368
  end
30369
+ function WEAPON:IsFoxOne()
30370
+ return self.guidance==Weapon.GuidanceType.RADAR_SEMI_ACTIVE
30371
+ end
30372
+ function WEAPON:IsFoxTwo()
30373
+ return self.guidance==Weapon.GuidanceType.IR
30374
+ end
30375
+ function WEAPON:IsFoxThree()
30376
+ return self.guidance==Weapon.GuidanceType.RADAR_ACTIVE
30377
+ end
29947
30378
  function WEAPON:Destroy(Delay)
29948
30379
  if Delay and Delay>0 then
29949
30380
  self:ScheduleOnce(Delay,WEAPON.Destroy,self,0)
@@ -30409,7 +30840,7 @@ end
30409
30840
  function NET.Lua2Json(Lua)
30410
30841
  return net.lua2json(Lua)
30411
30842
  end
30412
- function NET.Lua2Json(Json)
30843
+ function NET.Json2Lua(Json)
30413
30844
  return net.json2lua(Json)
30414
30845
  end
30415
30846
  function NET:DoStringIn(State,DoString)
@@ -31959,7 +32390,7 @@ ClassName="SCORING",
31959
32390
  ClassID=0,
31960
32391
  Players={},
31961
32392
  AutoSave=true,
31962
- version="1.17.1"
32393
+ version="1.18.4"
31963
32394
  }
31964
32395
  local _SCORINGCoalition={
31965
32396
  [1]="Red",
@@ -31972,7 +32403,7 @@ local _SCORINGCategory={
31972
32403
  [Unit.Category.SHIP]="Ship",
31973
32404
  [Unit.Category.STRUCTURE]="Structure",
31974
32405
  }
31975
- function SCORING:New(GameName)
32406
+ function SCORING:New(GameName,SavePath,AutoSave)
31976
32407
  local self=BASE:Inherit(self,BASE:New())
31977
32408
  if GameName then
31978
32409
  self.GameName=GameName
@@ -32005,7 +32436,8 @@ self:_AddPlayerFromUnit(PlayerUnit)
32005
32436
  self:SetScoringMenu(PlayerUnit:GetGroup())
32006
32437
  end
32007
32438
  end)
32008
- self.AutoSave=true
32439
+ self.AutoSavePath=SavePath
32440
+ self.AutoSave=AutoSave or true
32009
32441
  self:OpenCSV(GameName)
32010
32442
  return self
32011
32443
  end
@@ -32049,6 +32481,21 @@ self.ScoringObjects[UnitName]=Score
32049
32481
  end
32050
32482
  return self
32051
32483
  end
32484
+ function SCORING:AddScoreSetGroup(Set,Score)
32485
+ local set=Set:GetSetObjects()
32486
+ for _,_group in pairs(set)do
32487
+ if _group and _group:IsAlive()then
32488
+ self:AddScoreGroup(_group,Score)
32489
+ end
32490
+ end
32491
+ local function AddScore(group)
32492
+ self:AddScoreGroup(group,Score)
32493
+ end
32494
+ function Set:OnAfterAdded(From,Event,To,ObjectName,Object)
32495
+ AddScore(Object)
32496
+ end
32497
+ return self
32498
+ end
32052
32499
  function SCORING:AddZoneScore(ScoreZone,Score)
32053
32500
  local ZoneName=ScoreZone:GetName()
32054
32501
  self.ScoringZones[ZoneName]={}
@@ -32380,7 +32827,7 @@ PlayerHit.TimeStamp=PlayerHit.TimeStamp or 0
32380
32827
  PlayerHit.UNIT=PlayerHit.UNIT or TargetUNIT
32381
32828
  if PlayerHit.UNIT.ThreatType==nil then
32382
32829
  PlayerHit.ThreatLevel,PlayerHit.ThreatType=PlayerHit.UNIT:GetThreatLevel()
32383
- if PlayerHit.ThreatType==nil then
32830
+ if PlayerHit.ThreatType==nil or PlayerHit.ThreatType==""then
32384
32831
  PlayerHit.ThreatLevel=1
32385
32832
  PlayerHit.ThreatType="Unknown"
32386
32833
  end
@@ -32572,16 +33019,15 @@ self:F({ThreatLevel=ThreatPenalty,ThreatLevelTarget=ThreatLevelTarget,ThreatType
32572
33019
  Player.Penalty=Player.Penalty+ThreatPenalty
32573
33020
  TargetDestroy.Penalty=TargetDestroy.Penalty+ThreatPenalty
32574
33021
  TargetDestroy.PenaltyDestroy=TargetDestroy.PenaltyDestroy+1
32575
- self:OnKillPvP(Player,TargetPlayerName,true,TargetThreatLevel,Player.ThreatLevel,ThreatPenalty)
32576
33022
  if Player.HitPlayers[TargetPlayerName]then
32577
- self:OnKillPvP(Player,TargetPlayerName,true)
33023
+ self:OnKillPvP(PlayerName,TargetPlayerName,true)
32578
33024
  MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed friendly player '"..TargetPlayerName.."' "..TargetUnitCategory.." ( "..ThreatTypeTarget.." ) "..
32579
33025
  "Penalty: -"..ThreatPenalty.." = "..Player.Score-Player.Penalty,
32580
33026
  MESSAGE.Type.Information)
32581
33027
  :ToAllIf(self:IfMessagesDestroy()and self:IfMessagesToAll())
32582
33028
  :ToCoalitionIf(InitCoalition,self:IfMessagesDestroy()and self:IfMessagesToCoalition())
32583
33029
  else
32584
- self:OnKillPvE(Player,TargetUnitName,true,TargetThreatLevel,Player.ThreatLevel,ThreatPenalty)
33030
+ self:OnKillPvE(PlayerName,TargetUnitName,true,TargetThreatLevel,Player.ThreatLevel,ThreatPenalty)
32585
33031
  MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed friendly target "..TargetUnitCategory.." ( "..ThreatTypeTarget.." ) "..
32586
33032
  "Penalty: -"..ThreatPenalty.." = "..Player.Score-Player.Penalty,
32587
33033
  MESSAGE.Type.Information)
@@ -32605,14 +33051,14 @@ Player.PlayerKills=Player.PlayerKills+1
32605
33051
  else
32606
33052
  Player.PlayerKills=1
32607
33053
  end
32608
- self:OnKillPvP(Player,TargetPlayerName,false,TargetThreatLevel,Player.ThreatLevel,ThreatScore)
33054
+ self:OnKillPvP(PlayerName,TargetPlayerName,false,TargetThreatLevel,Player.ThreatLevel,ThreatScore)
32609
33055
  MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed enemy player '"..TargetPlayerName.."' "..TargetUnitCategory.." ( "..ThreatTypeTarget.." ) "..
32610
33056
  "Score: +"..ThreatScore.." = "..Player.Score-Player.Penalty,
32611
33057
  MESSAGE.Type.Information)
32612
33058
  :ToAllIf(self:IfMessagesDestroy()and self:IfMessagesToAll())
32613
33059
  :ToCoalitionIf(InitCoalition,self:IfMessagesDestroy()and self:IfMessagesToCoalition())
32614
33060
  else
32615
- self:OnKillPvE(Player,TargetUnitName,false,TargetThreatLevel,Player.ThreatLevel,ThreatScore)
33061
+ self:OnKillPvE(PlayerName,TargetUnitName,false,TargetThreatLevel,Player.ThreatLevel,ThreatScore)
32616
33062
  MESSAGE:NewType(self.DisplayMessagePrefix.."Player '"..PlayerName.."' destroyed enemy "..TargetUnitCategory.." ( "..ThreatTypeTarget.." ) "..
32617
33063
  "Score: +"..ThreatScore.." = "..Player.Score-Player.Penalty,
32618
33064
  MESSAGE.Type.Information)
@@ -32954,10 +33400,11 @@ end
32954
33400
  end
32955
33401
  function SCORING:OpenCSV(ScoringCSV)
32956
33402
  self:F(ScoringCSV)
32957
- if lfs and io and os and self.AutoSave then
33403
+ if lfs and io and os and self.AutoSave==true then
32958
33404
  if ScoringCSV then
32959
33405
  self.ScoringCSV=ScoringCSV
32960
- local fdir=lfs.writedir()..[[Logs\]]..self.ScoringCSV.." "..os.date("%Y-%m-%d %H-%M-%S")..".csv"
33406
+ local path=self.AutoSavePath or lfs.writedir()..[[Logs\]]
33407
+ local fdir=path..self.ScoringCSV.." "..os.date("%Y-%m-%d %H-%M-%S")..".csv"
32961
33408
  self.CSVFile,self.err=io.open(fdir,"w+")
32962
33409
  if not self.CSVFile then
32963
33410
  error("Error: Cannot open CSV file in "..lfs.writedir())
@@ -33036,9 +33483,9 @@ function SCORING:SwitchAutoSave(OnOff)
33036
33483
  self.AutoSave=OnOff
33037
33484
  return self
33038
33485
  end
33039
- function SCORING:OnKillPvP(Player,TargetPlayerName,IsTeamKill,TargetThreatLevel,PlayerThreatLevel,Score)
33486
+ function SCORING:OnKillPvP(PlayerName,TargetPlayerName,IsTeamKill,TargetThreatLevel,PlayerThreatLevel,Score)
33040
33487
  end
33041
- function SCORING:OnKillPvE(Player,TargetUnitName,IsTeamKill,TargetThreatLevel,PlayerThreatLevel,Score)
33488
+ function SCORING:OnKillPvE(PlayerName,TargetUnitName,IsTeamKill,TargetThreatLevel,PlayerThreatLevel,Score)
33042
33489
  end
33043
33490
  CLEANUP_AIRBASE={
33044
33491
  ClassName="CLEANUP_AIRBASE",
@@ -33528,7 +33975,6 @@ predpos:MarkToAll(string.format("height=%dm | heading=%d | velocity=%ddeg | Ropt
33528
33975
  targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true)
33529
33976
  end
33530
33977
  local seadset=SET_GROUP:New():FilterPrefixes(self.SEADGroupPrefixes):FilterZones({targetzone}):FilterOnce()
33531
- local tgtcoord=targetzone:GetRandomPointVec2()
33532
33978
  local tgtgrp=seadset:GetRandom()
33533
33979
  local _targetgroup=nil
33534
33980
  local _targetgroupname="none"
@@ -57204,7 +57650,7 @@ local rho=groovedata.Rho
57204
57650
  local lineupError=groovedata.LUE
57205
57651
  local glideslopeError=groovedata.GSE
57206
57652
  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
57653
+ 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
57654
  playerData.TIG0=timer.getTime()
57209
57655
  self:RadioTransmission(self.LSORadio,self.LSOCall.CALLTHEBALL,nil,nil,nil,true)
57210
57656
  playerData.Tlso=timer.getTime()
@@ -64426,6 +64872,8 @@ HasBeenDropped=false,
64426
64872
  PerCrateMass=0,
64427
64873
  Stock=nil,
64428
64874
  Mark=nil,
64875
+ DontShowInMenu=false,
64876
+ Location=nil,
64429
64877
  }
64430
64878
  CTLD_CARGO.Enum={
64431
64879
  VEHICLE="Vehicle",
@@ -64436,7 +64884,7 @@ REPAIR="Repair",
64436
64884
  ENGINEERS="Engineers",
64437
64885
  STATIC="Static",
64438
64886
  }
64439
- function CTLD_CARGO:New(ID,Name,Templates,Sorte,HasBeenMoved,LoadDirectly,CratesNeeded,Positionable,Dropped,PerCrateMass,Stock,Subcategory)
64887
+ function CTLD_CARGO:New(ID,Name,Templates,Sorte,HasBeenMoved,LoadDirectly,CratesNeeded,Positionable,Dropped,PerCrateMass,Stock,Subcategory,DontShowInMenu,Location)
64440
64888
  local self=BASE:Inherit(self,BASE:New())
64441
64889
  self:T({ID,Name,Templates,Sorte,HasBeenMoved,LoadDirectly,CratesNeeded,Positionable,Dropped})
64442
64890
  self.ID=ID or math.random(100000,1000000)
@@ -64452,8 +64900,16 @@ self.PerCrateMass=PerCrateMass or 0
64452
64900
  self.Stock=Stock or nil
64453
64901
  self.Mark=nil
64454
64902
  self.Subcategory=Subcategory or"Other"
64903
+ self.DontShowInMenu=DontShowInMenu or false
64904
+ if type(Location)=="string"then
64905
+ Location=ZONE:New(Location)
64906
+ end
64907
+ self.Location=Location
64455
64908
  return self
64456
64909
  end
64910
+ function CTLD_CARGO:GetLocation()
64911
+ return self.Location
64912
+ end
64457
64913
  function CTLD_CARGO:GetID()
64458
64914
  return self.ID
64459
64915
  end
@@ -64763,10 +65219,12 @@ CTLD.UnitTypeCapabilities={
64763
65219
  ["Mi-24V"]={type="Mi-24V",crates=true,troops=true,cratelimit=2,trooplimit=8,length=18,cargoweightlimit=700},
64764
65220
  ["Hercules"]={type="Hercules",crates=true,troops=true,cratelimit=7,trooplimit=64,length=25,cargoweightlimit=19000},
64765
65221
  ["UH-60L"]={type="UH-60L",crates=true,troops=true,cratelimit=2,trooplimit=20,length=16,cargoweightlimit=3500},
65222
+ ["MH-60R"]={type="MH-60R",crates=true,troops=true,cratelimit=2,trooplimit=20,length=16,cargoweightlimit=3500},
65223
+ ["SH-60B"]={type="SH-60B",crates=true,troops=true,cratelimit=2,trooplimit=20,length=16,cargoweightlimit=3500},
64766
65224
  ["AH-64D_BLK_II"]={type="AH-64D_BLK_II",crates=false,troops=true,cratelimit=0,trooplimit=2,length=17,cargoweightlimit=200},
64767
65225
  ["Bronco-OV-10A"]={type="Bronco-OV-10A",crates=false,troops=true,cratelimit=0,trooplimit=5,length=13,cargoweightlimit=1450},
64768
65226
  }
64769
- CTLD.version="1.0.45"
65227
+ CTLD.version="1.0.51"
64770
65228
  function CTLD:New(Coalition,Prefixes,Alias)
64771
65229
  local self=BASE:Inherit(self,FSM:New())
64772
65230
  BASE:T({Coalition,Prefixes,Alias})
@@ -65269,7 +65727,9 @@ local distancekeys={}
65269
65727
  local extractdistance=self.CrateDistance*self.ExtractFactor
65270
65728
  for k,v in pairs(self.DroppedTroops)do
65271
65729
  local distance=self:_GetDistance(v:GetCoordinate(),unitcoord)
65272
- if distance<=extractdistance and distance~=-1 then
65730
+ local TNow=timer.getTime()
65731
+ local vtime=v.ExtractTime or TNow-310
65732
+ if distance<=extractdistance and distance~=-1 and(TNow-vtime>300)then
65273
65733
  nearestGroup=v
65274
65734
  nearestGroupIndex=k
65275
65735
  nearestDistance=distance
@@ -65312,22 +65772,36 @@ loaded.Cargo={}
65312
65772
  end
65313
65773
  if troopsize+numberonboard>trooplimit then
65314
65774
  self:_SendMessage("Sorry, we\'re crammed already!",10,false,Group)
65775
+ nearestGroup.ExtractTime=0
65315
65776
  else
65316
65777
  self.CargoCounter=self.CargoCounter+1
65778
+ nearestGroup.ExtractTime=timer.getTime()
65317
65779
  local loadcargotype=CTLD_CARGO:New(self.CargoCounter,Cargotype.Name,Cargotype.Templates,Cargotype.CargoType,true,true,Cargotype.CratesNeeded,nil,nil,Cargotype.PerCrateMass)
65318
65780
  self:T({cargotype=loadcargotype})
65781
+ local running=math.floor(nearestDistance/4)+10
65319
65782
  loaded.Troopsloaded=loaded.Troopsloaded+troopsize
65320
65783
  table.insert(loaded.Cargo,loadcargotype)
65321
65784
  self.Loaded_Cargo[unitname]=loaded
65322
- self:_SendMessage("Troops boarded!",10,false,Group)
65785
+ self:ScheduleOnce(running,self._SendMessage,self,"Troops boarded!",10,false,Group)
65786
+ self:_SendMessage("Troops boarding!",10,false,Group)
65323
65787
  self:_UpdateUnitCargoMass(Unit)
65324
- self:__TroopsExtracted(1,Group,Unit,nearestGroup)
65788
+ self:__TroopsExtracted(running,Group,Unit,nearestGroup)
65789
+ local coord=Unit:GetCoordinate()or Group:GetCoordinate()
65790
+ local Point
65791
+ if coord then
65792
+ local heading=unit:GetHeading()or 0
65793
+ local Angle=math.floor((heading+160)%360)
65794
+ Point=coord:Translate(8,Angle):GetVec2()
65795
+ if Point then
65796
+ nearestGroup:RouteToVec2(Point,4)
65797
+ end
65798
+ end
65325
65799
  if type(Cargotype.Templates)=="table"and Cargotype.Templates[2]then
65326
65800
  for _,_key in pairs(Cargotype.Templates)do
65327
65801
  table.insert(secondarygroups,_key)
65328
65802
  end
65329
65803
  end
65330
- nearestGroup:Destroy(false)
65804
+ nearestGroup:Destroy(false,running)
65331
65805
  end
65332
65806
  end
65333
65807
  end
@@ -65336,7 +65810,7 @@ for _,_group in pairs(nearestList)do
65336
65810
  if _group and _group:IsAlive()then
65337
65811
  local groupname=string.match(_group:GetName(),"(.+)-(.+)$")
65338
65812
  if _name==groupname then
65339
- _group:Destroy(false)
65813
+ _group:Destroy(false,15)
65340
65814
  end
65341
65815
  end
65342
65816
  end
@@ -65378,6 +65852,16 @@ if not inzone then
65378
65852
  self:_SendMessage("You are not close enough to a logistics zone!",10,false,Group)
65379
65853
  if not self.debug then return self end
65380
65854
  end
65855
+ local location=Cargo:GetLocation()
65856
+ if location then
65857
+ local unitcoord=Unit:GetCoordinate()or Group:GetCoordinate()
65858
+ if unitcoord then
65859
+ if not location:IsCoordinateInZone(unitcoord)then
65860
+ self:_SendMessage("The requested cargo is not available in this zone!",10,false,Group)
65861
+ if not self.debug then return self end
65862
+ end
65863
+ end
65864
+ end
65381
65865
  local capabilities=self:_GetUnitCapabilities(Unit)
65382
65866
  local canloadcratesno=capabilities.cratelimit
65383
65867
  local loaddist=self.CrateDistance or 35
@@ -65928,9 +66412,9 @@ end
65928
66412
  function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
65929
66413
  local Positions={}
65930
66414
  local template=_DATABASE:GetGroupTemplate(Template)
65931
- UTILS.PrintTableToLog(template)
65932
66415
  local numbertroops=#template.units
65933
- local newcenter=Coordinate:Translate(Radius,((Heading+270)%360))
66416
+ local slightshift=math.abs(math.random(0,200)/100)
66417
+ local newcenter=Coordinate:Translate(Radius+slightshift,((Heading+270)%360))
65934
66418
  for i=1,360,math.floor(360/numbertroops)do
65935
66419
  local phead=((Heading+270+i)%360)
65936
66420
  local post=newcenter:Translate(Radius,phead)
@@ -65942,7 +66426,6 @@ heading=phead,
65942
66426
  }
65943
66427
  table.insert(Positions,p1t)
65944
66428
  end
65945
- UTILS.PrintTableToLog(Positions)
65946
66429
  return Positions
65947
66430
  end
65948
66431
  function CTLD:_UnloadTroops(Group,Unit)
@@ -66479,16 +66962,22 @@ end
66479
66962
  for _,_entry in pairs(self.Cargo_Troops)do
66480
66963
  local entry=_entry
66481
66964
  local subcat=entry.Subcategory
66965
+ local noshow=entry.DontShowInMenu
66966
+ if not noshow then
66482
66967
  menucount=menucount+1
66483
66968
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,entry.Name,subcatmenus[subcat],self._LoadTroops,self,_group,_unit,entry)
66484
66969
  end
66970
+ end
66485
66971
  else
66486
66972
  for _,_entry in pairs(self.Cargo_Troops)do
66487
66973
  local entry=_entry
66974
+ local noshow=entry.DontShowInMenu
66975
+ if not noshow then
66488
66976
  menucount=menucount+1
66489
66977
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,entry.Name,troopsmenu,self._LoadTroops,self,_group,_unit,entry)
66490
66978
  end
66491
66979
  end
66980
+ end
66492
66981
  local unloadmenu1=MENU_GROUP_COMMAND:New(_group,"Drop troops",toptroops,self._UnloadTroops,self,_group,_unit):Refresh()
66493
66982
  local extractMenu1=MENU_GROUP_COMMAND:New(_group,"Extract troops",toptroops,self._ExtractTroops,self,_group,_unit):Refresh()
66494
66983
  end
@@ -66505,33 +66994,61 @@ end
66505
66994
  for _,_entry in pairs(self.Cargo_Crates)do
66506
66995
  local entry=_entry
66507
66996
  local subcat=entry.Subcategory
66997
+ local noshow=entry.DontShowInMenu
66998
+ local zone=entry.Location
66999
+ if not noshow then
66508
67000
  menucount=menucount+1
66509
67001
  local menutext=string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
67002
+ if zone then
67003
+ menutext=string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
67004
+ end
66510
67005
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates,self,_group,_unit,entry)
66511
67006
  end
67007
+ end
66512
67008
  for _,_entry in pairs(self.Cargo_Statics)do
66513
67009
  local entry=_entry
66514
67010
  local subcat=entry.Subcategory
67011
+ local noshow=entry.DontShowInMenu
67012
+ local zone=entry.Location
67013
+ if not noshow then
66515
67014
  menucount=menucount+1
66516
67015
  local menutext=string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
67016
+ if zone then
67017
+ menutext=string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
67018
+ end
66517
67019
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,menutext,subcatmenus[subcat],self._GetCrates,self,_group,_unit,entry)
66518
67020
  end
67021
+ end
66519
67022
  else
66520
67023
  for _,_entry in pairs(self.Cargo_Crates)do
66521
67024
  local entry=_entry
67025
+ local noshow=entry.DontShowInMenu
67026
+ local zone=entry.Location
67027
+ if not noshow then
66522
67028
  menucount=menucount+1
66523
67029
  local menutext=string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
67030
+ if zone then
67031
+ menutext=string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
67032
+ end
66524
67033
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates,self,_group,_unit,entry)
66525
67034
  end
67035
+ end
66526
67036
  for _,_entry in pairs(self.Cargo_Statics)do
66527
67037
  local entry=_entry
67038
+ local noshow=entry.DontShowInMenu
67039
+ local zone=entry.Location
67040
+ if not noshow then
66528
67041
  menucount=menucount+1
66529
67042
  local menutext=string.format("Crate %s (%dkg)",entry.Name,entry.PerCrateMass or 0)
67043
+ if zone then
67044
+ menutext=string.format("Crate %s (%dkg)[R]",entry.Name,entry.PerCrateMass or 0)
67045
+ end
66530
67046
  menus[menucount]=MENU_GROUP_COMMAND:New(_group,menutext,cratesmenu,self._GetCrates,self,_group,_unit,entry)
66531
67047
  end
66532
67048
  end
67049
+ end
66533
67050
  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)
67051
+ local removecrates=MENU_GROUP_COMMAND:New(_group,"Remove crates nearby",removecratesmenu,self._RemoveCratesNearby,self,_group,_unit)
66535
67052
  local unloadmenu=MENU_GROUP_COMMAND:New(_group,"Drop crates",topcrates,self._UnloadCrates,self,_group,_unit)
66536
67053
  if not self.nobuildmenu then
66537
67054
  local buildmenu=MENU_GROUP_COMMAND:New(_group,"Build crates",topcrates,self._BuildCrates,self,_group,_unit)
@@ -66580,23 +67097,23 @@ local cargo=CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,true,NoTr
66580
67097
  table.insert(self.Cargo_Troops,cargo)
66581
67098
  return self
66582
67099
  end
66583
- function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory)
67100
+ function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
66584
67101
  self:T(self.lid.." AddCratesCargo")
66585
67102
  if not self:_CheckTemplates(Templates)then
66586
67103
  self:E(self.lid.."Crates Cargo for "..Name.." has missing template(s)!")
66587
67104
  return self
66588
67105
  end
66589
67106
  self.CargoCounter=self.CargoCounter+1
66590
- local cargo=CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory)
67107
+ local cargo=CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
66591
67108
  table.insert(self.Cargo_Crates,cargo)
66592
67109
  return self
66593
67110
  end
66594
- function CTLD:AddStaticsCargo(Name,Mass,Stock,SubCategory)
67111
+ function CTLD:AddStaticsCargo(Name,Mass,Stock,SubCategory,DontShowInMenu,Location)
66595
67112
  self:T(self.lid.." AddStaticsCargo")
66596
67113
  self.CargoCounter=self.CargoCounter+1
66597
67114
  local type=CTLD_CARGO.Enum.STATIC
66598
67115
  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)
67116
+ local cargo=CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,Stock,SubCategory,DontShowInMenu,Location)
66600
67117
  table.insert(self.Cargo_Statics,cargo)
66601
67118
  return self
66602
67119
  end
@@ -66608,14 +67125,14 @@ local template=STATIC:FindByName(Name,true):GetTypeName()
66608
67125
  local cargo=CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,1)
66609
67126
  return cargo
66610
67127
  end
66611
- function CTLD:AddCratesRepair(Name,Template,Type,NoCrates,PerCrateMass,Stock,SubCategory)
67128
+ function CTLD:AddCratesRepair(Name,Template,Type,NoCrates,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
66612
67129
  self:T(self.lid.." AddCratesRepair")
66613
67130
  if not self:_CheckTemplates(Template)then
66614
67131
  self:E(self.lid.."Repair Cargo for "..Name.." has a missing template!")
66615
67132
  return self
66616
67133
  end
66617
67134
  self.CargoCounter=self.CargoCounter+1
66618
- local cargo=CTLD_CARGO:New(self.CargoCounter,Name,Template,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory)
67135
+ local cargo=CTLD_CARGO:New(self.CargoCounter,Name,Template,Type,false,false,NoCrates,nil,nil,PerCrateMass,Stock,SubCategory,DontShowInMenu,Location)
66619
67136
  table.insert(self.Cargo_Crates,cargo)
66620
67137
  return self
66621
67138
  end
@@ -68437,7 +68954,8 @@ CSAR.AircraftType["Bell-47"]=2
68437
68954
  CSAR.AircraftType["UH-60L"]=10
68438
68955
  CSAR.AircraftType["AH-64D_BLK_II"]=2
68439
68956
  CSAR.AircraftType["Bronco-OV-10A"]=2
68440
- CSAR.version="1.0.19"
68957
+ CSAR.AircraftType["MH-60R"]=10
68958
+ CSAR.version="1.0.21"
68441
68959
  function CSAR:New(Coalition,Template,Alias)
68442
68960
  local self=BASE:Inherit(self,FSM:New())
68443
68961
  BASE:T({Coalition,Template,Alias})
@@ -68549,7 +69067,7 @@ self.SRSchannel=300
68549
69067
  self.SRSModulation=radio.modulation.AM
68550
69068
  self.SRSport=5002
68551
69069
  self.SRSCulture="en-GB"
68552
- self.SRSVoice=nil
69070
+ self.SRSVoice=MSRS.Voices.Google.Standard.en_GB_Standard_B
68553
69071
  self.SRSGPathToCredentials=nil
68554
69072
  self.SRSVolume=1.0
68555
69073
  self.SRSGender="male"
@@ -68925,7 +69443,7 @@ return self
68925
69443
  end
68926
69444
  if _place:GetCoalition()==self.coalition or _place:GetCoalition()==coalition.side.NEUTRAL then
68927
69445
  self:__Landed(2,_event.IniUnitName,_place)
68928
- self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true)
69446
+ self:_ScheduledSARFlight(_event.IniUnitName,_event.IniGroupName,true,true)
68929
69447
  else
68930
69448
  self:T(string.format("Airfield %d, Unit %d",_place:GetCoalition(),_unit:GetCoalition()))
68931
69449
  end
@@ -69148,6 +69666,7 @@ local _found,_pilotable=self:_CheckNameInDownedPilots(_woundedGroupName)
69148
69666
  local _pilotName=_pilotable.desc
69149
69667
  local _reset=true
69150
69668
  if(_distance<500)then
69669
+ self:T(self.lid.."[Pickup Debug] Helo closer than 500m: ".._lookupKeyHeli)
69151
69670
  if self.heliCloseMessage[_lookupKeyHeli]==nil then
69152
69671
  if self.autosmoke==true then
69153
69672
  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 +69675,15 @@ self:_DisplayMessageToSAR(_heliUnit,string.format("%s: %s. You\'re close now! La
69156
69675
  end
69157
69676
  self.heliCloseMessage[_lookupKeyHeli]=true
69158
69677
  end
69678
+ self:T(self.lid.."[Pickup Debug] Checking landed vs Hover for ".._lookupKeyHeli)
69159
69679
  if not _heliUnit:InAir()then
69680
+ self:T(self.lid.."[Pickup Debug] Helo landed: ".._lookupKeyHeli)
69160
69681
  if self.pilotRuntoExtractPoint==true then
69161
69682
  if(_distance<self.extractDistance)then
69162
69683
  local _time=self.landedStatus[_lookupKeyHeli]
69684
+ self:T(self.lid.."[Pickup Debug] Check pilot running or arrived ".._lookupKeyHeli)
69163
69685
  if _time==nil then
69686
+ self:T(self.lid.."[Pickup Debug] Pilot running not arrived yet ".._lookupKeyHeli)
69164
69687
  self.landedStatus[_lookupKeyHeli]=math.floor((_distance-self.loadDistance)/3.6)
69165
69688
  _time=self.landedStatus[_lookupKeyHeli]
69166
69689
  _woundedGroup:OptionAlarmStateGreen()
@@ -69170,11 +69693,15 @@ else
69170
69693
  _time=self.landedStatus[_lookupKeyHeli]-10
69171
69694
  self.landedStatus[_lookupKeyHeli]=_time
69172
69695
  end
69696
+ self:T(self.lid.."[Pickup Debug] Pilot close enough? ".._lookupKeyHeli)
69173
69697
  if _distance<self.loadDistance+5 or _distance<=13 then
69698
+ self:T(self.lid.."[Pickup Debug] Pilot close enough - YES ".._lookupKeyHeli)
69174
69699
  if self.pilotmustopendoors and(self:_IsLoadingDoorOpen(_heliName)==false)then
69175
69700
  self:_DisplayMessageToSAR(_heliUnit,"Open the door to let me in!",self.messageTime,true,true)
69701
+ self:T(self.lid.."[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
69176
69702
  return false
69177
69703
  else
69704
+ self:T(self.lid.."[Pickup Debug] Pick up Pilot ".._lookupKeyHeli)
69178
69705
  self.landedStatus[_lookupKeyHeli]=nil
69179
69706
  self:_PickupUnit(_heliUnit,_pilotName,_woundedGroup,_woundedGroupName)
69180
69707
  return true
@@ -69182,28 +69709,36 @@ end
69182
69709
  end
69183
69710
  end
69184
69711
  else
69712
+ self:T(self.lid.."[Pickup Debug] Helo landed, pilot NOT set to run to helo ".._lookupKeyHeli)
69185
69713
  if(_distance<self.loadDistance)then
69714
+ self:T(self.lid.."[Pickup Debug] Helo close enough, door check ".._lookupKeyHeli)
69186
69715
  if self.pilotmustopendoors and(self:_IsLoadingDoorOpen(_heliName)==false)then
69716
+ self:T(self.lid.."[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
69187
69717
  self:_DisplayMessageToSAR(_heliUnit,"Open the door to let me in!",self.messageTime,true,true)
69188
69718
  return false
69189
69719
  else
69720
+ self:T(self.lid.."[Pickup Debug] Pick up Pilot ".._lookupKeyHeli)
69190
69721
  self:_PickupUnit(_heliUnit,_pilotName,_woundedGroup,_woundedGroupName)
69191
69722
  return true
69192
69723
  end
69193
69724
  end
69194
69725
  end
69195
69726
  else
69727
+ self:T(self.lid.."[Pickup Debug] Helo hovering".._lookupKeyHeli)
69196
69728
  local _unitsInHelicopter=self:_PilotsOnboard(_heliName)
69197
69729
  local _maxUnits=self.AircraftType[_heliUnit:GetTypeName()]
69198
69730
  if _maxUnits==nil then
69199
69731
  _maxUnits=self.max_units
69200
69732
  end
69733
+ self:T(self.lid.."[Pickup Debug] Check capacity and close enough for winching ".._lookupKeyHeli)
69201
69734
  if _heliUnit:InAir()and _unitsInHelicopter+1<=_maxUnits then
69202
69735
  if _distance<self.rescuehoverdistance then
69736
+ self:T(self.lid.."[Pickup Debug] Helo hovering close enough ".._lookupKeyHeli)
69203
69737
  local leaderheight=_woundedLeader:GetHeight()
69204
69738
  if leaderheight<0 then leaderheight=0 end
69205
69739
  local _height=_heliUnit:GetHeight()-leaderheight
69206
69740
  if _height<=self.rescuehoverheight then
69741
+ self:T(self.lid.."[Pickup Debug] Helo hovering low enough ".._lookupKeyHeli)
69207
69742
  local _time=self.hoverStatus[_lookupKeyHeli]
69208
69743
  if _time==nil then
69209
69744
  self.hoverStatus[_lookupKeyHeli]=10
@@ -69212,21 +69747,28 @@ else
69212
69747
  _time=self.hoverStatus[_lookupKeyHeli]-10
69213
69748
  self.hoverStatus[_lookupKeyHeli]=_time
69214
69749
  end
69750
+ self:T(self.lid.."[Pickup Debug] Check hover timer ".._lookupKeyHeli)
69215
69751
  if _time>0 then
69752
+ self:T(self.lid.."[Pickup Debug] Helo hovering not long enough ".._lookupKeyHeli)
69216
69753
  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
69754
  else
69755
+ self:T(self.lid.."[Pickup Debug] Helo hovering long enough - door check ".._lookupKeyHeli)
69218
69756
  if self.pilotmustopendoors and(self:_IsLoadingDoorOpen(_heliName)==false)then
69219
69757
  self:_DisplayMessageToSAR(_heliUnit,"Open the door to let me in!",self.messageTime,true,true)
69758
+ self:T(self.lid.."[Pickup Debug] Door closed, try again next loop ".._lookupKeyHeli)
69220
69759
  return false
69221
69760
  else
69222
69761
  self.hoverStatus[_lookupKeyHeli]=nil
69223
69762
  self:_PickupUnit(_heliUnit,_pilotName,_woundedGroup,_woundedGroupName)
69763
+ self:T(self.lid.."[Pickup Debug] Pilot picked up ".._lookupKeyHeli)
69224
69764
  return true
69225
69765
  end
69226
69766
  end
69227
69767
  _reset=false
69228
69768
  else
69769
+ self:T(self.lid.."[Pickup Debug] Helo hovering too high ".._lookupKeyHeli)
69229
69770
  self:_DisplayMessageToSAR(_heliUnit,"Too high to winch ".._pilotName.." \nReduce height and hover for 10 seconds!",self.messageTime,true,true)
69771
+ self:T(self.lid.."[Pickup Debug] Hovering too high, try again next loop ".._lookupKeyHeli)
69230
69772
  return false
69231
69773
  end
69232
69774
  end
@@ -69242,7 +69784,7 @@ else
69242
69784
  return false
69243
69785
  end
69244
69786
  end
69245
- function CSAR:_ScheduledSARFlight(heliname,groupname,isairport)
69787
+ function CSAR:_ScheduledSARFlight(heliname,groupname,isairport,noreschedule)
69246
69788
  self:T(self.lid.." _ScheduledSARFlight")
69247
69789
  self:T({heliname,groupname})
69248
69790
  local _heliUnit=self:_GetSARHeli(heliname)
@@ -69256,17 +69798,25 @@ return
69256
69798
  end
69257
69799
  local _dist=self:_GetClosestMASH(_heliUnit)
69258
69800
  if _dist==-1 then
69801
+ self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance can not be determined!")
69259
69802
  return
69260
69803
  end
69804
+ self:T(self.lid.."[Drop off debug] Check distance to MASH for "..heliname.." Distance km: "..math.floor(_dist/1000))
69261
69805
  if(_dist<self.FARPRescueDistance or isairport)and _heliUnit:InAir()==false then
69806
+ self:T(self.lid.."[Drop off debug] Distance ok, door check")
69262
69807
  if self.pilotmustopendoors and self:_IsLoadingDoorOpen(heliname)==false then
69263
69808
  self:_DisplayMessageToSAR(_heliUnit,"Open the door to let me out!",self.messageTime,true,true)
69809
+ self:T(self.lid.."[Drop off debug] Door closed, try again next loop")
69264
69810
  else
69811
+ self:T(self.lid.."[Drop off debug] Rescued!")
69265
69812
  self:_RescuePilots(_heliUnit)
69266
69813
  return
69267
69814
  end
69268
69815
  end
69269
- self:__Returning(-5,heliname,_woundedGroupName,isairport)
69816
+ if not noreschedule then
69817
+ self:__Returning(5,heliname,_woundedGroupName,isairport)
69818
+ self:ScheduleOnce(5,self._ScheduledSARFlight,self,heliname,groupname,isairport,noreschedule)
69819
+ end
69270
69820
  return self
69271
69821
  end
69272
69822
  function CSAR:_RescuePilots(_heliUnit)
@@ -69308,7 +69858,6 @@ self.msrs:SetCoordinate(coord)
69308
69858
  end
69309
69859
  _text=string.gsub(_text,"km"," kilometer")
69310
69860
  _text=string.gsub(_text,"nm"," nautical miles")
69311
- self:I("Voice = "..self.SRSVoice)
69312
69861
  self.SRSQueue:NewTransmission(_text,duration,self.msrs,tstart,2,subgroups,subtitle,subduration,self.SRSchannel,self.SRSModulation,gender,culture,self.SRSVoice,volume,label,coord)
69313
69862
  end
69314
69863
  return self
@@ -69670,7 +70219,7 @@ self:T(self.lid.." _RefreshRadioBeacons")
69670
70219
  if self:_CountActiveDownedPilots()>0 then
69671
70220
  local PilotTable=self.downedPilots
69672
70221
  for _,_pilot in pairs(PilotTable)do
69673
- self:T({_pilot})
70222
+ self:T({_pilot.name})
69674
70223
  local pilot=_pilot
69675
70224
  local group=pilot.group
69676
70225
  local frequency=pilot.frequency or 0
@@ -69872,7 +70421,6 @@ return self
69872
70421
  end
69873
70422
  function CSAR:onbeforeReturning(From,Event,To,Heliname,Woundedgroupname,IsAirPort)
69874
70423
  self:T({From,Event,To,Heliname,Woundedgroupname})
69875
- self:_ScheduledSARFlight(Heliname,Woundedgroupname,IsAirPort)
69876
70424
  return self
69877
70425
  end
69878
70426
  function CSAR:onbeforeRescued(From,Event,To,HeliUnit,HeliName,PilotsSaved)
@@ -70279,7 +70827,7 @@ local DistanceFromHomeBase=self.HomeAirbase:GetCoordinate():Get2DDistance(self.C
70279
70827
  if not self:Is("Holding")and not self:Is("Returning")then
70280
70828
  local DistanceFromHomeBase=self.HomeAirbase:GetCoordinate():Get2DDistance(self.Controllable:GetCoordinate())
70281
70829
  if DistanceFromHomeBase>self.DisengageRadius then
70282
- self:I(self.Controllable:GetName().." is too far from home base, RTB!")
70830
+ self:T(self.Controllable:GetName().." is too far from home base, RTB!")
70283
70831
  self:Hold(300)
70284
70832
  RTB=false
70285
70833
  end
@@ -70288,10 +70836,10 @@ if not self:Is("Fuel")and not self:Is("Home")and not self:is("Refuelling")then
70288
70836
  local Fuel=self.Controllable:GetFuelMin()
70289
70837
  if Fuel<self.FuelThresholdPercentage then
70290
70838
  if self.TankerName then
70291
- self:I(self.Controllable:GetName().." is out of fuel: "..Fuel.." ... Refuelling at Tanker!")
70839
+ self:T(self.Controllable:GetName().." is out of fuel: "..Fuel.." ... Refuelling at Tanker!")
70292
70840
  self:Refuel()
70293
70841
  else
70294
- self:I(self.Controllable:GetName().." is out of fuel: "..Fuel.." ... RTB!")
70842
+ self:T(self.Controllable:GetName().." is out of fuel: "..Fuel.." ... RTB!")
70295
70843
  local OldAIControllable=self.Controllable
70296
70844
  local OrbitTask=OldAIControllable:TaskOrbitCircle(math.random(self.PatrolFloorAltitude,self.PatrolCeilingAltitude),self.PatrolMinSpeed)
70297
70845
  local TimedOrbitTask=OldAIControllable:TaskControlled(OrbitTask,OldAIControllable:TaskCondition(nil,nil,nil,nil,self.OutOfFuelOrbitTime,nil))
@@ -70308,7 +70856,7 @@ end
70308
70856
  local Damage=self.Controllable:GetLife()
70309
70857
  local InitialLife=self.Controllable:GetLife0()
70310
70858
  if(Damage/InitialLife)<self.PatrolDamageThreshold then
70311
- self:I(self.Controllable:GetName().." is damaged: "..Damage.." ... RTB!")
70859
+ self:T(self.Controllable:GetName().." is damaged: "..Damage.." ... RTB!")
70312
70860
  self:Damaged()
70313
70861
  RTB=true
70314
70862
  self:SetStatusOff()
@@ -70323,7 +70871,7 @@ if self.IdleCount>=10 then
70323
70871
  if Damage~=InitialLife then
70324
70872
  self:Damaged()
70325
70873
  else
70326
- self:I(self.Controllable:GetName().." control lost! ")
70874
+ self:T(self.Controllable:GetName().." control lost! ")
70327
70875
  self:LostControl()
70328
70876
  end
70329
70877
  else
@@ -70369,6 +70917,7 @@ self:ClearTargetDistance()
70369
70917
  AIGroup:OptionProhibitAfterburner(true)
70370
70918
  local EngageRoute={}
70371
70919
  local FromCoord=AIGroup:GetCoordinate()
70920
+ if not FromCoord then return end
70372
70921
  local ToTargetCoord=self.HomeAirbase:GetCoordinate()
70373
70922
  local ToTargetVec3=ToTargetCoord:GetVec3()
70374
70923
  ToTargetVec3.y=ToTargetCoord:GetLandHeight()+3000
@@ -70383,12 +70932,12 @@ local RTBSpeed=math.random(self.RTBMinSpeed,self.RTBMaxSpeed)
70383
70932
  local Distance=FromCoord:Get2DDistance(ToTargetCoord2)
70384
70933
  local ToAirbaseCoord=ToTargetCoord2
70385
70934
  if Distance<5000 then
70386
- self:I("RTB and near the airbase!")
70935
+ self:T("RTB and near the airbase!")
70387
70936
  self:Home()
70388
70937
  return
70389
70938
  end
70390
70939
  if not AIGroup:InAir()==true then
70391
- self:I("Not anymore in the air, considered Home.")
70940
+ self:T("Not anymore in the air, considered Home.")
70392
70941
  self:Home()
70393
70942
  return
70394
70943
  end
@@ -70418,15 +70967,17 @@ end
70418
70967
  end
70419
70968
  function AI_AIR:onafterHome(AIGroup,From,Event,To)
70420
70969
  self:F({AIGroup,From,Event,To})
70421
- self:I("Group "..self.Controllable:GetName().." ... Home! ( "..self:GetState().." )")
70970
+ self:T("Group "..self.Controllable:GetName().." ... Home! ( "..self:GetState().." )")
70422
70971
  if AIGroup and AIGroup:IsAlive()then
70423
70972
  end
70424
70973
  end
70425
70974
  function AI_AIR:onafterHold(AIGroup,From,Event,To,HoldTime)
70426
70975
  self:F({AIGroup,From,Event,To})
70427
- self:I("Group "..self.Controllable:GetName().." ... Holding! ( "..self:GetState().." )")
70976
+ self:T("Group "..self.Controllable:GetName().." ... Holding! ( "..self:GetState().." )")
70428
70977
  if AIGroup and AIGroup:IsAlive()then
70429
- local OrbitTask=AIGroup:TaskOrbitCircle(math.random(self.PatrolFloorAltitude,self.PatrolCeilingAltitude),self.PatrolMinSpeed)
70978
+ local Coordinate=AIGroup:GetCoordinate()
70979
+ if Coordinate==nil then return end
70980
+ local OrbitTask=AIGroup:TaskOrbitCircle(math.random(self.PatrolFloorAltitude,self.PatrolCeilingAltitude),self.PatrolMinSpeed,Coordinate)
70430
70981
  local TimedOrbitTask=AIGroup:TaskControlled(OrbitTask,AIGroup:TaskCondition(nil,nil,nil,nil,HoldTime,nil))
70431
70982
  local RTBTask=AIGroup:TaskFunction("AI_AIR.RTBHold",self)
70432
70983
  local OrbitHoldTask=AIGroup:TaskOrbitCircle(4000,self.PatrolMinSpeed)
@@ -70434,7 +70985,7 @@ AIGroup:SetTask(AIGroup:TaskCombo({TimedOrbitTask,RTBTask,OrbitHoldTask}),1)
70434
70985
  end
70435
70986
  end
70436
70987
  function AI_AIR.Resume(AIGroup,Fsm)
70437
- AIGroup:I({"AI_AIR.Resume:",AIGroup:GetName()})
70988
+ AIGroup:T({"AI_AIR.Resume:",AIGroup:GetName()})
70438
70989
  if AIGroup:IsAlive()then
70439
70990
  Fsm:__RTB(Fsm.TaskDelay)
70440
70991
  end
@@ -70444,7 +70995,7 @@ self:F({AIGroup,From,Event,To})
70444
70995
  if AIGroup and AIGroup:IsAlive()then
70445
70996
  local Tanker=GROUP:FindByName(self.TankerName)
70446
70997
  if Tanker and Tanker:IsAlive()and Tanker:IsAirPlane()then
70447
- self:I("Group "..self.Controllable:GetName().." ... Refuelling! State="..self:GetState()..", Refuelling tanker "..self.TankerName)
70998
+ self:T("Group "..self.Controllable:GetName().." ... Refuelling! State="..self:GetState()..", Refuelling tanker "..self.TankerName)
70448
70999
  local RefuelRoute={}
70449
71000
  local FromRefuelCoord=AIGroup:GetCoordinate()
70450
71001
  local ToRefuelCoord=Tanker:GetCoordinate()
@@ -70657,13 +71208,13 @@ end
70657
71208
  end
70658
71209
  end
70659
71210
  function AI_AIR_ENGAGE.___EngageRoute(AIGroup,Fsm,AttackSetUnit)
70660
- Fsm:I(string.format("AI_AIR_ENGAGE.___EngageRoute: %s",tostring(AIGroup:GetName())))
71211
+ Fsm:T(string.format("AI_AIR_ENGAGE.___EngageRoute: %s",tostring(AIGroup:GetName())))
70661
71212
  if AIGroup and AIGroup:IsAlive()then
70662
71213
  Fsm:__EngageRoute(Fsm.TaskDelay or 0.1,AttackSetUnit)
70663
71214
  end
70664
71215
  end
70665
71216
  function AI_AIR_ENGAGE:onafterEngageRoute(DefenderGroup,From,Event,To,AttackSetUnit)
70666
- self:I({DefenderGroup,From,Event,To,AttackSetUnit})
71217
+ self:T({DefenderGroup,From,Event,To,AttackSetUnit})
70667
71218
  local DefenderGroupName=DefenderGroup:GetName()
70668
71219
  self.AttackSetUnit=AttackSetUnit
70669
71220
  local AttackCount=AttackSetUnit:CountAlive()
@@ -70673,7 +71224,11 @@ local EngageAltitude=math.random(self.EngageFloorAltitude,self.EngageCeilingAlti
70673
71224
  local EngageSpeed=math.random(self.EngageMinSpeed,self.EngageMaxSpeed)
70674
71225
  local DefenderCoord=DefenderGroup:GetPointVec3()
70675
71226
  DefenderCoord:SetY(EngageAltitude)
70676
- local TargetCoord=AttackSetUnit:GetFirst():GetPointVec3()
71227
+ local TargetCoord=AttackSetUnit:GetRandomSurely():GetPointVec3()
71228
+ if TargetCoord==nil then
71229
+ self:Return()
71230
+ return
71231
+ end
70677
71232
  TargetCoord:SetY(EngageAltitude)
70678
71233
  local TargetDistance=DefenderCoord:Get2DDistance(TargetCoord)
70679
71234
  local EngageDistance=(DefenderGroup:IsHelicopter()and 5000)or(DefenderGroup:IsAirPlane()and 10000)
@@ -70697,12 +71252,12 @@ DefenderGroup:Route(EngageRoute,self.TaskDelay or 0.1)
70697
71252
  end
70698
71253
  end
70699
71254
  else
70700
- self:I(DefenderGroupName..": No targets found -> Going RTB")
71255
+ self:T(DefenderGroupName..": No targets found -> Going RTB")
70701
71256
  self:Return()
70702
71257
  end
70703
71258
  end
70704
71259
  function AI_AIR_ENGAGE.___Engage(AIGroup,Fsm,AttackSetUnit)
70705
- Fsm:I(string.format("AI_AIR_ENGAGE.___Engage: %s",tostring(AIGroup:GetName())))
71260
+ Fsm:T(string.format("AI_AIR_ENGAGE.___Engage: %s",tostring(AIGroup:GetName())))
70706
71261
  if AIGroup and AIGroup:IsAlive()then
70707
71262
  local delay=Fsm.TaskDelay or 0.1
70708
71263
  Fsm:__Engage(delay,AttackSetUnit)
@@ -70720,7 +71275,7 @@ local EngageAltitude=math.random(self.EngageFloorAltitude or 500,self.EngageCeil
70720
71275
  local EngageSpeed=math.random(self.EngageMinSpeed,self.EngageMaxSpeed)
70721
71276
  local DefenderCoord=DefenderGroup:GetPointVec3()
70722
71277
  DefenderCoord:SetY(EngageAltitude)
70723
- local TargetCoord=AttackSetUnit:GetFirst():GetPointVec3()
71278
+ local TargetCoord=AttackSetUnit:GetRandomSurely():GetPointVec3()
70724
71279
  if not TargetCoord then
70725
71280
  self:Return()
70726
71281
  return
@@ -70740,12 +71295,12 @@ EngageRoute[#EngageRoute+1]=ToWP
70740
71295
  if TargetDistance<=EngageDistance*9 then
70741
71296
  local AttackUnitTasks=self:CreateAttackUnitTasks(AttackSetUnit,DefenderGroup,EngageAltitude)
70742
71297
  if#AttackUnitTasks==0 then
70743
- self:I(DefenderGroupName..": No valid targets found -> Going RTB")
71298
+ self:T(DefenderGroupName..": No valid targets found -> Going RTB")
70744
71299
  self:Return()
70745
71300
  return
70746
71301
  else
70747
71302
  local text=string.format("%s: Engaging targets at distance %.2f NM",DefenderGroupName,UTILS.MetersToNM(TargetDistance))
70748
- self:I(text)
71303
+ self:T(text)
70749
71304
  DefenderGroup:OptionROEOpenFire()
70750
71305
  DefenderGroup:OptionROTEvadeFire()
70751
71306
  DefenderGroup:OptionKeepWeaponsOnThreat()
@@ -70757,7 +71312,7 @@ EngageRoute[#EngageRoute].task=DefenderGroup:TaskCombo(AttackTasks)
70757
71312
  DefenderGroup:Route(EngageRoute,self.TaskDelay or 0.1)
70758
71313
  end
70759
71314
  else
70760
- self:I(DefenderGroupName..": No targets found -> returning.")
71315
+ self:T(DefenderGroupName..": No targets found -> returning.")
70761
71316
  self:Return()
70762
71317
  return
70763
71318
  end
@@ -71018,12 +71573,12 @@ end
71018
71573
  end
71019
71574
  function AI_A2A_DISPATCHER:OnEventBaseCaptured(EventData)
71020
71575
  local AirbaseName=EventData.PlaceName
71021
- self:I("Captured "..AirbaseName)
71576
+ self:T("Captured "..AirbaseName)
71022
71577
  for SquadronName,Squadron in pairs(self.DefenderSquadrons)do
71023
71578
  if Squadron.AirbaseName==AirbaseName then
71024
71579
  Squadron.ResourceCount=-999
71025
71580
  Squadron.Captured=true
71026
- self:I("Squadron "..SquadronName.." captured.")
71581
+ self:T("Squadron "..SquadronName.." captured.")
71027
71582
  end
71028
71583
  end
71029
71584
  end
@@ -71260,7 +71815,7 @@ Cap.PatrolCeilingAltitude=PatrolCeilingAltitude
71260
71815
  Cap.PatrolAltType=PatrolAltType
71261
71816
  Cap.EngageAltType=EngageAltType
71262
71817
  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}})
71818
+ self:T({CAP={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,Zone,PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageAltType}})
71264
71819
  local RecceSet=self.Detection:GetDetectionSet()
71265
71820
  RecceSet:FilterPrefixes(DefenderSquadron.TemplatePrefixes)
71266
71821
  RecceSet:FilterStart()
@@ -71378,7 +71933,7 @@ Intercept.EngageMaxSpeed=EngageMaxSpeed
71378
71933
  Intercept.EngageFloorAltitude=EngageFloorAltitude
71379
71934
  Intercept.EngageCeilingAltitude=EngageCeilingAltitude
71380
71935
  Intercept.EngageAltType=EngageAltType
71381
- self:I({GCI={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
71936
+ self:T({GCI={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
71382
71937
  end
71383
71938
  function AI_A2A_DISPATCHER:SetSquadronGci(SquadronName,EngageMinSpeed,EngageMaxSpeed)
71384
71939
  self.DefenderSquadrons[SquadronName]=self.DefenderSquadrons[SquadronName]or{}
@@ -72255,22 +72810,22 @@ table.insert(AirbaseNames,AirbaseName)
72255
72810
  end
72256
72811
  end
72257
72812
  self.Templates=SET_GROUP:New():FilterPrefixes(TemplatePrefixes):FilterOnce()
72258
- self:I({Airbases=AirbaseNames})
72259
- self:I("Defining Templates for Airbases ...")
72813
+ self:T({Airbases=AirbaseNames})
72814
+ self:T("Defining Templates for Airbases ...")
72260
72815
  for AirbaseID,AirbaseName in pairs(AirbaseNames)do
72261
72816
  local Airbase=_DATABASE:FindAirbase(AirbaseName)
72262
72817
  local AirbaseName=Airbase:GetName()
72263
72818
  local AirbaseCoord=Airbase:GetCoordinate()
72264
72819
  local AirbaseZone=ZONE_RADIUS:New("Airbase",AirbaseCoord:GetVec2(),3000)
72265
72820
  local Templates=nil
72266
- self:I({Airbase=AirbaseName})
72821
+ self:T({Airbase=AirbaseName})
72267
72822
  for TemplateID,Template in pairs(self.Templates:GetSet())do
72268
72823
  local Template=Template
72269
72824
  local TemplateCoord=Template:GetCoordinate()
72270
72825
  if AirbaseZone:IsVec2InZone(TemplateCoord:GetVec2())then
72271
72826
  Templates=Templates or{}
72272
72827
  table.insert(Templates,Template:GetName())
72273
- self:I({Template=Template:GetName()})
72828
+ self:T({Template=Template:GetName()})
72274
72829
  end
72275
72830
  end
72276
72831
  if Templates then
@@ -72280,12 +72835,12 @@ end
72280
72835
  self.CAPTemplates=SET_GROUP:New()
72281
72836
  self.CAPTemplates:FilterPrefixes(CapPrefixes)
72282
72837
  self.CAPTemplates:FilterOnce()
72283
- self:I("Setting up CAP ...")
72838
+ self:T("Setting up CAP ...")
72284
72839
  for CAPID,CAPTemplate in pairs(self.CAPTemplates:GetSet())do
72285
72840
  local CAPZone=ZONE_POLYGON:New(CAPTemplate:GetName(),CAPTemplate)
72286
72841
  local AirbaseDistance=99999999
72287
72842
  local AirbaseClosest=nil
72288
- self:I({CAPZoneGroup=CAPID})
72843
+ self:T({CAPZoneGroup=CAPID})
72289
72844
  for AirbaseID,AirbaseName in pairs(AirbaseNames)do
72290
72845
  local Airbase=_DATABASE:FindAirbase(AirbaseName)
72291
72846
  local AirbaseName=Airbase:GetName()
@@ -72293,7 +72848,7 @@ local AirbaseCoord=Airbase:GetCoordinate()
72293
72848
  local Squadron=self.DefenderSquadrons[AirbaseName]
72294
72849
  if Squadron then
72295
72850
  local Distance=AirbaseCoord:Get2DDistance(CAPZone:GetCoordinate())
72296
- self:I({AirbaseDistance=Distance})
72851
+ self:T({AirbaseDistance=Distance})
72297
72852
  if Distance<AirbaseDistance then
72298
72853
  AirbaseDistance=Distance
72299
72854
  AirbaseClosest=Airbase
@@ -72301,19 +72856,19 @@ end
72301
72856
  end
72302
72857
  end
72303
72858
  if AirbaseClosest then
72304
- self:I({CAPAirbase=AirbaseClosest:GetName()})
72859
+ self:T({CAPAirbase=AirbaseClosest:GetName()})
72305
72860
  self:SetSquadronCap(AirbaseClosest:GetName(),CAPZone,6000,10000,500,800,800,1200,"RADIO")
72306
72861
  self:SetSquadronCapInterval(AirbaseClosest:GetName(),CapLimit,300,600,1)
72307
72862
  end
72308
72863
  end
72309
- self:I("Setting up GCI ...")
72864
+ self:T("Setting up GCI ...")
72310
72865
  for AirbaseID,AirbaseName in pairs(AirbaseNames)do
72311
72866
  local Airbase=_DATABASE:FindAirbase(AirbaseName)
72312
72867
  local AirbaseName=Airbase:GetName()
72313
72868
  local Squadron=self.DefenderSquadrons[AirbaseName]
72314
72869
  self:F({Airbase=AirbaseName})
72315
72870
  if Squadron then
72316
- self:I({GCIAirbase=AirbaseName})
72871
+ self:T({GCIAirbase=AirbaseName})
72317
72872
  self:SetSquadronGci(AirbaseName,800,1200)
72318
72873
  end
72319
72874
  end
@@ -72476,7 +73031,7 @@ DefenderSquadron.Resource={}
72476
73031
  for Resource=1,DefenderSquadron.ResourceCount or 0 do
72477
73032
  self:ResourcePark(DefenderSquadron)
72478
73033
  end
72479
- self:I("Parked resources for squadron "..DefenderSquadron.Name)
73034
+ self:T("Parked resources for squadron "..DefenderSquadron.Name)
72480
73035
  end
72481
73036
  end
72482
73037
  function AI_A2G_DISPATCHER:Lock(DetectedItemIndex)
@@ -72520,12 +73075,12 @@ end
72520
73075
  end
72521
73076
  function AI_A2G_DISPATCHER:OnEventBaseCaptured(EventData)
72522
73077
  local AirbaseName=EventData.PlaceName
72523
- self:I("Captured "..AirbaseName)
73078
+ self:T("Captured "..AirbaseName)
72524
73079
  for SquadronName,Squadron in pairs(self.DefenderSquadrons)do
72525
73080
  if Squadron.AirbaseName==AirbaseName then
72526
73081
  Squadron.ResourceCount=-999
72527
73082
  Squadron.Captured=true
72528
- self:I("Squadron "..SquadronName.." captured.")
73083
+ self:T("Squadron "..SquadronName.." captured.")
72529
73084
  end
72530
73085
  end
72531
73086
  end
@@ -72546,7 +73101,7 @@ if DefenderSize==1 then
72546
73101
  self:RemoveDefenderFromSquadron(Squadron,Defender)
72547
73102
  end
72548
73103
  DefenderUnit:Destroy()
72549
- self:ResourcePark(Squadron,Defender)
73104
+ self:ResourcePark(Squadron)
72550
73105
  return
72551
73106
  end
72552
73107
  if DefenderUnit:GetLife()~=DefenderUnit:GetLife0()then
@@ -72569,7 +73124,7 @@ if DefenderSize==1 then
72569
73124
  self:RemoveDefenderFromSquadron(Squadron,Defender)
72570
73125
  end
72571
73126
  DefenderUnit:Destroy()
72572
- self:ResourcePark(Squadron,Defender)
73127
+ self:ResourcePark(Squadron)
72573
73128
  end
72574
73129
  end
72575
73130
  end
@@ -72592,7 +73147,7 @@ self.DisengageRadius=DisengageRadius or 300000
72592
73147
  return self
72593
73148
  end
72594
73149
  function AI_A2G_DISPATCHER:SetDefenseRadius(DefenseRadius)
72595
- self.DefenseRadius=DefenseRadius or 100000
73150
+ self.DefenseRadius=DefenseRadius or 40000
72596
73151
  self.Detection:SetAcceptRange(self.DefenseRadius)
72597
73152
  return self
72598
73153
  end
@@ -72861,7 +73416,7 @@ Sead.EngageFloorAltitude=EngageFloorAltitude or 500
72861
73416
  Sead.EngageCeilingAltitude=EngageCeilingAltitude or 1000
72862
73417
  Sead.EngageAltType=EngageAltType
72863
73418
  Sead.Defend=true
72864
- self:I({SEAD={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
73419
+ self:T({SEAD={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72865
73420
  return self
72866
73421
  end
72867
73422
  function AI_A2G_DISPATCHER:SetSquadronSead(SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude)
@@ -72888,7 +73443,7 @@ SeadPatrol.PatrolAltType=PatrolAltType
72888
73443
  SeadPatrol.EngageAltType=EngageAltType
72889
73444
  SeadPatrol.Patrol=true
72890
73445
  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}})
73446
+ self:T({SEAD={Zone:GetName(),PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72892
73447
  end
72893
73448
  function AI_A2G_DISPATCHER:SetSquadronSeadPatrol(SquadronName,Zone,FloorAltitude,CeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,EngageMinSpeed,EngageMaxSpeed,AltType)
72894
73449
  self:SetSquadronSeadPatrol2(SquadronName,Zone,PatrolMinSpeed,PatrolMaxSpeed,FloorAltitude,CeilingAltitude,AltType,EngageMinSpeed,EngageMaxSpeed,FloorAltitude,CeilingAltitude,AltType)
@@ -72904,7 +73459,7 @@ Cas.EngageFloorAltitude=EngageFloorAltitude or 500
72904
73459
  Cas.EngageCeilingAltitude=EngageCeilingAltitude or 1000
72905
73460
  Cas.EngageAltType=EngageAltType
72906
73461
  Cas.Defend=true
72907
- self:I({CAS={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
73462
+ self:T({CAS={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72908
73463
  return self
72909
73464
  end
72910
73465
  function AI_A2G_DISPATCHER:SetSquadronCas(SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude)
@@ -72931,7 +73486,7 @@ CasPatrol.PatrolAltType=PatrolAltType
72931
73486
  CasPatrol.EngageAltType=EngageAltType
72932
73487
  CasPatrol.Patrol=true
72933
73488
  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}})
73489
+ self:T({CAS={Zone:GetName(),PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72935
73490
  end
72936
73491
  function AI_A2G_DISPATCHER:SetSquadronCasPatrol(SquadronName,Zone,FloorAltitude,CeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,EngageMinSpeed,EngageMaxSpeed,AltType)
72937
73492
  self:SetSquadronCasPatrol2(SquadronName,Zone,PatrolMinSpeed,PatrolMaxSpeed,FloorAltitude,CeilingAltitude,AltType,EngageMinSpeed,EngageMaxSpeed,FloorAltitude,CeilingAltitude,AltType)
@@ -72947,7 +73502,7 @@ Bai.EngageFloorAltitude=EngageFloorAltitude or 500
72947
73502
  Bai.EngageCeilingAltitude=EngageCeilingAltitude or 1000
72948
73503
  Bai.EngageAltType=EngageAltType
72949
73504
  Bai.Defend=true
72950
- self:I({BAI={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
73505
+ self:T({BAI={SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72951
73506
  return self
72952
73507
  end
72953
73508
  function AI_A2G_DISPATCHER:SetSquadronBai(SquadronName,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude)
@@ -72974,7 +73529,7 @@ BaiPatrol.PatrolAltType=PatrolAltType
72974
73529
  BaiPatrol.EngageAltType=EngageAltType
72975
73530
  BaiPatrol.Patrol=true
72976
73531
  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}})
73532
+ self:T({BAI={Zone:GetName(),PatrolMinSpeed,PatrolMaxSpeed,PatrolFloorAltitude,PatrolCeilingAltitude,PatrolAltType,EngageMinSpeed,EngageMaxSpeed,EngageFloorAltitude,EngageCeilingAltitude,EngageAltType}})
72978
73533
  end
72979
73534
  function AI_A2G_DISPATCHER:SetSquadronBaiPatrol(SquadronName,Zone,FloorAltitude,CeilingAltitude,PatrolMinSpeed,PatrolMaxSpeed,EngageMinSpeed,EngageMaxSpeed,AltType)
72980
73535
  self:SetSquadronBaiPatrol2(SquadronName,Zone,PatrolMinSpeed,PatrolMaxSpeed,FloorAltitude,CeilingAltitude,AltType,EngageMinSpeed,EngageMaxSpeed,FloorAltitude,CeilingAltitude,AltType)
@@ -73514,7 +74069,7 @@ local DefenderName=DefenderGroup:GetCallsign()
73514
74069
  local Dispatcher=AI_A2G_Fsm:GetDispatcher()
73515
74070
  local Squadron=Dispatcher:GetSquadronFromDefender(DefenderGroup)
73516
74071
  if Squadron then
73517
- local FirstUnit=AttackSetUnit:GetFirst()
74072
+ local FirstUnit=AttackSetUnit:GetRandomSurely()
73518
74073
  local Coordinate=FirstUnit:GetCoordinate()
73519
74074
  if self.SetSendPlayerMessages then
73520
74075
  Dispatcher:MessageToPlayers(Squadron,DefenderName..", on route to ground target at "..Coordinate:ToStringA2G(DefenderGroup),DefenderGroup)
@@ -74333,7 +74888,7 @@ if self.Controllable and self.Controllable:IsAlive()then
74333
74888
  local RTB=false
74334
74889
  local Fuel=self.Controllable:GetFuelMin()
74335
74890
  if Fuel<self.PatrolFuelThresholdPercentage then
74336
- self:I(self.Controllable:GetName().." is out of fuel:"..Fuel..", RTB!")
74891
+ self:T(self.Controllable:GetName().." is out of fuel:"..Fuel..", RTB!")
74337
74892
  local OldAIControllable=self.Controllable
74338
74893
  local OrbitTask=OldAIControllable:TaskOrbitCircle(math.random(self.PatrolFloorAltitude,self.PatrolCeilingAltitude),self.PatrolMinSpeed)
74339
74894
  local TimedOrbitTask=OldAIControllable:TaskControlled(OrbitTask,OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil))
@@ -74343,7 +74898,7 @@ else
74343
74898
  end
74344
74899
  local Damage=self.Controllable:GetLife()
74345
74900
  if Damage<=self.PatrolDamageThreshold then
74346
- self:I(self.Controllable:GetName().." is damaged:"..Damage..", RTB!")
74901
+ self:T(self.Controllable:GetName().." is damaged:"..Damage..", RTB!")
74347
74902
  RTB=true
74348
74903
  end
74349
74904
  if RTB==true then
@@ -76509,11 +77064,11 @@ function AI_ESCORT_DISPATCHER:OnEventExit(EventData)
76509
77064
  local PlayerGroupName=EventData.IniGroupName
76510
77065
  local PlayerGroup=EventData.IniGroup
76511
77066
  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)})
77067
+ self:T({EscortAirbase=self.EscortAirbase})
77068
+ self:T({PlayerGroupName=PlayerGroupName})
77069
+ self:T({PlayerGroup=PlayerGroup})
77070
+ self:T({FirstGroup=self.CarrierSet:GetFirst()})
77071
+ self:T({FindGroup=self.CarrierSet:FindGroup(PlayerGroupName)})
76517
77072
  if self.CarrierSet:FindGroup(PlayerGroupName)then
76518
77073
  if self.AI_Escorts[PlayerGroupName]then
76519
77074
  self.AI_Escorts[PlayerGroupName]:Stop()
@@ -76525,16 +77080,16 @@ function AI_ESCORT_DISPATCHER:OnEventBirth(EventData)
76525
77080
  local PlayerGroupName=EventData.IniGroupName
76526
77081
  local PlayerGroup=EventData.IniGroup
76527
77082
  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)})
77083
+ self:T({EscortAirbase=self.EscortAirbase})
77084
+ self:T({PlayerGroupName=PlayerGroupName})
77085
+ self:T({PlayerGroup=PlayerGroup})
77086
+ self:T({FirstGroup=self.CarrierSet:GetFirst()})
77087
+ self:T({FindGroup=self.CarrierSet:FindGroup(PlayerGroupName)})
76533
77088
  if self.CarrierSet:FindGroup(PlayerGroupName)then
76534
77089
  if not self.AI_Escorts[PlayerGroupName]then
76535
77090
  local LeaderUnit=PlayerUnit
76536
77091
  local EscortGroup=self.EscortSpawn:SpawnAtAirbase(self.EscortAirbase,SPAWN.Takeoff.Hot)
76537
- self:I({EscortGroup=EscortGroup})
77092
+ self:T({EscortGroup=EscortGroup})
76538
77093
  self:ScheduleOnce(1,
76539
77094
  function(EscortGroup)
76540
77095
  local EscortSet=SET_GROUP:New()
@@ -76833,7 +77388,7 @@ if Carrier and Carrier:IsAlive()then
76833
77388
  for _,CarrierUnit in pairs(Carrier:GetUnits())do
76834
77389
  local CarrierUnit=CarrierUnit
76835
77390
  local IsEmpty=CarrierUnit:IsCargoEmpty()
76836
- self:I({IsEmpty=IsEmpty})
77391
+ self:T({IsEmpty=IsEmpty})
76837
77392
  if not IsEmpty then
76838
77393
  AllUnloaded=false
76839
77394
  break
@@ -77921,7 +78476,7 @@ break
77921
78476
  else
77922
78477
  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
78478
  tostring(Cargo:GetName()),Cargo:GetWeight(),LargestLoadCapacity,tostring(Carrier:GetName()))
77924
- self:I(text)
78479
+ self:T(text)
77925
78480
  end
77926
78481
  end
77927
78482
  end
@@ -78527,6 +79082,954 @@ end
78527
79082
  )
78528
79083
  end
78529
79084
  end
79085
+ SHAPE_BASE={
79086
+ ClassName="SHAPE_BASE",
79087
+ Name="",
79088
+ CenterVec2=nil,
79089
+ Points={},
79090
+ Coords={},
79091
+ MarkIDs={},
79092
+ ColorString="",
79093
+ ColorRGBA={}
79094
+ }
79095
+ function SHAPE_BASE:New()
79096
+ local self=BASE:Inherit(self,BASE:New())
79097
+ return self
79098
+ end
79099
+ function SHAPE_BASE:FindOnMap(shape_name)
79100
+ local self=BASE:Inherit(self,BASE:New())
79101
+ local found=false
79102
+ for _,layer in pairs(env.mission.drawings.layers)do
79103
+ for _,object in pairs(layer["objects"])do
79104
+ if object["name"]==shape_name then
79105
+ self.Name=object["name"]
79106
+ self.CenterVec2={x=object["mapX"],y=object["mapY"]}
79107
+ self.ColorString=object["colorString"]
79108
+ self.ColorRGBA=UTILS.HexToRGBA(self.ColorString)
79109
+ found=true
79110
+ end
79111
+ end
79112
+ end
79113
+ if not found then
79114
+ self:E("Can't find a shape with name "..shape_name)
79115
+ end
79116
+ return self
79117
+ end
79118
+ function SHAPE_BASE:GetAllShapes(filter)
79119
+ filter=filter or""
79120
+ local return_shapes={}
79121
+ for _,layer in pairs(env.mission.drawings.layers)do
79122
+ for _,object in pairs(layer["objects"])do
79123
+ if string.contains(object["name"],filter)then
79124
+ table.add(return_shapes,object)
79125
+ end
79126
+ end
79127
+ end
79128
+ return return_shapes
79129
+ end
79130
+ function SHAPE_BASE:Offset(new_vec2)
79131
+ local offset_vec2=UTILS.Vec2Subtract(new_vec2,self.CenterVec2)
79132
+ self.CenterVec2=new_vec2
79133
+ if self.ClassName=="POLYGON"then
79134
+ for _,point in pairs(self.Points)do
79135
+ point.x=point.x+offset_vec2.x
79136
+ point.y=point.y+offset_vec2.y
79137
+ end
79138
+ end
79139
+ end
79140
+ function SHAPE_BASE:GetName()
79141
+ return self.Name
79142
+ end
79143
+ function SHAPE_BASE:GetColorString()
79144
+ return self.ColorString
79145
+ end
79146
+ function SHAPE_BASE:GetColorRGBA()
79147
+ return self.ColorRGBA
79148
+ end
79149
+ function SHAPE_BASE:GetColorRed()
79150
+ return self.ColorRGBA.R
79151
+ end
79152
+ function SHAPE_BASE:GetColorGreen()
79153
+ return self.ColorRGBA.G
79154
+ end
79155
+ function SHAPE_BASE:GetColorBlue()
79156
+ return self.ColorRGBA.B
79157
+ end
79158
+ function SHAPE_BASE:GetColorAlpha()
79159
+ return self.ColorRGBA.A
79160
+ end
79161
+ function SHAPE_BASE:GetCenterVec2()
79162
+ return self.CenterVec2
79163
+ end
79164
+ function SHAPE_BASE:GetCenterCoordinate()
79165
+ return COORDINATE:NewFromVec2(self.CenterVec2)
79166
+ end
79167
+ function SHAPE_BASE:GetCoordinate()
79168
+ return self:GetCenterCoordinate()
79169
+ end
79170
+ function SHAPE_BASE:ContainsPoint(_)
79171
+ self:E("This needs to be set in the derived class")
79172
+ end
79173
+ function SHAPE_BASE:ContainsUnit(unit_name)
79174
+ local unit=UNIT:FindByName(unit_name)
79175
+ if unit==nil or not unit:IsAlive()then
79176
+ return false
79177
+ end
79178
+ if self:ContainsPoint(unit:GetVec2())then
79179
+ return true
79180
+ end
79181
+ return false
79182
+ end
79183
+ function SHAPE_BASE:ContainsAnyOfGroup(group_name)
79184
+ local group=GROUP:FindByName(group_name)
79185
+ if group==nil or not group:IsAlive()then
79186
+ return false
79187
+ end
79188
+ for _,unit in pairs(group:GetUnits())do
79189
+ if self:ContainsPoint(unit:GetVec2())then
79190
+ return true
79191
+ end
79192
+ end
79193
+ return false
79194
+ end
79195
+ function SHAPE_BASE:ContainsAllOfGroup(group_name)
79196
+ local group=GROUP:FindByName(group_name)
79197
+ if group==nil or not group:IsAlive()then
79198
+ return false
79199
+ end
79200
+ for _,unit in pairs(group:GetUnits())do
79201
+ if not self:ContainsPoint(unit:GetVec2())then
79202
+ return false
79203
+ end
79204
+ end
79205
+ return true
79206
+ end
79207
+ CIRCLE={
79208
+ ClassName="CIRCLE",
79209
+ Radius=nil,
79210
+ }
79211
+ function CIRCLE:FindOnMap(shape_name)
79212
+ local self=BASE:Inherit(self,SHAPE_BASE:FindOnMap(shape_name))
79213
+ for _,layer in pairs(env.mission.drawings.layers)do
79214
+ for _,object in pairs(layer["objects"])do
79215
+ if string.find(object["name"],shape_name,1,true)then
79216
+ if object["polygonMode"]=="circle"then
79217
+ self.Radius=object["radius"]
79218
+ end
79219
+ end
79220
+ end
79221
+ end
79222
+ return self
79223
+ end
79224
+ function CIRCLE:Find(shape_name)
79225
+ return _DATABASE:FindShape(shape_name)
79226
+ end
79227
+ function CIRCLE:New(vec2,radius)
79228
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
79229
+ self.CenterVec2=vec2
79230
+ self.Radius=radius
79231
+ return self
79232
+ end
79233
+ function CIRCLE:GetRadius()
79234
+ return self.Radius
79235
+ end
79236
+ function CIRCLE:ContainsPoint(point)
79237
+ if((point.x-self.CenterVec2.x)^2+(point.y-self.CenterVec2.y)^2)^0.5<=self.Radius then
79238
+ return true
79239
+ end
79240
+ return false
79241
+ end
79242
+ function CIRCLE:PointInSector(point,sector_start,sector_end,center,radius)
79243
+ center=center or self.CenterVec2
79244
+ radius=radius or self.Radius
79245
+ local function are_clockwise(v1,v2)
79246
+ return-v1.x*v2.y+v1.y*v2.x>0
79247
+ end
79248
+ local function is_in_radius(rp)
79249
+ return rp.x*rp.x+rp.y*rp.y<=radius^2
79250
+ end
79251
+ local rel_pt={
79252
+ x=point.x-center.x,
79253
+ y=point.y-center.y
79254
+ }
79255
+ local rel_sector_start={
79256
+ x=sector_start.x-center.x,
79257
+ y=sector_start.y-center.y,
79258
+ }
79259
+ local rel_sector_end={
79260
+ x=sector_end.x-center.x,
79261
+ y=sector_end.y-center.y,
79262
+ }
79263
+ return not are_clockwise(rel_sector_start,rel_pt)and
79264
+ are_clockwise(rel_sector_end,rel_pt)and
79265
+ is_in_radius(rel_pt,radius)
79266
+ end
79267
+ function CIRCLE:UnitInSector(unit_name,sector_start,sector_end,center,radius)
79268
+ center=center or self.CenterVec2
79269
+ radius=radius or self.Radius
79270
+ if self:PointInSector(UNIT:FindByName(unit_name):GetVec2(),sector_start,sector_end,center,radius)then
79271
+ return true
79272
+ end
79273
+ return false
79274
+ end
79275
+ function CIRCLE:AnyOfGroupInSector(group_name,sector_start,sector_end,center,radius)
79276
+ center=center or self.CenterVec2
79277
+ radius=radius or self.Radius
79278
+ for _,unit in pairs(GROUP:FindByName(group_name):GetUnits())do
79279
+ if self:PointInSector(unit:GetVec2(),sector_start,sector_end,center,radius)then
79280
+ return true
79281
+ end
79282
+ end
79283
+ return false
79284
+ end
79285
+ function CIRCLE:AllOfGroupInSector(group_name,sector_start,sector_end,center,radius)
79286
+ center=center or self.CenterVec2
79287
+ radius=radius or self.Radius
79288
+ for _,unit in pairs(GROUP:FindByName(group_name):GetUnits())do
79289
+ if not self:PointInSector(unit:GetVec2(),sector_start,sector_end,center,radius)then
79290
+ return false
79291
+ end
79292
+ end
79293
+ return true
79294
+ end
79295
+ function CIRCLE:UnitInRadius(unit_name,center,radius)
79296
+ center=center or self.CenterVec2
79297
+ radius=radius or self.Radius
79298
+ if UTILS.IsInRadius(center,UNIT:FindByName(unit_name):GetVec2(),radius)then
79299
+ return true
79300
+ end
79301
+ return false
79302
+ end
79303
+ function CIRCLE:AnyOfGroupInRadius(group_name,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 UTILS.IsInRadius(center,unit:GetVec2(),radius)then
79308
+ return true
79309
+ end
79310
+ end
79311
+ return false
79312
+ end
79313
+ function CIRCLE:AllOfGroupInRadius(group_name,center,radius)
79314
+ center=center or self.CenterVec2
79315
+ radius=radius or self.Radius
79316
+ for _,unit in pairs(GROUP:FindByName(group_name):GetUnits())do
79317
+ if not UTILS.IsInRadius(center,unit:GetVec2(),radius)then
79318
+ return false
79319
+ end
79320
+ end
79321
+ return true
79322
+ end
79323
+ function CIRCLE:GetRandomVec2()
79324
+ local angle=math.random()*2*math.pi
79325
+ local rx=math.random(0,self.Radius)*math.cos(angle)+self.CenterVec2.x
79326
+ local ry=math.random(0,self.Radius)*math.sin(angle)+self.CenterVec2.y
79327
+ return{x=rx,y=ry}
79328
+ end
79329
+ function CIRCLE:GetRandomVec2OnBorder()
79330
+ local angle=math.random()*2*math.pi
79331
+ local rx=self.Radius*math.cos(angle)+self.CenterVec2.x
79332
+ local ry=self.Radius*math.sin(angle)+self.CenterVec2.y
79333
+ return{x=rx,y=ry}
79334
+ end
79335
+ function CIRCLE:GetBoundingBox()
79336
+ local min_x=self.CenterVec2.x-self.Radius
79337
+ local min_y=self.CenterVec2.y-self.Radius
79338
+ local max_x=self.CenterVec2.x+self.Radius
79339
+ local max_y=self.CenterVec2.y+self.Radius
79340
+ return{
79341
+ {x=min_x,y=min_x},{x=max_x,y=min_y},{x=max_x,y=max_y},{x=min_x,y=max_y}
79342
+ }
79343
+ end
79344
+ CUBE={
79345
+ ClassName="CUBE",
79346
+ Points={},
79347
+ Coords={}
79348
+ }
79349
+ function CUBE:New(p1,p2,p3,p4,p5,p6,p7,p8)
79350
+ local self=BASE:Inherit(self,SHAPE_BASE)
79351
+ self.Points={p1,p2,p3,p4,p5,p6,p7,p8}
79352
+ for _,point in spairs(self.Points)do
79353
+ table.insert(self.Coords,COORDINATE:NewFromVec3(point))
79354
+ end
79355
+ return self
79356
+ end
79357
+ function CUBE:GetCenter()
79358
+ local center={x=0,y=0,z=0}
79359
+ for _,point in pairs(self.Points)do
79360
+ center.x=center.x+point.x
79361
+ center.y=center.y+point.y
79362
+ center.z=center.z+point.z
79363
+ end
79364
+ center.x=center.x/8
79365
+ center.y=center.y/8
79366
+ center.z=center.z/8
79367
+ return center
79368
+ end
79369
+ function CUBE:ContainsPoint(point,cube_points)
79370
+ cube_points=cube_points or self.Points
79371
+ local min_x,min_y,min_z=math.huge,math.huge,math.huge
79372
+ local max_x,max_y,max_z=-math.huge,-math.huge,-math.huge
79373
+ for _,p in ipairs(cube_points)do
79374
+ if p.x<min_x then min_x=p.x end
79375
+ if p.y<min_y then min_y=p.y end
79376
+ if p.z<min_z then min_z=p.z end
79377
+ if p.x>max_x then max_x=p.x end
79378
+ if p.y>max_y then max_y=p.y end
79379
+ if p.z>max_z then max_z=p.z end
79380
+ end
79381
+ 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
79382
+ end
79383
+ LINE={
79384
+ ClassName="LINE",
79385
+ Points={},
79386
+ Coords={},
79387
+ }
79388
+ function LINE:FindOnMap(line_name)
79389
+ local self=BASE:Inherit(self,SHAPE_BASE:FindOnMap(line_name))
79390
+ for _,layer in pairs(env.mission.drawings.layers)do
79391
+ for _,object in pairs(layer["objects"])do
79392
+ if object["name"]==line_name then
79393
+ if object["primitiveType"]=="Line"then
79394
+ for _,point in UTILS.spairs(object["points"])do
79395
+ local p={x=object["mapX"]+point["x"],
79396
+ y=object["mapY"]+point["y"]}
79397
+ local coord=COORDINATE:NewFromVec2(p)
79398
+ table.insert(self.Points,p)
79399
+ table.insert(self.Coords,coord)
79400
+ end
79401
+ end
79402
+ end
79403
+ end
79404
+ end
79405
+ self:I(#self.Points)
79406
+ if#self.Points==0 then
79407
+ return nil
79408
+ end
79409
+ self.MarkIDs={}
79410
+ return self
79411
+ end
79412
+ function LINE:Find(shape_name)
79413
+ return _DATABASE:FindShape(shape_name)
79414
+ end
79415
+ function LINE:New(...)
79416
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
79417
+ self.Points={...}
79418
+ self:I(self.Points)
79419
+ for _,point in UTILS.spairs(self.Points)do
79420
+ table.insert(self.Coords,COORDINATE:NewFromVec2(point))
79421
+ end
79422
+ return self
79423
+ end
79424
+ function LINE:NewFromCircle(center_point,radius,angle_degrees)
79425
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
79426
+ self.CenterVec2=center_point
79427
+ local angleRadians=math.rad(angle_degrees)
79428
+ local point1={
79429
+ x=center_point.x+radius*math.cos(angleRadians),
79430
+ y=center_point.y+radius*math.sin(angleRadians)
79431
+ }
79432
+ local point2={
79433
+ x=center_point.x+radius*math.cos(angleRadians+math.pi),
79434
+ y=center_point.y+radius*math.sin(angleRadians+math.pi)
79435
+ }
79436
+ for _,point in pairs{point1,point2}do
79437
+ table.insert(self.Points,point)
79438
+ table.insert(self.Coords,COORDINATE:NewFromVec2(point))
79439
+ end
79440
+ return self
79441
+ end
79442
+ function LINE:Coordinates()
79443
+ return self.Coords
79444
+ end
79445
+ function LINE:GetStartCoordinate()
79446
+ return self.Coords[1]
79447
+ end
79448
+ function LINE:GetEndCoordinate()
79449
+ return self.Coords[#self.Coords]
79450
+ end
79451
+ function LINE:GetStartPoint()
79452
+ return self.Points[1]
79453
+ end
79454
+ function LINE:GetEndPoint()
79455
+ return self.Points[#self.Points]
79456
+ end
79457
+ function LINE:GetLength()
79458
+ local total_length=0
79459
+ for i=1,#self.Points-1 do
79460
+ local x1,y1=self.Points[i]["x"],self.Points[i]["y"]
79461
+ local x2,y2=self.Points[i+1]["x"],self.Points[i+1]["y"]
79462
+ local segment_length=math.sqrt((x2-x1)^2+(y2-y1)^2)
79463
+ total_length=total_length+segment_length
79464
+ end
79465
+ return total_length
79466
+ end
79467
+ function LINE:GetRandomPoint(points)
79468
+ points=points or self.Points
79469
+ local rand=math.random()
79470
+ local random_x=points[1].x+rand*(points[2].x-points[1].x)
79471
+ local random_y=points[1].y+rand*(points[2].y-points[1].y)
79472
+ return{x=random_x,y=random_y}
79473
+ end
79474
+ function LINE:GetHeading(points)
79475
+ points=points or self.Points
79476
+ local angle=math.atan2(points[2].y-points[1].y,points[2].x-points[1].x)
79477
+ angle=math.deg(angle)
79478
+ if angle<0 then
79479
+ angle=angle+360
79480
+ end
79481
+ return angle
79482
+ end
79483
+ function LINE:GetIndividualParts()
79484
+ local parts={}
79485
+ if#self.Points==2 then
79486
+ parts={self}
79487
+ end
79488
+ for i=1,#self.Points-1 do
79489
+ local p1=self.Points[i]
79490
+ local p2=self.Points[i%#self.Points+1]
79491
+ table.add(parts,LINE:New(p1,p2))
79492
+ end
79493
+ return parts
79494
+ end
79495
+ function LINE:GetPointsInbetween(amount,start_point,end_point)
79496
+ start_point=start_point or self:GetStartPoint()
79497
+ end_point=end_point or self:GetEndPoint()
79498
+ if amount==0 then return{start_point,end_point}end
79499
+ amount=amount+1
79500
+ local points={}
79501
+ local difference={x=end_point.x-start_point.x,y=end_point.y-start_point.y}
79502
+ local divided={x=difference.x/amount,y=difference.y/amount}
79503
+ for j=0,amount do
79504
+ local part_pos={x=divided.x*j,y=divided.y*j}
79505
+ local point={x=start_point.x+part_pos.x,y=start_point.y+part_pos.y}
79506
+ table.insert(points,point)
79507
+ end
79508
+ return points
79509
+ end
79510
+ function LINE:GetCoordinatesInBetween(amount,start_point,end_point)
79511
+ local coords={}
79512
+ for _,pt in pairs(self:GetPointsInbetween(amount,start_point,end_point))do
79513
+ table.add(coords,COORDINATE:NewFromVec2(pt))
79514
+ end
79515
+ return coords
79516
+ end
79517
+ function LINE:GetRandomPoint(start_point,end_point)
79518
+ start_point=start_point or self:GetStartPoint()
79519
+ end_point=end_point or self:GetEndPoint()
79520
+ local fraction=math.random()
79521
+ local difference={x=end_point.x-start_point.x,y=end_point.y-start_point.y}
79522
+ local part_pos={x=difference.x*fraction,y=difference.y*fraction}
79523
+ local random_point={x=start_point.x+part_pos.x,y=start_point.y+part_pos.y}
79524
+ return random_point
79525
+ end
79526
+ function LINE:GetRandomCoordinate(start_point,end_point)
79527
+ start_point=start_point or self:GetStartPoint()
79528
+ end_point=end_point or self:GetEndPoint()
79529
+ return COORDINATE:NewFromVec2(self:GetRandomPoint(start_point,end_point))
79530
+ end
79531
+ function LINE:GetPointsBetweenAsSineWave(amount,start_point,end_point,frequency,phase,amplitude)
79532
+ amount=amount or 20
79533
+ start_point=start_point or self:GetStartPoint()
79534
+ end_point=end_point or self:GetEndPoint()
79535
+ frequency=frequency or 1
79536
+ phase=phase or 0
79537
+ amplitude=amplitude or 100
79538
+ local points={}
79539
+ local function sine_wave(x)
79540
+ return amplitude*math.sin(2*math.pi*frequency*(x-start_point.x)+phase)
79541
+ end
79542
+ local x=start_point.x
79543
+ local step=(end_point.x-start_point.x)/20
79544
+ for _=1,amount do
79545
+ local y=sine_wave(x)
79546
+ x=x+step
79547
+ table.add(points,{x=x,y=y})
79548
+ end
79549
+ return points
79550
+ end
79551
+ function LINE:GetBoundingBox()
79552
+ 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
79553
+ for i=2,#self.Points do
79554
+ local x,y=self.Points[i].x,self.Points[i].y
79555
+ if x<min_x then
79556
+ min_x=x
79557
+ end
79558
+ if y<min_y then
79559
+ min_y=y
79560
+ end
79561
+ if x>max_x then
79562
+ max_x=x
79563
+ end
79564
+ if y>max_y then
79565
+ max_y=y
79566
+ end
79567
+ end
79568
+ return{
79569
+ {x=min_x,y=min_x},{x=max_x,y=min_y},{x=max_x,y=max_y},{x=min_x,y=max_y}
79570
+ }
79571
+ end
79572
+ function LINE:Draw()
79573
+ for i=1,#self.Coords-1 do
79574
+ local c1=self.Coords[i]
79575
+ local c2=self.Coords[i%#self.Coords+1]
79576
+ table.add(self.MarkIDs,c1:LineToAll(c2))
79577
+ end
79578
+ end
79579
+ function LINE:RemoveDraw()
79580
+ for _,mark_id in pairs(self.MarkIDs)do
79581
+ UTILS.RemoveMark(mark_id)
79582
+ end
79583
+ end
79584
+ OVAL={
79585
+ ClassName="OVAL",
79586
+ MajorAxis=nil,
79587
+ MinorAxis=nil,
79588
+ Angle=0,
79589
+ DrawPoly=nil
79590
+ }
79591
+ function OVAL:FindOnMap(shape_name)
79592
+ local self=BASE:Inherit(self,SHAPE_BASE:FindOnMap(shape_name))
79593
+ for _,layer in pairs(env.mission.drawings.layers)do
79594
+ for _,object in pairs(layer["objects"])do
79595
+ if string.find(object["name"],shape_name,1,true)then
79596
+ if object["polygonMode"]=="oval"then
79597
+ self.CenterVec2={x=object["mapX"],y=object["mapY"]}
79598
+ self.MajorAxis=object["r1"]
79599
+ self.MinorAxis=object["r2"]
79600
+ self.Angle=object["angle"]
79601
+ end
79602
+ end
79603
+ end
79604
+ end
79605
+ return self
79606
+ end
79607
+ function OVAL:Find(shape_name)
79608
+ return _DATABASE:FindShape(shape_name)
79609
+ end
79610
+ function OVAL:New(vec2,major_axis,minor_axis,angle)
79611
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
79612
+ self.CenterVec2=vec2
79613
+ self.MajorAxis=major_axis
79614
+ self.MinorAxis=minor_axis
79615
+ self.Angle=angle or 0
79616
+ return self
79617
+ end
79618
+ function OVAL:GetMajorAxis()
79619
+ return self.MajorAxis
79620
+ end
79621
+ function OVAL:GetMinorAxis()
79622
+ return self.MinorAxis
79623
+ end
79624
+ function OVAL:GetAngle()
79625
+ return self.Angle
79626
+ end
79627
+ function OVAL:SetMajorAxis(value)
79628
+ self.MajorAxis=value
79629
+ end
79630
+ function OVAL:SetMinorAxis(value)
79631
+ self.MinorAxis=value
79632
+ end
79633
+ function OVAL:SetAngle(value)
79634
+ self.Angle=value
79635
+ end
79636
+ function OVAL:ContainsPoint(point)
79637
+ local cos,sin=math.cos,math.sin
79638
+ local dx=point.x-self.CenterVec2.x
79639
+ local dy=point.y-self.CenterVec2.y
79640
+ local rx=dx*cos(self.Angle)+dy*sin(self.Angle)
79641
+ local ry=-dx*sin(self.Angle)+dy*cos(self.Angle)
79642
+ return rx*rx/(self.MajorAxis*self.MajorAxis)+ry*ry/(self.MinorAxis*self.MinorAxis)<=1
79643
+ end
79644
+ function OVAL:GetRandomVec2()
79645
+ local theta=math.rad(self.Angle)
79646
+ local random_point=math.sqrt(math.random())
79647
+ local phi=math.random()*2*math.pi
79648
+ local x_c=random_point*math.cos(phi)
79649
+ local y_c=random_point*math.sin(phi)
79650
+ local x_e=x_c*self.MajorAxis
79651
+ local y_e=y_c*self.MinorAxis
79652
+ local rx=(x_e*math.cos(theta)-y_e*math.sin(theta))+self.CenterVec2.x
79653
+ local ry=(x_e*math.sin(theta)+y_e*math.cos(theta))+self.CenterVec2.y
79654
+ return{x=rx,y=ry}
79655
+ end
79656
+ function OVAL:GetBoundingBox()
79657
+ local min_x=self.CenterVec2.x-self.MajorAxis
79658
+ local min_y=self.CenterVec2.y-self.MinorAxis
79659
+ local max_x=self.CenterVec2.x+self.MajorAxis
79660
+ local max_y=self.CenterVec2.y+self.MinorAxis
79661
+ return{
79662
+ {x=min_x,y=min_x},{x=max_x,y=min_y},{x=max_x,y=max_y},{x=min_x,y=max_y}
79663
+ }
79664
+ end
79665
+ function OVAL:Draw()
79666
+ self.DrawPoly=POLYGON:NewFromPoints(self:PointsOnEdge(20))
79667
+ self.DrawPoly:Draw(true)
79668
+ end
79669
+ function OVAL:RemoveDraw()
79670
+ self.DrawPoly:RemoveDraw()
79671
+ end
79672
+ function OVAL:PointsOnEdge(num_points)
79673
+ num_points=num_points or 20
79674
+ local points={}
79675
+ local dtheta=2*math.pi/num_points
79676
+ for i=0,num_points-1 do
79677
+ local theta=i*dtheta
79678
+ local x=self.CenterVec2.x+self.MajorAxis*math.cos(theta)*math.cos(self.Angle)-self.MinorAxis*math.sin(theta)*math.sin(self.Angle)
79679
+ local y=self.CenterVec2.y+self.MajorAxis*math.cos(theta)*math.sin(self.Angle)+self.MinorAxis*math.sin(theta)*math.cos(self.Angle)
79680
+ table.insert(points,{x=x,y=y})
79681
+ end
79682
+ return points
79683
+ end
79684
+ POLYGON={
79685
+ ClassName="POLYGON",
79686
+ Points={},
79687
+ Coords={},
79688
+ Triangles={},
79689
+ SurfaceArea=0,
79690
+ TriangleMarkIDs={},
79691
+ OutlineMarkIDs={},
79692
+ Angle=nil,
79693
+ Heading=nil
79694
+ }
79695
+ function POLYGON:FindOnMap(shape_name)
79696
+ local self=BASE:Inherit(self,SHAPE_BASE:FindOnMap(shape_name))
79697
+ for _,layer in pairs(env.mission.drawings.layers)do
79698
+ for _,object in pairs(layer["objects"])do
79699
+ if object["name"]==shape_name then
79700
+ if(object["primitiveType"]=="Line"and object["closed"]==true)or(object["polygonMode"]=="free")then
79701
+ for _,point in UTILS.spairs(object["points"])do
79702
+ local p={x=object["mapX"]+point["x"],
79703
+ y=object["mapY"]+point["y"]}
79704
+ local coord=COORDINATE:NewFromVec2(p)
79705
+ self.Points[#self.Points+1]=p
79706
+ self.Coords[#self.Coords+1]=coord
79707
+ end
79708
+ elseif object["polygonMode"]=="rect"then
79709
+ local angle=object["angle"]
79710
+ local half_width=object["width"]/2
79711
+ local half_height=object["height"]/2
79712
+ local p1=UTILS.RotatePointAroundPivot({x=self.CenterVec2.x-half_height,y=self.CenterVec2.y+half_width},self.CenterVec2,angle)
79713
+ local p2=UTILS.RotatePointAroundPivot({x=self.CenterVec2.x+half_height,y=self.CenterVec2.y+half_width},self.CenterVec2,angle)
79714
+ local p3=UTILS.RotatePointAroundPivot({x=self.CenterVec2.x+half_height,y=self.CenterVec2.y-half_width},self.CenterVec2,angle)
79715
+ local p4=UTILS.RotatePointAroundPivot({x=self.CenterVec2.x-half_height,y=self.CenterVec2.y-half_width},self.CenterVec2,angle)
79716
+ self.Points={p1,p2,p3,p4}
79717
+ for _,point in pairs(self.Points)do
79718
+ self.Coords[#self.Coords+1]=COORDINATE:NewFromVec2(point)
79719
+ end
79720
+ elseif object["polygonMode"]=="arrow"then
79721
+ for _,point in UTILS.spairs(object["points"])do
79722
+ local p={x=object["mapX"]+point["x"],
79723
+ y=object["mapY"]+point["y"]}
79724
+ local coord=COORDINATE:NewFromVec2(p)
79725
+ self.Points[#self.Points+1]=p
79726
+ self.Coords[#self.Coords+1]=coord
79727
+ end
79728
+ self.Angle=object["angle"]
79729
+ self.Heading=UTILS.ClampAngle(self.Angle+90)
79730
+ end
79731
+ end
79732
+ end
79733
+ end
79734
+ if#self.Points==0 then
79735
+ return nil
79736
+ end
79737
+ self.CenterVec2=self:GetCentroid()
79738
+ self.Triangles=self:Triangulate()
79739
+ self.SurfaceArea=self:__CalculateSurfaceArea()
79740
+ self.TriangleMarkIDs={}
79741
+ self.OutlineMarkIDs={}
79742
+ return self
79743
+ end
79744
+ function POLYGON:FromZone(zone_name)
79745
+ for _,zone in pairs(env.mission.triggers.zones)do
79746
+ if zone["name"]==zone_name then
79747
+ return POLYGON:New(unpack(zone["verticies"]or{}))
79748
+ end
79749
+ end
79750
+ end
79751
+ function POLYGON:Find(shape_name)
79752
+ return _DATABASE:FindShape(shape_name)
79753
+ end
79754
+ function POLYGON:New(...)
79755
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
79756
+ self.Points={...}
79757
+ self.Coords={}
79758
+ for _,point in UTILS.spairs(self.Points)do
79759
+ table.insert(self.Coords,COORDINATE:NewFromVec2(point))
79760
+ end
79761
+ self.Triangles=self:Triangulate()
79762
+ self.SurfaceArea=self:__CalculateSurfaceArea()
79763
+ return self
79764
+ end
79765
+ function POLYGON:GetCentroid()
79766
+ local function sum(t)
79767
+ local total=0
79768
+ for _,value in pairs(t)do
79769
+ total=total+value
79770
+ end
79771
+ return total
79772
+ end
79773
+ local x_values={}
79774
+ local y_values={}
79775
+ local length=table.length(self.Points)
79776
+ for _,point in pairs(self.Points)do
79777
+ table.insert(x_values,point.x)
79778
+ table.insert(y_values,point.y)
79779
+ end
79780
+ local x=sum(x_values)/length
79781
+ local y=sum(y_values)/length
79782
+ return{
79783
+ ["x"]=x,
79784
+ ["y"]=y
79785
+ }
79786
+ end
79787
+ function POLYGON:GetCoordinates()
79788
+ return self.Coords
79789
+ end
79790
+ function POLYGON:GetStartCoordinate()
79791
+ return self.Coords[1]
79792
+ end
79793
+ function POLYGON:GetEndCoordinate()
79794
+ return self.Coords[#self.Coords]
79795
+ end
79796
+ function POLYGON:GetStartPoint()
79797
+ return self.Points[1]
79798
+ end
79799
+ function POLYGON:GetEndPoint()
79800
+ return self.Points[#self.Points]
79801
+ end
79802
+ function POLYGON:GetPoints()
79803
+ return self.Points
79804
+ end
79805
+ function POLYGON:GetSurfaceArea()
79806
+ return self.SurfaceArea
79807
+ end
79808
+ function POLYGON:GetBoundingBox()
79809
+ 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
79810
+ for i=2,#self.Points do
79811
+ local x,y=self.Points[i].x,self.Points[i].y
79812
+ if x<min_x then
79813
+ min_x=x
79814
+ end
79815
+ if y<min_y then
79816
+ min_y=y
79817
+ end
79818
+ if x>max_x then
79819
+ max_x=x
79820
+ end
79821
+ if y>max_y then
79822
+ max_y=y
79823
+ end
79824
+ end
79825
+ return{
79826
+ {x=min_x,y=min_x},{x=max_x,y=min_y},{x=max_x,y=max_y},{x=min_x,y=max_y}
79827
+ }
79828
+ end
79829
+ function POLYGON:Triangulate(points)
79830
+ points=points or self.Points
79831
+ local triangles={}
79832
+ local function get_orientation(shape_points)
79833
+ local sum=0
79834
+ for i=1,#shape_points do
79835
+ local j=i%#shape_points+1
79836
+ sum=sum+(shape_points[j].x-shape_points[i].x)*(shape_points[j].y+shape_points[i].y)
79837
+ end
79838
+ return sum>=0 and"clockwise"or"counter-clockwise"
79839
+ end
79840
+ local function ensure_clockwise(shape_points)
79841
+ local orientation=get_orientation(shape_points)
79842
+ if orientation=="counter-clockwise"then
79843
+ local reversed={}
79844
+ for i=#shape_points,1,-1 do
79845
+ table.insert(reversed,shape_points[i])
79846
+ end
79847
+ return reversed
79848
+ end
79849
+ return shape_points
79850
+ end
79851
+ local function is_clockwise(p1,p2,p3)
79852
+ local cross_product=(p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x)
79853
+ return cross_product<0
79854
+ end
79855
+ local function divide_recursively(shape_points)
79856
+ if#shape_points==3 then
79857
+ table.insert(triangles,TRIANGLE:New(shape_points[1],shape_points[2],shape_points[3]))
79858
+ elseif#shape_points>3 then
79859
+ for i,p1 in ipairs(shape_points)do
79860
+ local p2=shape_points[(i%#shape_points)+1]
79861
+ local p3=shape_points[(i+1)%#shape_points+1]
79862
+ local triangle=TRIANGLE:New(p1,p2,p3)
79863
+ local is_ear=true
79864
+ if not is_clockwise(p1,p2,p3)then
79865
+ is_ear=false
79866
+ else
79867
+ for _,point in ipairs(shape_points)do
79868
+ if point~=p1 and point~=p2 and point~=p3 and triangle:ContainsPoint(point)then
79869
+ is_ear=false
79870
+ break
79871
+ end
79872
+ end
79873
+ end
79874
+ if is_ear then
79875
+ local is_valid_triangle=true
79876
+ for _,point in ipairs(points)do
79877
+ if point~=p1 and point~=p2 and point~=p3 and triangle:ContainsPoint(point)then
79878
+ is_valid_triangle=false
79879
+ break
79880
+ end
79881
+ end
79882
+ if is_valid_triangle then
79883
+ table.insert(triangles,triangle)
79884
+ local remaining_points={}
79885
+ for j,point in ipairs(shape_points)do
79886
+ if point~=p2 then
79887
+ table.insert(remaining_points,point)
79888
+ end
79889
+ end
79890
+ divide_recursively(remaining_points)
79891
+ break
79892
+ end
79893
+ end
79894
+ end
79895
+ end
79896
+ end
79897
+ points=ensure_clockwise(points)
79898
+ divide_recursively(points)
79899
+ return triangles
79900
+ end
79901
+ function POLYGON:CovarianceMatrix()
79902
+ local cx,cy=self:GetCentroid()
79903
+ local covXX,covYY,covXY=0,0,0
79904
+ for _,p in ipairs(self.points)do
79905
+ covXX=covXX+(p.x-cx)^2
79906
+ covYY=covYY+(p.y-cy)^2
79907
+ covXY=covXY+(p.x-cx)*(p.y-cy)
79908
+ end
79909
+ covXX=covXX/(#self.points-1)
79910
+ covYY=covYY/(#self.points-1)
79911
+ covXY=covXY/(#self.points-1)
79912
+ return covXX,covYY,covXY
79913
+ end
79914
+ function POLYGON:Direction()
79915
+ local covXX,covYY,covXY=self:CovarianceMatrix()
79916
+ local theta=0.5*math.atan2(2*covXY,covXX-covYY)
79917
+ return math.cos(theta),math.sin(theta)
79918
+ end
79919
+ function POLYGON:GetRandomVec2()
79920
+ local weights={}
79921
+ for _,triangle in pairs(self.Triangles)do
79922
+ weights[triangle]=triangle.SurfaceArea/self.SurfaceArea
79923
+ end
79924
+ local random_weight=math.random()
79925
+ local accumulated_weight=0
79926
+ for triangle,weight in pairs(weights)do
79927
+ accumulated_weight=accumulated_weight+weight
79928
+ if accumulated_weight>=random_weight then
79929
+ return triangle:GetRandomVec2()
79930
+ end
79931
+ end
79932
+ end
79933
+ function POLYGON:GetRandomNonWeightedVec2()
79934
+ return self.Triangles[math.random(1,#self.Triangles)]:GetRandomVec2()
79935
+ end
79936
+ function POLYGON:ContainsPoint(point,polygon_points)
79937
+ local x=point.x
79938
+ local y=point.y
79939
+ polygon_points=polygon_points or self.Points
79940
+ local counter=0
79941
+ local num_points=#polygon_points
79942
+ for current_index=1,num_points do
79943
+ local next_index=(current_index%num_points)+1
79944
+ local current_x,current_y=polygon_points[current_index].x,polygon_points[current_index].y
79945
+ local next_x,next_y=polygon_points[next_index].x,polygon_points[next_index].y
79946
+ if((current_y>y)~=(next_y>y))and(x<(next_x-current_x)*(y-current_y)/(next_y-current_y)+current_x)then
79947
+ counter=counter+1
79948
+ end
79949
+ end
79950
+ return counter%2==1
79951
+ end
79952
+ function POLYGON:Draw(include_inner_triangles)
79953
+ include_inner_triangles=include_inner_triangles or false
79954
+ for i=1,#self.Coords do
79955
+ local c1=self.Coords[i]
79956
+ local c2=self.Coords[i%#self.Coords+1]
79957
+ table.add(self.OutlineMarkIDs,c1:LineToAll(c2))
79958
+ end
79959
+ if include_inner_triangles then
79960
+ for _,triangle in ipairs(self.Triangles)do
79961
+ triangle:Draw()
79962
+ end
79963
+ end
79964
+ end
79965
+ function POLYGON:RemoveDraw()
79966
+ for _,triangle in pairs(self.Triangles)do
79967
+ triangle:RemoveDraw()
79968
+ end
79969
+ for _,mark_id in pairs(self.OutlineMarkIDs)do
79970
+ UTILS.RemoveMark(mark_id)
79971
+ end
79972
+ end
79973
+ function POLYGON:__CalculateSurfaceArea()
79974
+ local area=0
79975
+ for _,triangle in pairs(self.Triangles)do
79976
+ area=area+triangle.SurfaceArea
79977
+ end
79978
+ return area
79979
+ end
79980
+ TRIANGLE={
79981
+ ClassName="TRIANGLE",
79982
+ Points={},
79983
+ Coords={},
79984
+ SurfaceArea=0
79985
+ }
79986
+ function TRIANGLE:New(p1,p2,p3)
79987
+ local self=BASE:Inherit(self,SHAPE_BASE:New())
79988
+ self.Points={p1,p2,p3}
79989
+ local center_x=(p1.x+p2.x+p3.x)/3
79990
+ local center_y=(p1.y+p2.y+p3.y)/3
79991
+ self.CenterVec2={x=center_x,y=center_y}
79992
+ for _,pt in pairs({p1,p2,p3})do
79993
+ table.add(self.Coords,COORDINATE:NewFromVec2(pt))
79994
+ end
79995
+ self.SurfaceArea=math.abs((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))*0.5
79996
+ self.MarkIDs={}
79997
+ return self
79998
+ end
79999
+ function TRIANGLE:ContainsPoint(pt,points)
80000
+ points=points or self.Points
80001
+ local function sign(p1,p2,p3)
80002
+ return(p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y)
80003
+ end
80004
+ local d1=sign(pt,self.Points[1],self.Points[2])
80005
+ local d2=sign(pt,self.Points[2],self.Points[3])
80006
+ local d3=sign(pt,self.Points[3],self.Points[1])
80007
+ local has_neg=(d1<0)or(d2<0)or(d3<0)
80008
+ local has_pos=(d1>0)or(d2>0)or(d3>0)
80009
+ return not(has_neg and has_pos)
80010
+ end
80011
+ function TRIANGLE:GetRandomVec2(points)
80012
+ points=points or self.Points
80013
+ local pt={math.random(),math.random()}
80014
+ table.sort(pt)
80015
+ local s=pt[1]
80016
+ local t=pt[2]-pt[1]
80017
+ local u=1-pt[2]
80018
+ return{x=s*points[1].x+t*points[2].x+u*points[3].x,
80019
+ y=s*points[1].y+t*points[2].y+u*points[3].y}
80020
+ end
80021
+ function TRIANGLE:Draw()
80022
+ for i=1,#self.Coords do
80023
+ local c1=self.Coords[i]
80024
+ local c2=self.Coords[i%#self.Coords+1]
80025
+ table.add(self.MarkIDs,c1:LineToAll(c2))
80026
+ end
80027
+ end
80028
+ function TRIANGLE:RemoveDraw()
80029
+ for _,mark_id in pairs(self.MarkIDs)do
80030
+ UTILS.RemoveMark(mark_id)
80031
+ end
80032
+ end
78530
80033
  do
78531
80034
  USERSOUND={
78532
80035
  ClassName="USERSOUND",
@@ -79788,7 +81291,7 @@ end
79788
81291
  function MSRS:SetVoiceProvider(Voice,Provider)
79789
81292
  self:F({Voice=Voice,Provider=Provider})
79790
81293
  self.poptions=self.poptions or{}
79791
- self.poptions[Provider or self:GetProvider()]=Voice
81294
+ self.poptions[Provider or self:GetProvider()].voice=Voice
79792
81295
  return self
79793
81296
  end
79794
81297
  function MSRS:SetVoiceWindows(Voice)
@@ -82636,7 +84139,7 @@ local ActRouteTarget=ProcessUnit:GetProcess("Engaging","RouteToTargetZone")
82636
84139
  return ActRouteTarget:GetZone()
82637
84140
  end
82638
84141
  function TASK_A2G:SetGoalTotal()
82639
- self.GoalTotal=self.TargetSetUnit:Count()
84142
+ self.GoalTotal=self.TargetSetUnit:CountAlive()
82640
84143
  end
82641
84144
  function TASK_A2G:GetGoalTotal()
82642
84145
  return self.GoalTotal
@@ -82649,7 +84152,7 @@ return Distance
82649
84152
  end
82650
84153
  function TASK_A2G:onafterGoal(TaskUnit,From,Event,To)
82651
84154
  local TargetSetUnit=self.TargetSetUnit
82652
- if TargetSetUnit:Count()==0 then
84155
+ if TargetSetUnit:CountAlive()==0 then
82653
84156
  self:Success()
82654
84157
  end
82655
84158
  self:__Goal(-10)
@@ -82667,7 +84170,7 @@ ThreatLevel,ThreatText=self.TargetSetUnit:CalculateThreatLevelA2G()
82667
84170
  end
82668
84171
  self.TaskInfo:AddThreat(ThreatText,ThreatLevel,10,"MOD",true)
82669
84172
  if self.Detection then
82670
- local DetectedItemsCount=self.TargetSetUnit:Count()
84173
+ local DetectedItemsCount=self.TargetSetUnit:CountAlive()
82671
84174
  local ReportTypes=REPORT:New()
82672
84175
  local TargetTypes={}
82673
84176
  for TargetUnitName,TargetUnit in pairs(self.TargetSetUnit:GetSet())do
@@ -82680,7 +84183,7 @@ end
82680
84183
  self.TaskInfo:AddTargetCount(DetectedItemsCount,11,"O",true)
82681
84184
  self.TaskInfo:AddTargets(DetectedItemsCount,ReportTypes:Text(", "),20,"D",true)
82682
84185
  else
82683
- local DetectedItemsCount=self.TargetSetUnit:Count()
84186
+ local DetectedItemsCount=self.TargetSetUnit:CountAlive()
82684
84187
  local DetectedItemsTypes=self.TargetSetUnit:GetTypeNames()
82685
84188
  self.TaskInfo:AddTargetCount(DetectedItemsCount,11,"O",true)
82686
84189
  self.TaskInfo:AddTargets(DetectedItemsCount,DetectedItemsTypes,20,"D",true)