@jtff/miztemplate-lib 3.10.14 → 4.0.1

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,18 +1,21 @@
1
1
  -- *****************************************************************************
2
2
  -- ** AirBoss **
3
3
  -- *********************************************************
4
- function switchCarrierDefCon2(params)
4
+
5
+ -- region AirBossFunctions -----------------------------------------------------
6
+
7
+ function SwitchCarrierDefCon2(params)
5
8
  local carrierName = params[1]
6
9
  local timeMinutes = params[2]
7
10
  local cvUnit = UNIT:FindByName(carrierName)
8
11
  local cvGroup = cvUnit:GetGroup()
9
12
  cvGroup:OptionROE(ENUMS.ROE.WeaponFree):OptionAlarmStateRed()
10
- jtff_log.info(string.format("CSG : %s DEFCON 2 -> ROE = %d", carrierName, ENUMS.ROE.WeaponFree),"AIRBOSS")
13
+ Jtff_log.info(string.format("CSG : %s DEFCON 2 -> ROE = %d", carrierName, ENUMS.ROE.WeaponFree),"AIRBOSS")
11
14
  SCHEDULER:New(
12
15
  nil,
13
16
  function(carrierName)
14
- jtff_log.info(carrierName .. " switchback to DEFCON 4","AIRBOSS")
15
- jtff_log.info(string.format("CSG : %s DEFCON 4 -> ROE = %d", carrierName, ENUMS.ROE.ReturnFire),"AIRBOSS")
17
+ Jtff_log.info(carrierName .. " switchback to DEFCON 4","AIRBOSS")
18
+ Jtff_log.info(string.format("CSG : %s DEFCON 4 -> ROE = %d", carrierName, ENUMS.ROE.ReturnFire),"AIRBOSS")
16
19
  UNIT:FindByName(carrierName):GetGroup():OptionROE(ENUMS.ROE.ReturnFire):OptionAlarmStateRed()
17
20
  end,
18
21
  { carrierName },
@@ -20,34 +23,39 @@ function switchCarrierDefCon2(params)
20
23
  )
21
24
  end
22
25
 
23
- function forceCarrierDefCon4(params)
26
+ function ForceCarrierDefCon4(params)
24
27
  local carrierName = params[1]
25
28
  local cvUnit = UNIT:FindByName(carrierName)
26
29
  local cvGroup = cvUnit:GetGroup()
27
- cvGroup:OptionROE(ENUMS.ROE.WeaponFree):OptionAlarmStateRed()
30
+ cvGroup:OptionROE(ENUMS.ROE.ReturnFire):OptionAlarmStateRed()
28
31
  end
29
32
 
30
- function getCaseTypeFromWeather(CVNCoordinates, recovery_start, recovery_stop)
33
+ --- Get Weather and visibility parameters from a #COORDINATE object and return the case Type based on NATOPS
34
+ -- @param Core.Point#COORDINATE CVNCoordinates Object to get the weather and visibility parameters from
35
+ -- @param #number recovery_start Recovery start time in seconds
36
+ -- @param #number recovery_stop Recovery stop time in seconds
37
+ -- @return #number caseType Case Type based on NATOPS (1 = Good visibility, 2 = Bad visibility in altitude, 3 = Bad visibility)
38
+ function GetCaseTypeFromWeather(CVNCoordinates, recovery_start, recovery_stop)
31
39
  --navyNightCondition : Day by default
32
40
  local navyNightCondition = false
33
41
  if (CVNCoordinates) then
34
42
  if (type(tonumber(CVNCoordinates:GetSunset(true))) ~= "nil" and type(tonumber(CVNCoordinates:GetSunrise(true))) ~= "nil" ) then
35
43
  if ((timer.getAbsTime() >= (tonumber(CVNCoordinates:GetSunset(true)) - 30*60)) or (timer.getAbsTime() <= (tonumber(CVNCoordinates:GetSunrise(true)) + 30*60))) then
36
44
  --Navy Night conditions
37
- jtff_log.info("CASE III weather : Navy Night", "AIRBOSS")
45
+ Jtff_log.info("CASE III weather : Navy Night", "AIRBOSS")
38
46
  navyNightCondition = true
39
47
  end
40
48
  if (recovery_stop) then
41
49
  if (recovery_stop > (tonumber(CVNCoordinates:GetSunset(true)) - 30*60)) then
42
50
  --recovery_stop after Navy SunSet
43
- jtff_log.info("CASE III weather : Recovery ending after Navy SunSet", "AIRBOSS")
51
+ Jtff_log.info("CASE III weather : Recovery ending after Navy SunSet", "AIRBOSS")
44
52
  navyNightCondition = true
45
53
  end
46
54
  end
47
55
  if (recovery_start) then
48
56
  if (recovery_start < (tonumber(CVNCoordinates:GetSunrise(true)) + 30*60)) then
49
57
  --recover_start before Navy SunRise
50
- jtff_log.info("CASE III weather : Recovery starting before Navy SunRise","AIRBOSS")
58
+ Jtff_log.info("CASE III weather : Recovery starting before Navy SunRise","AIRBOSS")
51
59
  navyNightCondition = true
52
60
  end
53
61
  end
@@ -79,7 +87,7 @@ function getCaseTypeFromWeather(CVNCoordinates, recovery_start, recovery_stop)
79
87
  }
80
88
  end
81
89
 
82
- jtff_log.info(string.format("visibility : %i | cloud : base %i density %i | fog %i,%i | dust %i | precpt: %i", visibility, clouds.base, clouds.density, fog.thickness, fog.visibility, dust, clouds.iprecptns),"AIRBOSS")
90
+ Jtff_log.info(string.format("visibility : %i | cloud : base %i density %i | fog %i,%i | dust %i | precpt: %i", visibility, clouds.base, clouds.density, fog.thickness, fog.visibility, dust, clouds.iprecptns),"AIRBOSS")
83
91
  --détermination de minVisibility en fonction des precipitations
84
92
  local minVisibility = (clouds.iprecptns >= 2) and math.floor(visibility/2) or visibility
85
93
  if (weather.enable_fog and fog.thickness > 0) then
@@ -93,36 +101,47 @@ function getCaseTypeFromWeather(CVNCoordinates, recovery_start, recovery_stop)
93
101
  --minVisibility > 5nm we need to check the cloudbase
94
102
  if (clouds.base > UTILS.FeetToMeters(3000)) then
95
103
  --cloud base > 3000ft -> case I
96
- jtff_log.info("CASE I weather","AIRBOSS")
104
+ Jtff_log.info("CASE I weather","AIRBOSS")
97
105
  return 1
98
106
  elseif (clouds.base > UTILS.FeetToMeters(1200)) then
99
107
  --cloud base > 1200ft -> case II
100
- jtff_log.info("CASE II weather","AIRBOSS")
108
+ Jtff_log.info("CASE II weather","AIRBOSS")
101
109
  return 2
102
110
  else
103
111
  --cloud base <= 1200ft -> case III
104
- jtff_log.info("CASE III weather","AIRBOSS")
112
+ Jtff_log.info("CASE III weather","AIRBOSS")
105
113
  return 3
106
114
  end
107
115
  else
108
116
  --minVisibility <= 5 nm -> Case III
109
- jtff_log.info("CASE III weather","AIRBOSS")
117
+ Jtff_log.info("CASE III weather","AIRBOSS")
110
118
  return 3
111
119
  end
112
120
  end
113
121
 
114
- function startRecoveryOnDemand(objAirboss, forced_eventcase)
122
+ function StartRecoveryOnDemand(objAirboss, forced_eventcase, turn_into_wind, durationMinutes)
115
123
  local effectiveeventcase
124
+ local effective_turn_into_wind
125
+ if type(turn_into_wind) == 'boolean' then
126
+ effective_turn_into_wind = turn_into_wind
127
+ else
128
+ effective_turn_into_wind = true
129
+ end
116
130
  local turnBeforeRecoveryDuration = 5
117
- local delayMinutesBeforeRecovery = 10
131
+ local delayMinutesBeforeRecovery = ( effective_turn_into_wind and 10 ) or 5
118
132
  local recoveryStart = UTILS.Round(timer.getAbsTime() + delayMinutesBeforeRecovery *60,0)
119
- local recoveryStop = UTILS.Round(recoveryStart + ((objAirboss.customconfig.recoveryops.ondemand.recovery_duration_minutes or 30) * 60),0)
133
+ local recoveryStop
134
+ if type(durationMinutes) == 'number' then
135
+ recoveryStop = UTILS.Round(recoveryStart + (durationMinutes * 60),0)
136
+ else
137
+ recoveryStop = UTILS.Round(recoveryStart + ((objAirboss.customconfig.recoveryops.ondemand.recovery_duration_minutes or 30) * 60),0)
138
+ end
120
139
  if (forced_eventcase) then
121
140
  --Forcage du case si demandé
122
141
  effectiveeventcase = forced_eventcase
123
142
  else
124
143
  -- Si pas de forcage de case demandé determination par les conditions météo
125
- effectiveeventcase = getCaseTypeFromWeather(
144
+ effectiveeventcase = GetCaseTypeFromWeather(
126
145
  objAirboss:GetCoordinate(),
127
146
  recoveryStart - (turnBeforeRecoveryDuration * 60),
128
147
  recoveryStop
@@ -140,43 +159,705 @@ function startRecoveryOnDemand(objAirboss, forced_eventcase)
140
159
  else
141
160
  objAirboss:SetMaxSectionSize(1)
142
161
  end
162
+ Jtff_log.info(
163
+ string.format(
164
+ "StartRecoveryOnDemand: turn into wind=%s -- event_case=%d -- recoveryStart=%s, recoveryStop=%s",
165
+ tostring(effective_turn_into_wind),
166
+ effectiveeventcase,
167
+ UTILS.SecondsToClock(recoveryStart, false),
168
+ UTILS.SecondsToClock(recoveryStop, false)
169
+ ),
170
+ "AIRBOSS"
171
+ )
143
172
  objAirboss:AddRecoveryWindow(
144
- UTILS.SecondsToClock(recoveryStart, false, false),
145
- UTILS.SecondsToClock(recoveryStop, false, false),
173
+ UTILS.SecondsToClock(recoveryStart, false),
174
+ UTILS.SecondsToClock(recoveryStop, false),
146
175
  effectiveeventcase,
147
176
  objAirboss.customconfig.menurecovery.offset,
148
- true,
177
+ effective_turn_into_wind,
149
178
  objAirboss.customconfig.menurecovery.windondeck,
150
179
  objAirboss.customconfig.menurecovery.uturn
151
180
  )
152
181
  end
153
182
 
154
- function wipeDeckLayout(objAirboss)
183
+ function InitCSGAirbossMenus(airbossObject)
184
+ local menuCoalitionCSGCommands = {}
185
+ local rootMenuObject
186
+ local deckLayoutmenuObject
187
+ menuCoalitionCSGCommands = MenuCoalitionCSGCommands[UTILS.GetCoalitionName(airbossObject:GetCoalition())]
188
+ rootMenuObject = MENU_COALITION:New(
189
+ airbossObject:GetCoalition(),
190
+ airbossObject.customconfig.alias,
191
+ menuCoalitionCSGCommands
192
+ )
193
+ MENU_COALITION_COMMAND:New(
194
+ airbossObject:GetCoalition(),
195
+ "DEFCON 2 - duration 5 minutes",
196
+ rootMenuObject,
197
+ SwitchCarrierDefCon2,
198
+ {
199
+ airbossObject.customconfig.carriername,
200
+ 5
201
+ }
202
+ )
203
+ MENU_COALITION_COMMAND:New(
204
+ airbossObject:GetCoalition(),
205
+ "DEFCON 2 - duration 10 minutes",
206
+ rootMenuObject,
207
+ SwitchCarrierDefCon2,
208
+ {
209
+ airbossObject.customconfig.carriername,
210
+ 10
211
+ }
212
+ )
213
+ MENU_COALITION_COMMAND:New(
214
+ airbossObject:GetCoalition(),
215
+ "Release : DEFCON 4",
216
+ rootMenuObject,
217
+ ForceCarrierDefCon4,
218
+ {
219
+ airbossObject.customconfig.carriername
220
+ }
221
+ )
222
+ if (
223
+ (airbossObject.carriertype == AIRBOSS.CarrierType.ROOSEVELT) or
224
+ (airbossObject.carriertype == AIRBOSS.CarrierType.LINCOLN) or
225
+ (airbossObject.carriertype == AIRBOSS.CarrierType.WASHINGTON) or
226
+ (airbossObject.carriertype == AIRBOSS.CarrierType.TRUMAN)
227
+ ) then
228
+ deckLayoutmenuObject = MENU_COALITION:New(
229
+ airbossObject:GetCoalition(),
230
+ "Deck Layout",
231
+ rootMenuObject
232
+ )
233
+ MENU_COALITION_COMMAND:New(
234
+ airbossObject:GetCoalition(),
235
+ "Clean Layout",
236
+ deckLayoutmenuObject,
237
+ CleanDeckLayout,
238
+ airbossObject
239
+ )
240
+ MENU_COALITION_COMMAND:New(
241
+ airbossObject:GetCoalition(),
242
+ "Flex 3 Spawns",
243
+ deckLayoutmenuObject,
244
+ FlexDeck3SpawnLayout,
245
+ airbossObject
246
+ )
247
+ MENU_COALITION_COMMAND:New(
248
+ airbossObject:GetCoalition(),
249
+ "Flex 7 Spawns",
250
+ deckLayoutmenuObject,
251
+ FlexDeck7SpawnLayout,
252
+ airbossObject
253
+ )
254
+ MENU_COALITION_COMMAND:New(
255
+ airbossObject:GetCoalition(),
256
+ "Launch 7 Spawns",
257
+ deckLayoutmenuObject,
258
+ LaunchDeck7SpawnLayout,
259
+ airbossObject
260
+ )
261
+ MENU_COALITION_COMMAND:New(
262
+ airbossObject:GetCoalition(),
263
+ "Launch 1 Spawn",
264
+ deckLayoutmenuObject,
265
+ LaunchDeck1SpawnLayout,
266
+ airbossObject
267
+ )
268
+ MENU_COALITION_COMMAND:New(
269
+ airbossObject:GetCoalition(),
270
+ "Wipe All",
271
+ deckLayoutmenuObject,
272
+ WipeDeckLayout,
273
+ airbossObject
274
+ )
275
+ end
276
+ if (airbossObject.customconfig.recoveryops.mode == 'ondemand') then
277
+ MENU_COALITION_COMMAND:New(
278
+ airbossObject:GetCoalition(),
279
+ "OnDemand Recovery : will start turning in 5 minutes",
280
+ rootMenuObject,
281
+ StartRecoveryOnDemand,
282
+ airbossObject
283
+ )
284
+ MENU_COALITION_COMMAND:New(
285
+ airbossObject:GetCoalition(),
286
+ "OnDemand Recovery Forced Case I: will start turning in 5 minutes",
287
+ rootMenuObject,
288
+ StartRecoveryOnDemand,
289
+ airbossObject,
290
+ 1
291
+ )
292
+ MENU_COALITION_COMMAND:New(
293
+ airbossObject:GetCoalition(),
294
+ "OnDemand Recovery Forced Case II: will start turning in 5 minutes",
295
+ rootMenuObject,
296
+ StartRecoveryOnDemand,
297
+ airbossObject,
298
+ 2
299
+ )
300
+ MENU_COALITION_COMMAND:New(
301
+ airbossObject:GetCoalition(),
302
+ "OnDemand Recovery Forced Case III: will start turning in 5 minutes",
303
+ rootMenuObject,
304
+ StartRecoveryOnDemand,
305
+ airbossObject,
306
+ 3
307
+ )
308
+ end
309
+ MENU_COALITION_COMMAND:New(
310
+ airbossObject:GetCoalition(),
311
+ "Recovery : close the deck and reset Airboss",
312
+ rootMenuObject,
313
+ ResetAirbossDeck,
314
+ airbossObject
315
+ )
316
+ return rootMenuObject, menuCoalitionCSGCommands, deckLayoutmenuObject
317
+ end
318
+
319
+ function ActivateDL4(customconfig)
320
+ if (customconfig.dl4) then
321
+ local cvUnit = UNIT:FindByName(customconfig.carriername)
322
+ cvUnit:SetCommand(
323
+ {
324
+ id = "ActivateLink4",
325
+ params =
326
+ {
327
+ ["unitId"] = cvUnit:GetID(),
328
+ ["frequency"] = customconfig.dl4.freq * 1000000
329
+ },
330
+ }
331
+ )
332
+ cvUnit:SetCommand(
333
+ {
334
+ id = "ActivateACLS",
335
+ params =
336
+ {
337
+ ["unitId"] = cvUnit:GetID(),
338
+ },
339
+ }
340
+ )
341
+ end
342
+ end
343
+
344
+ --- Generate a RescueHelo mission object.
345
+ -- @param #AirBossConfig airbossconfig configuration object.
346
+ -- @param #boolean manageEscort Manage escort mission creation.
347
+ -- @return #AUFTRAG rescueheloMission RescueHelo mission object, #AIRWING airwing Airwing object.
348
+ function GenerateRescueHeloMission(airbossconfig, manageEscort)
349
+ local generateEscortMission = false
350
+ if manageEscort == true then
351
+ generateEscortMission = true
352
+ end
353
+ local objAirboss = FindAirbossByUnitName(airbossconfig.carriername) or {}
354
+ local airwing = objAirboss.airwing
355
+ local rescueheloMission = AUFTRAG:NewRESCUEHELO(objAirboss.carrier)
356
+ rescueheloMission:SetRepeat(10)
357
+ rescueheloMission:SetReturnToLegion(true)
358
+ rescueheloMission:SetRequiredAssets(1)
359
+ rescueheloMission:SetName(
360
+ string.format(
361
+ "Pedro-%s",
362
+ airbossconfig.alias
363
+ )
364
+ )
365
+ rescueheloMission:SetTeleport(false)
366
+ rescueheloMission:SetRadio(
367
+ airbossconfig.integratedpatrols.rescuehelo.freq,
368
+ radio.modulation.AM
369
+ )
370
+ rescueheloMission:SetEPLRS(true)
371
+ rescueheloMission:SetVerbosity(JTFF_verbosity_levels[JTFF_LOGLEVEL])
372
+ rescueheloMission.additionalData = {
373
+ fuelLowThreshold = 25,
374
+ }
375
+ function rescueheloMission:OnAfterScheduled(From, Event, To)
376
+ local rescueheloOpsGroup = self:GetOpsGroups()[1]
377
+ local airwing = rescueheloOpsGroup:GetAirwing()
378
+ for _, _opsGroup in ipairs(self:GetOpsGroups()) do
379
+ _opsGroup:SetFuelLowThreshold(self.additionalData.fuelLowThreshold)
380
+ _opsGroup:SetFuelCriticalThreshold(self.additionalData.fuelLowThreshold-10)
381
+ _opsGroup:SetFuelLowRefuel(false)
382
+ _opsGroup:SetFuelLowRTB(false)
383
+ _opsGroup:SetFuelCriticalRTB(false)
384
+ _opsGroup:SetDespawnAfterLanding()
385
+ _opsGroup:SetHomebase(_opsGroup:GetAirwing().airboss.carrier:GetName())
386
+ _opsGroup:SetDestinationbase(_opsGroup:GetAirwing().airboss.carrier:GetName())
387
+ function _opsGroup:OnAfterFuelLow(From, Event, To)
388
+ Jtff_log.debug(
389
+ string.format(
390
+ "RescueHelo LowFuel"
391
+ ),
392
+ "AIRBOSS"
393
+ )
394
+ local currenttask=self:GetTaskCurrent()
395
+ currenttask.formation.airbase=self.homebase
396
+ currenttask.formation:RTB()
397
+ end
398
+ function _opsGroup:OnAfterFuelCritical(From, Event, To)
399
+ Jtff_log.debug(
400
+ string.format(
401
+ "RescueHelo CriticalFuel"
402
+ ),
403
+ "AIRBOSS"
404
+ )
405
+ local currenttask=self:GetTaskCurrent()
406
+ currenttask.formation.airbase=self.homebase
407
+ currenttask.formation:RTB()
408
+ end
409
+ end
410
+ end
411
+ return rescueheloMission, airwing
412
+ end
413
+
414
+ --- Generate a Naval AWACS mission object.
415
+ -- @param #AirBossConfig airbossconfig configuration object.
416
+ -- @param #boolean manageEscort Manage escort mission creation.
417
+ -- @return #AUFTRAG navalAwacsMission Naval AWACS mission object, #AIRWING airwing Airwing object.
418
+ function GenerateNavalAwacsMission(airbossconfig, manageEscort)
419
+ local generateEscortMission = false
420
+ if manageEscort == true then
421
+ generateEscortMission = true
422
+ end
423
+ local objAirboss = FindAirbossByUnitName(airbossconfig.carriername) or {}
424
+ local airwing = objAirboss.airwing
425
+ local navalAwacsMission = nil
426
+ if airwing == nil then
427
+ Jtff_log.error(
428
+ string.format(
429
+ "Airwing not found for AirBoss %s, skipping navalAwacs mission generation",
430
+ airbossconfig.alias
431
+ ),
432
+ "AIRBOSS"
433
+ )
434
+ return nil,nil
435
+ else
436
+ navalAwacsMission = AUFTRAG:NewAWACS(
437
+ objAirboss.carrier,
438
+ airbossconfig.integratedpatrols.awacs.racetrack.fl * 100,
439
+ airbossconfig.integratedpatrols.awacs.racetrack.speed,
440
+ nil,
441
+ math.abs(airbossconfig.integratedpatrols.awacs.racetrack.front + airbossconfig.integratedpatrols.awacs.racetrack.back)
442
+ ) or {}
443
+ local offsetAngle
444
+ local offsetDist=math.abs(airbossconfig.integratedpatrols.awacs.racetrack.back)
445
+ if (airbossconfig.integratedpatrols.awacs.racetrack.back >= 0) then
446
+ offsetAngle = 180
447
+ else
448
+ offsetAngle = 0
449
+ end
450
+ local orbitDeltaR = UTILS.NMToMeters(5)
451
+ local offsetVec2={r=UTILS.NMToMeters(offsetDist), phi=offsetAngle}
452
+ navalAwacsMission.orbitOffsetVec2=offsetVec2
453
+ navalAwacsMission.orbitDeltaR=orbitDeltaR
454
+ navalAwacsMission:SetDuration(airbossconfig.integratedpatrols.awacs.missionmaxduration * 60)
455
+ navalAwacsMission:SetRepeat(10)
456
+ navalAwacsMission:SetReturnToLegion(true)
457
+ navalAwacsMission:SetRequiredAssets(1)
458
+ navalAwacsMission:SetName(
459
+ string.format(
460
+ "NavalAwacs-%s",
461
+ airbossconfig.alias
462
+ )
463
+ )
464
+ navalAwacsMission:SetRadio(
465
+ airbossconfig.integratedpatrols.awacs.radio.freq,
466
+ airbossconfig.integratedpatrols.awacs.radio.modulation
467
+ )
468
+ navalAwacsMission:SetTACAN(
469
+ airbossconfig.integratedpatrols.awacs.tacan.channel,
470
+ airbossconfig.integratedpatrols.awacs.tacan.morse,
471
+ nil,
472
+ airbossconfig.integratedpatrols.awacs.tacan.band
473
+ )
474
+ navalAwacsMission:SetEPLRS(true)
475
+ navalAwacsMission:SetEmission(true)
476
+ navalAwacsMission:SetVerbosity(JTFF_verbosity_levels[JTFF_LOGLEVEL])
477
+ -- navalAwacsMission:SetEnableMarkers(objAirboss.carrier:GetCoalition())
478
+ navalAwacsMission.additionalData = {
479
+ minEscort = airbossconfig.integratedpatrols.awacs.nbEscort,
480
+ maxEscort = airbossconfig.integratedpatrols.awacs.nbEscort,
481
+ awacsDuration = airbossconfig.integratedpatrols.awacs.missionmaxduration,
482
+ callsign = airbossconfig.integratedpatrols.awacs.callsign,
483
+ awacsTacan = airbossconfig.integratedpatrols.awacs.tacan,
484
+ awacsFuelLowThreshold = airbossconfig.integratedpatrols.awacs.fuelLowThreshold,
485
+ awacsSpeed = airbossconfig.integratedpatrols.awacs.racetrack.speed,
486
+ }
487
+ function navalAwacsMission:OnAfterScheduled(From, Event, To)
488
+ local navalAwacsOpsGroup = self:GetOpsGroups()[1]
489
+ local airwing = navalAwacsOpsGroup:GetAirwing()
490
+ local airboss_name = airwing.airboss.carrier:GetName()
491
+ navalAwacsOpsGroup:SwitchCallsign(
492
+ self.additionalData.callsign.name,
493
+ self.additionalData.callsign.number
494
+ )
495
+ for _, _opsGroup in ipairs(self:GetOpsGroups()) do
496
+ _opsGroup:SetFuelLowThreshold(self.additionalData.awacsFuelLowThreshold)
497
+ _opsGroup:SetFuelCriticalThreshold(self.additionalData.awacsFuelLowThreshold-10)
498
+ _opsGroup:SetFuelLowRefuel(true)
499
+ _opsGroup:SetFuelLowRTB(true)
500
+ _opsGroup:SetFuelCriticalRTB(true)
501
+ _opsGroup:SetDespawnAfterLanding()
502
+ _opsGroup:SetHomebase(
503
+ AIRBASE:FindByName(airboss_name)
504
+ )
505
+ _opsGroup:SetAirboss(
506
+ FindAirbossByUnitName(airboss_name)
507
+ )
508
+ end
509
+ if self.additionalData.maxEscort > 0 and generateEscortMission == true then
510
+ local escortMission = AUFTRAG:NewESCORT(
511
+ navalAwacsOpsGroup,
512
+ {x=250, y=100, z=400},
513
+ 40,
514
+ {'Air'}
515
+ )
516
+ escortMission:SetMissionSpeed(self.additionalData.awacsSpeed)
517
+ escortMission:SetReturnToLegion(true)
518
+ escortMission:SetRequiredAssets(self.additionalData.minEscort, self.additionalData.maxEscort)
519
+ escortMission:SetName(
520
+ string.format("Escort-NavalAwacs-%s", navalAwacsOpsGroup:GetName())
521
+ )
522
+ escortMission:SetEPLRS(true)
523
+ escortMission:SetEmission(true)
524
+ escortMission:SetVerbosity(JTFF_verbosity_levels[JTFF_LOGLEVEL])
525
+ escortMission:SetFormation(ENUMS.Formation.FixedWing.EchelonRight.Close)
526
+ escortMission:SetMissionAltitude(math.floor(math.random(10000, 25000)))
527
+ escortMission:SetMissionWaypointRandomization(UTILS.NMToMeters(math.random(30, 50)))
528
+ escortMission:SetTime(
529
+ 180,
530
+ (self.additionalData.awacsDuration*60)+960
531
+ )
532
+ function escortMission:OnAfterScheduled(From, Event, To)
533
+ for _, opsGroup in ipairs(self:GetOpsGroups()) do
534
+ local airwing = opsGroup:GetAirwing()
535
+ local airboss_name = airwing.airboss.carrier:GetName()
536
+ opsGroup:SetHomebase(
537
+ AIRBASE:FindByName(airboss_name)
538
+ )
539
+ opsGroup:SetAirboss(
540
+ FindAirbossByUnitName(airboss_name)
541
+ )
542
+ opsGroup:SetFuelLowThreshold(30)
543
+ opsGroup:SetFuelCriticalThreshold(25)
544
+ opsGroup:SetJettisonEmptyTanks(false)
545
+ opsGroup:SetFuelLowRefuel(false)
546
+ opsGroup:SetFuelLowRTB(true)
547
+ opsGroup:SetFuelCriticalRTB(true)
548
+ opsGroup:SetDespawnAfterLanding()
549
+ function opsGroup:OnBeforeRTB(From, Event, To, airBase, speedTo, speedHold, speedLand)
550
+ local airwing = self:GetAirwing()
551
+ local airboss = FindAirbossByUnitName(
552
+ airwing.airboss.carrier:GetName()
553
+ ) or {}
554
+ local mission = self:GetMissionCurrent()
555
+ if mission then
556
+ mission:SetRepeat(mission.Nrepeat+1)
557
+ Jtff_log.debug(
558
+ string.format(
559
+ "%s mission is done (RTB requested). Repeating it",
560
+ mission:GetName()
561
+ ),
562
+ "AIRBOSS"
563
+ )
564
+ end
565
+ local nextRecoveryStart, nextRecoveryStop = airboss:GetNextRecoveryTime( true )
566
+ if nextRecoveryStart == -1 then
567
+ nextRecoveryStart = timer.getAbsTime() + 24 * 3600
568
+ end
569
+ if ( not(airboss:IsRecovering()) and nextRecoveryStart > timer.getAbsTime() + 15 * 60) or (airboss:IsRecovering() and nextRecoveryStop < timer.getAbsTime() + 20 * 60) then
570
+ Jtff_log.debug(
571
+ string.format(
572
+ "Airboss %s not recovering any time soon (next is %s) : requesting Ondemand recovery",
573
+ airwing.airboss.alias,
574
+ UTILS.SecondsToClock((nextRecoveryStart), false)
575
+ ),
576
+ "AIRBOSS"
577
+ )
578
+ StartRecoveryOnDemand(airboss, nil, false, UTILS.Round(airboss.customconfig.menurecovery.duration,0))
579
+ else
580
+ Jtff_log.debug(
581
+ string.format(
582
+ "Airboss %s is or will be recovering at %s : %s is going to Marshall in the mean time",
583
+ airwing.airboss.alias,
584
+ UTILS.SecondsToClock((nextRecoveryStart), false),
585
+ self:GetName()
586
+ ),
587
+ "AIRBOSS"
588
+ )
589
+ end
590
+ end
591
+ end
592
+ end
593
+ airwing:AddMission(escortMission)
594
+ self.JTFFEscortmission = escortMission
595
+ end
596
+ end
597
+ end
598
+ return navalAwacsMission, airwing
599
+ end
600
+
601
+ --- Generate a Tanker mission object.
602
+ -- @param #AirBossConfig airbossconfig configuration object.
603
+ -- @param #boolean manageEscort Manage escort mission creation.
604
+ -- @return #AUFTRAG tankermission Recovery Tanker mission object, #AIRWING airwing Airwing object.
605
+ function GenerateRecoveryTankerMission(airbossconfig, manageEscort)
606
+ local generateEscortMission = false
607
+ if manageEscort == true then
608
+ generateEscortMission = true
609
+ end
610
+ local objAirboss = FindAirbossByUnitName(airbossconfig.carriername) or {}
611
+ local airwing = objAirboss.airwing
612
+ local tankermission = nil
613
+ if airwing == nil then
614
+ Jtff_log.error(
615
+ string.format(
616
+ "Airwing not found for AirBoss %s, skipping tanker mission generation",
617
+ airbossconfig.alias
618
+ ),
619
+ "AIRBOSS"
620
+ )
621
+ return nil,nil
622
+ else
623
+ local offsetAngle
624
+ local offsetDist=math.abs(
625
+ airbossconfig.integratedpatrols.tanker.racetrack.back
626
+ )
627
+ if (airbossconfig.integratedpatrols.tanker.racetrack.back >= 0) then
628
+ offsetAngle = 180
629
+ else
630
+ offsetAngle = 0
631
+ end
632
+ tankermission = AUFTRAG:NewRECOVERYTANKER(
633
+ objAirboss.carrier,
634
+ airbossconfig.integratedpatrols.tanker.racetrack.fl * 100,
635
+ airbossconfig.integratedpatrols.tanker.racetrack.speed,
636
+ math.abs(airbossconfig.integratedpatrols.tanker.racetrack.front + airbossconfig.integratedpatrols.tanker.racetrack.back),
637
+ nil,
638
+ offsetDist,
639
+ offsetAngle,
640
+ 5
641
+ )
642
+ tankermission:SetDuration(airbossconfig.integratedpatrols.tanker.missionmaxduration * 60)
643
+ tankermission:SetRepeat(10)
644
+ tankermission:SetReturnToLegion(true)
645
+ tankermission:SetRequiredAssets(1)
646
+ tankermission:SetName(
647
+ string.format(
648
+ "RecoveryTanker-%s",
649
+ airbossconfig.alias
650
+ )
651
+ )
652
+ tankermission:SetRadio(
653
+ airbossconfig.integratedpatrols.tanker.radio.freq,
654
+ airbossconfig.integratedpatrols.tanker.radio.modulation
655
+ )
656
+ tankermission:SetTACAN(
657
+ airbossconfig.integratedpatrols.tanker.tacan.channel,
658
+ airbossconfig.integratedpatrols.tanker.tacan.morse,
659
+ nil,
660
+ airbossconfig.integratedpatrols.tanker.tacan.band
661
+ )
662
+ tankermission:SetEPLRS(true)
663
+ tankermission:SetEmission(false)
664
+ tankermission:SetVerbosity(JTFF_verbosity_levels[JTFF_LOGLEVEL])
665
+ -- tankermission:SetEnableMarkers(objAirboss.carrier:GetCoalition())
666
+ -- if airbossconfig.integratedpatrols.tanker.escorts > 5000 and generateEscortMission == true then
667
+ -- tankermission:SetRequiredEscorts(
668
+ -- airbossconfig.integratedpatrols.tanker.nbEscort,
669
+ -- airbossconfig.integratedpatrols.tanker.nbEscort,
670
+ -- AUFTRAG.Type.ESCORT,
671
+ -- {"Air"},
672
+ -- 35
673
+ -- )
674
+ -- end
675
+ tankermission.additionalData = {
676
+ minEscort = airbossconfig.integratedpatrols.tanker.nbEscort,
677
+ maxEscort = airbossconfig.integratedpatrols.tanker.nbEscort,
678
+ tankerDuration = airbossconfig.integratedpatrols.tanker.missionmaxduration,
679
+ callsign = airbossconfig.integratedpatrols.tanker.callsign,
680
+ tankerTacan = airbossconfig.integratedpatrols.tanker.tacan,
681
+ tankerFuelLowThreshold = airbossconfig.integratedpatrols.tanker.fuelLowThreshold,
682
+ tankerSpeed = airbossconfig.integratedpatrols.tanker.racetrack.speed,
683
+ }
684
+ function tankermission:OnAfterScheduled(From, Event, To)
685
+ local tankerOpsGroup = self:GetOpsGroups()[1]
686
+ local airwing = tankerOpsGroup:GetAirwing()
687
+ tankerOpsGroup:SwitchCallsign(
688
+ self.additionalData.callsign.name,
689
+ self.additionalData.callsign.number
690
+ )
691
+ for _, _opsGroup in ipairs(self:GetOpsGroups()) do
692
+ _opsGroup:SetFuelLowThreshold(self.additionalData.tankerFuelLowThreshold)
693
+ _opsGroup:SetFuelCriticalThreshold(self.additionalData.tankerFuelLowThreshold-10)
694
+ _opsGroup:SetFuelLowRefuel(false)
695
+ _opsGroup:SetFuelLowRTB(true)
696
+ _opsGroup:SetFuelCriticalRTB(true)
697
+ _opsGroup:SetDespawnAfterLanding()
698
+ end
699
+ if self.additionalData.maxEscort > 0 and generateEscortMission == true then
700
+ local escortMission = AUFTRAG:NewESCORT(
701
+ tankerOpsGroup,
702
+ {x=250, y=100, z=400},
703
+ 35,
704
+ {'Air'}
705
+ )
706
+ escortMission:SetReturnToLegion(true)
707
+ escortMission:SetMissionSpeed(self.additionalData.tankerSpeed)
708
+ escortMission:SetRequiredAssets(self.additionalData.minEscort, self.additionalData.maxEscort)
709
+ escortMission:SetName("Escort-RecoveryTanker-%s" .. tankerOpsGroup:GetName())
710
+ escortMission:SetEPLRS(true)
711
+ escortMission:SetEmission(true)
712
+ escortMission:SetVerbosity(JTFF_verbosity_levels[JTFF_LOGLEVEL])
713
+ escortMission:SetFormation(ENUMS.Formation.FixedWing.EchelonRight.Close)
714
+ escortMission:SetMissionAltitude(math.floor(math.random(10000, 25000)))
715
+ escortMission:SetMissionWaypointRandomization(UTILS.NMToMeters(math.random(30, 50)))
716
+ escortMission:SetProhibitAfterburnerExecutePhase()
717
+ escortMission:SetTime(
718
+ 180,
719
+ (self.additionalData.tankerDuration*60)+960
720
+ )
721
+ function escortMission:OnAfterScheduled(From, Event, To)
722
+ for _, opsGroup in ipairs(self:GetOpsGroups()) do
723
+ opsGroup:SetHomebase(
724
+ AIRBASE:FindByName(
725
+ opsGroup:GetAirwing().airboss.carrier:GetName()
726
+ )
727
+ )
728
+ opsGroup:SetAirboss(
729
+ FindAirbossByUnitName(
730
+ opsGroup:GetAirwing().airboss.carrier:GetName()
731
+ )
732
+ )
733
+ opsGroup:SetFuelLowThreshold(30)
734
+ opsGroup:SetFuelCriticalThreshold(20)
735
+ opsGroup:SetFuelLowRefuel(false)
736
+ opsGroup:SetFuelLowRTB(true)
737
+ opsGroup:SetFuelCriticalRTB(true)
738
+ opsGroup:SetJettisonEmptyTanks(false)
739
+ opsGroup:SetJettisonWeapons(false)
740
+ opsGroup:SetDespawnAfterLanding()
741
+ function opsGroup:OnBeforeRTB(From, Event, To, airBase, speedTo, speedHold, speedLand)
742
+ local airwing = self:GetAirwing()
743
+ local airboss = FindAirbossByUnitName(
744
+ airwing.airboss.carrier:GetName()
745
+ ) or {}
746
+ local mission = self:GetMissionCurrent()
747
+ if mission then
748
+ mission:SetRepeat(mission.Nrepeat+1)
749
+ Jtff_log.debug(
750
+ string.format(
751
+ "%s mission is done. Repeating it",
752
+ mission:GetName()
753
+ ),
754
+ "AIRBOSS"
755
+ )
756
+ end
757
+ local nextRecoveryStart, nextRecoveryStop = airboss:GetNextRecoveryTime( true )
758
+ if nextRecoveryStart == -1 then
759
+ nextRecoveryStart = timer.getAbsTime() + 24 * 3600
760
+ end
761
+ if ( not(airboss:IsRecovering()) and nextRecoveryStart > timer.getAbsTime() + 15 * 60) or (airboss:IsRecovering() and nextRecoveryStop < timer.getAbsTime() + 20 * 60) then
762
+ Jtff_log.debug(
763
+ string.format(
764
+ "Airboss %s not recovering any time soon (next is %s) : requesting Ondemand recovery",
765
+ airwing.airboss.alias,
766
+ UTILS.SecondsToClock((nextRecoveryStart), false)
767
+ ),
768
+ "AIRBOSS"
769
+ )
770
+ StartRecoveryOnDemand(airboss, nil, false, UTILS.Round(airboss.customconfig.menurecovery.duration,0))
771
+ else
772
+ Jtff_log.debug(
773
+ string.format(
774
+ "Airboss %s is or will be recovering at %s : %s is going to Marshall in the mean time",
775
+ airwing.airboss.alias,
776
+ UTILS.SecondsToClock((nextRecoveryStart), false),
777
+ self:GetName()
778
+ ),
779
+ "AIRBOSS"
780
+ )
781
+ end
782
+ end
783
+ end
784
+ end
785
+ airwing:AddMission(escortMission)
786
+ self.JTFFEscortmission = escortMission
787
+ end
788
+ end
789
+ function tankermission:OnAfterCancel(From, Event, To)
790
+ Jtff_log.debug(
791
+ string.format(
792
+ "Recovery Tanker %s is done",
793
+ self:GetName()
794
+ ),
795
+ "AIRBOSS"
796
+ )
797
+ local tankerOpsGroup = self:GetOpsGroups()[1]
798
+ local airwing = tankerOpsGroup:GetAirwing()
799
+ local airboss = FindAirbossByUnitName(airwing.airboss.carrier:GetName()) or {}
800
+ local nextRecoveryStart, nextRecoveryStop = airboss:GetNextRecoveryTime( true )
801
+ if nextRecoveryStart == -1 then
802
+ nextRecoveryStart = timer.getAbsTime() + 24 * 3600
803
+ end
804
+ if ( not(airboss:IsRecovering()) and nextRecoveryStart > timer.getAbsTime() + 15 * 60) or (airboss:IsRecovering() and nextRecoveryStop < timer.getAbsTime() + 20 * 60) then
805
+ Jtff_log.debug(
806
+ string.format(
807
+ "Airboss %s not recovering any time soon (next is %s) : requesting Ondemand recovery",
808
+ airwing.airboss.alias,
809
+ UTILS.SecondsToClock((nextRecoveryStart), false)
810
+ ),
811
+ "AIRBOSS"
812
+ )
813
+ StartRecoveryOnDemand(airboss, nil, false, UTILS.Round(airboss.customconfig.menurecovery.duration,0))
814
+ else
815
+ Jtff_log.debug(
816
+ string.format(
817
+ "Airboss %s is or will be recovering at %s : %s is going to Marshall in the mean time",
818
+ airwing.airboss.alias,
819
+ UTILS.SecondsToClock((nextRecoveryStart), false),
820
+ self:GetName()
821
+ ),
822
+ "AIRBOSS"
823
+ )
824
+ end
825
+ airboss.airwing:RemoveMission(self.JTFFEscortmission)
826
+ end
827
+ return tankermission, objAirboss.airwing
828
+ end
829
+ end
830
+
831
+ -- endregion AirBossFunctions
832
+
833
+ -- region AirBossDeckFunctions -------------------------------------------------
834
+
835
+ function WipeDeckLayout(objAirboss)
155
836
  local statObj = coalition.getStaticObjects(objAirboss:GetCoalition())
156
- jtff_log.info(string.format("CSG : %s Wiping Deck Layout...", objAirboss.customconfig.alias),"AIRBOSS")
837
+ Jtff_log.info(string.format("CSG : %s Wiping Deck Layout...", objAirboss.customconfig.alias),"AIRBOSS")
157
838
  for i, static in pairs(statObj) do
158
839
  local staticName = static:getName()
159
840
  if string.match(staticName, objAirboss.customconfig.alias .. "_Deck_Layout_.*") then
160
- jtff_log.debug(string.format("CSG : %s Deleting Static %s.", objAirboss.customconfig.alias, staticName),"AIRBOSS")
841
+ Jtff_log.debug(string.format("CSG : %s Deleting Static %s.", objAirboss.customconfig.alias, staticName),"AIRBOSS")
161
842
  static:destroy()
162
843
  end
163
844
  end
164
- jtff_log.info(string.format("CSG : %s Deck Layout is shining clean", objAirboss.customconfig.alias),"AIRBOSS")
845
+ Jtff_log.info(string.format("CSG : %s Deck Layout is shining clean", objAirboss.customconfig.alias),"AIRBOSS")
165
846
  end
166
847
 
167
- function spawnDeckLayout_Zone(objAirboss, zoneName, layoutData)
168
- jtff_log.info(string.format("CSG : %s Deck Layout " .. zoneName .. " Spawning Layout...", objAirboss.customconfig.alias),"AIRBOSS")
169
- spawnStaticListWithUnitLink(
848
+ function SpawnDeckLayout_Zone(objAirboss, zoneName, layoutData)
849
+ Jtff_log.info(string.format("CSG : %s Deck Layout " .. zoneName .. " Spawning Layout...", objAirboss.customconfig.alias),"AIRBOSS")
850
+ SpawnStaticListWithUnitLink(
170
851
  layoutData,
171
852
  objAirboss.customconfig.alias .. "_Deck_Layout_" .. zoneName,
172
853
  objAirboss.carrier:GetID(),
173
854
  objAirboss.carrier:GetCountry()
174
855
  )
175
- jtff_log.info(string.format("CSG : %s Deck Layout " .. zoneName .. " is up and ready.", objAirboss.customconfig.alias),"AIRBOSS")
856
+ Jtff_log.info(string.format("CSG : %s Deck Layout " .. zoneName .. " is up and ready.", objAirboss.customconfig.alias),"AIRBOSS")
176
857
  end
177
858
 
178
- function cleanDeckLayout(objAirboss)
179
- wipeDeckLayout(objAirboss)
859
+ function CleanDeckLayout(objAirboss)
860
+ WipeDeckLayout(objAirboss)
180
861
  local lsoLayout = {
181
862
  {
182
863
  ["category"] = "Personnel",
@@ -245,7 +926,7 @@ function cleanDeckLayout(objAirboss)
245
926
  ["type"] = "Carrier LSO Personell 5",
246
927
  },
247
928
  }
248
- spawnDeckLayout_Zone(objAirboss, "LSO", lsoLayout)
929
+ SpawnDeckLayout_Zone(objAirboss, "LSO", lsoLayout)
249
930
  local islandLayout = {
250
931
  {
251
932
  ["livery_id"] = "usn hsm-70",
@@ -303,7 +984,7 @@ function cleanDeckLayout(objAirboss)
303
984
  ["type"] = "E-2C",
304
985
  },
305
986
  }
306
- spawnDeckLayout_Zone(objAirboss, "Island", islandLayout)
987
+ SpawnDeckLayout_Zone(objAirboss, "Island", islandLayout)
307
988
  local fingerLayout = {
308
989
  {
309
990
  ["category"] = "ADEquipment",
@@ -359,10 +1040,10 @@ function cleanDeckLayout(objAirboss)
359
1040
  ["type"] = "us carrier tech",
360
1041
  },
361
1042
  }
362
- spawnDeckLayout_Zone(objAirboss, "Finger", fingerLayout)
1043
+ SpawnDeckLayout_Zone(objAirboss, "Finger", fingerLayout)
363
1044
  local junkyardLayout = {
364
1045
  {
365
- ["livery_id"] = "VF-41 AJ100 1989 by Reflected",
1046
+ ["livery_id"] = "jtff_vf-84_91_206",
366
1047
  ["category"] = "Planes",
367
1048
  ["offsets"] =
368
1049
  {
@@ -448,11 +1129,11 @@ function cleanDeckLayout(objAirboss)
448
1129
  ["type"] = "us carrier tech",
449
1130
  },
450
1131
  }
451
- spawnDeckLayout_Zone(objAirboss, "Junkyard", junkyardLayout)
1132
+ SpawnDeckLayout_Zone(objAirboss, "Junkyard", junkyardLayout)
452
1133
  end
453
1134
 
454
- function flexDeck3SpawnLayout(objAirboss)
455
- flexDeck7SpawnLayout(objAirboss)
1135
+ function FlexDeck3SpawnLayout(objAirboss)
1136
+ FlexDeck7SpawnLayout(objAirboss)
456
1137
  local elev2Layout = {
457
1138
  {
458
1139
  ["livery_id"] = "vaq-137 co 158805",
@@ -488,7 +1169,7 @@ function flexDeck3SpawnLayout(objAirboss)
488
1169
  ["type"] = "FA-18C_hornet",
489
1170
  },
490
1171
  }
491
- spawnDeckLayout_Zone(objAirboss, "Elev2", elev2Layout)
1172
+ SpawnDeckLayout_Zone(objAirboss, "Elev2", elev2Layout)
492
1173
  local elev4Layout = {
493
1174
  {
494
1175
  ["livery_id"] = "jtff_vf-84_91_200",
@@ -534,11 +1215,11 @@ function flexDeck3SpawnLayout(objAirboss)
534
1215
  ["type"] = "AS32-p25",
535
1216
  },
536
1217
  }
537
- spawnDeckLayout_Zone(objAirboss, "Elev4", elev4Layout)
1218
+ SpawnDeckLayout_Zone(objAirboss, "Elev4", elev4Layout)
538
1219
  end
539
1220
 
540
- function flexDeck7SpawnLayout(objAirboss)
541
- cleanDeckLayout(objAirboss)
1221
+ function FlexDeck7SpawnLayout(objAirboss)
1222
+ CleanDeckLayout(objAirboss)
542
1223
  local pointLayout = {
543
1224
  {
544
1225
  ["category"] = "ADEquipment",
@@ -595,7 +1276,7 @@ function flexDeck7SpawnLayout(objAirboss)
595
1276
  ["type"] = "EA_6B",
596
1277
  },
597
1278
  }
598
- spawnDeckLayout_Zone(objAirboss, "Point", pointLayout)
1279
+ SpawnDeckLayout_Zone(objAirboss, "Point", pointLayout)
599
1280
  local cat1Layout = {
600
1281
  {
601
1282
  ["livery_id"] = "JTFF VFA-83 Line",
@@ -664,7 +1345,7 @@ function flexDeck7SpawnLayout(objAirboss)
664
1345
  ["type"] = "FA-18C_hornet",
665
1346
  },
666
1347
  }
667
- spawnDeckLayout_Zone(objAirboss, "Cat1", cat1Layout)
1348
+ SpawnDeckLayout_Zone(objAirboss, "Cat1", cat1Layout)
668
1349
  local patioLayout = {
669
1350
  {
670
1351
  ["livery_id"] = "VF-41 AJ102 1981 base Reflected",
@@ -678,7 +1359,7 @@ function flexDeck7SpawnLayout(objAirboss)
678
1359
  ["type"] = "F-14B",
679
1360
  },
680
1361
  {
681
- ["livery_id"] = "VF-41 AJ105 1989 by Reflected",
1362
+ ["livery_id"] = "jtff_vf-84_91_205",
682
1363
  ["category"] = "Planes",
683
1364
  ["offsets"] =
684
1365
  {
@@ -700,7 +1381,7 @@ function flexDeck7SpawnLayout(objAirboss)
700
1381
  ["type"] = "F-14B",
701
1382
  },
702
1383
  }
703
- spawnDeckLayout_Zone(objAirboss, "Patio", patioLayout)
1384
+ SpawnDeckLayout_Zone(objAirboss, "Patio", patioLayout)
704
1385
  local elev1Layout = {
705
1386
  {
706
1387
  ["livery_id"] = "VFA-87",
@@ -736,7 +1417,7 @@ function flexDeck7SpawnLayout(objAirboss)
736
1417
  ["type"] = "FA-18C_hornet",
737
1418
  },
738
1419
  }
739
- spawnDeckLayout_Zone(objAirboss, "Elev1", elev1Layout)
1420
+ SpawnDeckLayout_Zone(objAirboss, "Elev1", elev1Layout)
740
1421
  local coralLayout = {
741
1422
  {
742
1423
  ["livery_id"] = "usn vrc-40",
@@ -761,11 +1442,11 @@ function flexDeck7SpawnLayout(objAirboss)
761
1442
  ["type"] = "S-3B Tanker",
762
1443
  },
763
1444
  }
764
- spawnDeckLayout_Zone(objAirboss, "Coral", coralLayout)
1445
+ SpawnDeckLayout_Zone(objAirboss, "Coral", coralLayout)
765
1446
  end
766
1447
 
767
- function launchDeck7SpawnLayout(objAirboss)
768
- flexDeck7SpawnLayout(objAirboss)
1448
+ function LaunchDeck7SpawnLayout(objAirboss)
1449
+ FlexDeck7SpawnLayout(objAirboss)
769
1450
  local sternLayout = {
770
1451
  {
771
1452
  ["livery_id"] = "VF-41 AJ101 1981 base Reflected",
@@ -779,7 +1460,7 @@ function launchDeck7SpawnLayout(objAirboss)
779
1460
  ["type"] = "F-14B",
780
1461
  },
781
1462
  {
782
- ["livery_id"] = "jtff_vf-84_91_205",
1463
+ ["livery_id"] = "VF-41 AJ105 1989 by Reflected",
783
1464
  ["category"] = "Planes",
784
1465
  ["offsets"] =
785
1466
  {
@@ -834,14 +1515,14 @@ function launchDeck7SpawnLayout(objAirboss)
834
1515
  ["type"] = "F-14B",
835
1516
  },
836
1517
  }
837
- spawnDeckLayout_Zone(objAirboss, "Stern", sternLayout)
1518
+ SpawnDeckLayout_Zone(objAirboss, "Stern", sternLayout)
838
1519
  end
839
1520
 
840
- function launchDeck1SpawnLayout(objAirboss)
841
- flexDeck3SpawnLayout(objAirboss)
1521
+ function LaunchDeck1SpawnLayout(objAirboss)
1522
+ FlexDeck3SpawnLayout(objAirboss)
842
1523
  local elev3Layout = {
843
1524
  {
844
- ["livery_id"] = "jtff_vf-84_91_206",
1525
+ ["livery_id"] = "VF-41 AJ100 1989 by Reflected",
845
1526
  ["category"] = "Planes",
846
1527
  ["offsets"] =
847
1528
  {
@@ -927,7 +1608,7 @@ function launchDeck1SpawnLayout(objAirboss)
927
1608
  ["type"] = "us carrier tech",
928
1609
  },
929
1610
  }
930
- spawnDeckLayout_Zone(objAirboss, "Elev3", elev3Layout)
1611
+ SpawnDeckLayout_Zone(objAirboss, "Elev3", elev3Layout)
931
1612
  local sternLayout = {
932
1613
  {
933
1614
  ["livery_id"] = "VF-41 AJ101 1981 base Reflected",
@@ -996,33 +1677,822 @@ function launchDeck1SpawnLayout(objAirboss)
996
1677
  ["type"] = "F-14B",
997
1678
  },
998
1679
  }
999
- spawnDeckLayout_Zone(objAirboss, "Stern", sternLayout)
1680
+ SpawnDeckLayout_Zone(objAirboss, "Stern", sternLayout)
1000
1681
  end
1001
1682
 
1002
- function parseAirbossConfigJson(config)
1003
- local json = require('Scripts/json')
1004
- local airbossConfigJson = {
1005
- enable = true,
1006
- }
1007
- local default_radio_freqs = {
1008
- base = 127.300,
1009
- marshall = 127.500,
1010
- lso = 127.400
1011
- }
1012
- local default_alpha_recovery_config = {}
1013
- local default_cyclic_recovery_config = {
1014
- event_duration_minutes = 60,
1015
- event_ia_reserved_minutes = 15,
1683
+ function ResetAirbossDeck(objAirboss, delay)
1684
+ local delay_second = delay or 5
1685
+ Jtff_log.info(string.format("reset all Deck Operations, closing the Deck on %s in %i seconds",objAirboss.customconfig.alias, delay_second),"AIRBOSS")
1686
+ objAirboss:CloseCurrentRecoveryWindow(delay_second)
1687
+ objAirboss:DeleteAllRecoveryWindows(delay_second+1)
1688
+ end
1689
+
1690
+ -- endregion AirBossDeckFunctions
1691
+
1692
+ -- region AirBossConfig --------------------------------------------------------
1693
+
1694
+ -- @type RescueHeloCallsignConfig
1695
+ -- @field #string alias Alias for the rescuehelo.
1696
+ -- @field #number name CallSign name for the rescuehelo.
1697
+ -- @field #number number CallSign number (1-7) for the rescuehelo.
1698
+
1699
+ --- Parse an RescueHelo Callsign config Object.
1700
+ -- @param #JsonObject config Config object to parse
1701
+ -- @param #string parser_name Parser name ("AIRBASE", "AIRBOSS", etc...).
1702
+ -- @return #RescueHeloCallsignConfig rescueHeloCallsignConfigJson Parsed CallSign object
1703
+ function ParseRescueHeloCallsignConfigJson(config, parser_name)
1704
+ local rescueHeloCallsignConfigJson = {}
1705
+ local default_number = 1
1706
+ -- **************************************************************************
1707
+ -- name
1708
+ -- **************************************************************************
1709
+ if type(config.name) == "number" then
1710
+ if table.count_value(CALLSIGN.Aircraft, config.name) > 0 then
1711
+ rescueHeloCallsignConfigJson.name = config.name
1712
+ else
1713
+ Jtff_log.warn("RescueHelo Callsign name is not a valid CallSign name, skipping RescueHelo configuration",
1714
+ parser_name)
1715
+ rescueHeloCallsignConfigJson.name = CALLSIGN.Aircraft.Ford
1716
+ end
1717
+ else
1718
+ Jtff_log.error("RescueHelo Callsign name is not valid, skipping RescueHelo configuration", parser_name)
1719
+ return {}
1720
+ end
1721
+ -- **************************************************************************
1722
+ -- alias
1723
+ -- **************************************************************************
1724
+ if type(config.alias) == "string" then
1725
+ rescueHeloCallsignConfigJson.alias = config.alias
1726
+ else
1727
+ Jtff_log.warn("RescueHelo Callsign alias is not a string, defaulting to RescueHelo name", parser_name)
1728
+ rescueHeloCallsignConfigJson.alias = "Ford"
1729
+ end
1730
+ -- **************************************************************************
1731
+ -- number
1732
+ -- **************************************************************************
1733
+ if type(config.number) == "number" then
1734
+ if config.number >= 1 and config.number <= 7 then
1735
+ rescueHeloCallsignConfigJson.number = config.number
1736
+ else
1737
+ Jtff_log.warn(
1738
+ string.format("RescueHelo Callsign number is not a valid number (1-7), defaulting number to %d", default_number),
1739
+ parser_name)
1740
+ rescueHeloCallsignConfigJson.number = default_number
1741
+ end
1742
+ else
1743
+ Jtff_log.warn(string.format("RescueHelo Callsign number is not a number, defaulting number to %d", default_number),
1744
+ parser_name)
1745
+ rescueHeloCallsignConfigJson.number = default_number
1746
+ end
1747
+ return rescueHeloCallsignConfigJson
1748
+ end
1749
+
1750
+ -- @type AirbossIntegratedNavalAwacsConfig
1751
+ -- @field #boolean enable Enable AWACS integrated patrol.
1752
+ -- @field #boolean nbEscort Number of escort assets.
1753
+ -- @field #boolean autorespawn Enable auto respawn of the awacs.
1754
+ -- @field #number missionmaxduration Maximum duration of the mission in minutes.
1755
+ -- @field #number fuelLowThreshold Fuel warning level in %.
1756
+ -- @field #TacanConfig tacan TACAN configuration.
1757
+ -- @field #RadioConfig radio Radio configuration.
1758
+ -- @field #RelativeRacetrackConfig racetrack Racetrack configuration for the tanker.
1759
+ -- @field #AwacsCallsignConfig callsign Callsign configuration.
1760
+
1761
+ --- Parse a Naval AWACS config Object.
1762
+ -- @param #JsonObject config Config object to parse
1763
+ -- @param #string parser_name Parser name ("AIRBASE", "AIRBOSS", etc...).
1764
+ -- @return #AirbossIntegratedNavalAwacsConfig awacsConfigJson Parsed AWACS configuration object
1765
+ function ParseNavalAwacsConfigJson(config, parser_name)
1766
+ local awacsConfigJson = {}
1767
+ local default_enable = false
1768
+ local default_escorts = 1
1769
+ local default_autorespawn = true
1770
+ local default_missionmaxduration = 180
1771
+ local default_fuelLowThreshold = 30
1772
+ local default_callsign = {
1773
+ name = CALLSIGN.AWACS.Darkstar,
1774
+ alias = "Darkstar",
1775
+ number = 4,
1016
1776
  }
1017
- local dl4_default_freq = 336.000
1018
- local default_infinite_patrol = true
1019
- local default_cca_radius_nm = 60
1020
- local default_max_patterns = 5
1021
- local default_max_stacks = 10
1777
+ -- **************************************************************************
1778
+ -- enable
1779
+ -- **************************************************************************
1780
+ if type(config.enable) == "boolean" then
1781
+ awacsConfigJson.enable = config.enable
1782
+ else
1783
+ Jtff_log.warn(
1784
+ "Tanker enable is not a boolean, defaulting to false",
1785
+ parser_name
1786
+ )
1787
+ awacsConfigJson.enable = default_enable
1788
+ return awacsConfigJson
1789
+ end
1790
+ -- **************************************************************************
1791
+ -- racetrack
1792
+ -- **************************************************************************
1793
+ if type(config.racetrack) == "table" then
1794
+ awacsConfigJson.racetrack = ParseRelativeRacetrackConfigJson(config.racetrack, parser_name)
1795
+ if next(awacsConfigJson.racetrack) == nil then
1796
+ Jtff_log.error("AWACS racetrack is not a valid Racetrack object, skipping AWACS configuration", parser_name)
1797
+ config.enable = false
1798
+ return config
1799
+ end
1800
+ else
1801
+ Jtff_log.error("AWACS racetrack is not a table, skipping AWACS configuration", parser_name)
1802
+ config.enable = false
1803
+ return config
1804
+ end
1805
+ -- **************************************************************************
1806
+ -- nbEscort
1807
+ -- **************************************************************************
1808
+ if type(config.nbEscort) == "number" then
1809
+ awacsConfigJson.nbEscort = config.nbEscort or default_escorts
1810
+ else
1811
+ Jtff_log.warn(
1812
+ string.format(
1813
+ "AWACS escorts is not a number, defaulting to %d",
1814
+ default_escorts
1815
+ ),
1816
+ parser_name
1817
+ )
1818
+ awacsConfigJson.nbEscort = default_escorts
1819
+ end
1820
+ -- **************************************************************************
1821
+ -- autorespawn
1822
+ -- **************************************************************************
1823
+ if type(config.autorespawn) == "boolean" then
1824
+ awacsConfigJson.autorespawn = config.autorespawn or default_autorespawn
1825
+ else
1826
+ Jtff_log.warn(
1827
+ "AWACS autorespawn is not a boolean, defaulting to false",
1828
+ parser_name
1829
+ )
1830
+ awacsConfigJson.autorespawn = default_autorespawn
1831
+ end
1832
+ -- **************************************************************************
1833
+ -- missionmaxduration
1834
+ -- **************************************************************************
1835
+ if type(config.missionmaxduration) == "number" then
1836
+ awacsConfigJson.missionmaxduration = config.missionmaxduration
1837
+ else
1838
+ Jtff_log.warn(
1839
+ string.format("AWACS missionmaxduration is not a number, defaulting to %d", default_missionmaxduration),
1840
+ parser_name)
1841
+ awacsConfigJson.missionmaxduration = default_missionmaxduration
1842
+ end
1843
+ -- **************************************************************************
1844
+ -- tacan
1845
+ -- **************************************************************************
1846
+ if type(config.tacan) == "table" then
1847
+ awacsConfigJson.tacan = ParseTacanConfigJson(config.tacan, parser_name)
1848
+ else
1849
+ Jtff_log.error("AWACS tacan is not a table, skipping AWACS Tacan configuration", parser_name)
1850
+ awacsConfigJson.tacan = {}
1851
+ end
1852
+ -- **************************************************************************
1853
+ -- radio
1854
+ -- **************************************************************************
1855
+ if type(config.radio) == "table" then
1856
+ awacsConfigJson.radio = ParseRadioConfigJson(config.radio, parser_name)
1857
+ if next(awacsConfigJson.radio) == nil then
1858
+ Jtff_log.error("AWACS radio is not a valid Radio object, skipping AWACS configuration", parser_name)
1859
+ config.enable = false
1860
+ return config
1861
+ end
1862
+ else
1863
+ Jtff_log.error("AWACS radio is not a table, skipping AWACS configuration", parser_name)
1864
+ config.enable = false
1865
+ return config
1866
+ end
1867
+ -- **************************************************************************
1868
+ -- fuelLowThreshold
1869
+ -- **************************************************************************
1870
+ if type(config.fuelLowThreshold) == "number" then
1871
+ awacsConfigJson.fuelLowThreshold = config.fuelLowThreshold
1872
+ else
1873
+ Jtff_log.warn(
1874
+ string.format("AWACS fuelLowThreshold is not a number, defaulting to %d %%", default_fuelLowThreshold),
1875
+ parser_name)
1876
+ awacsConfigJson.fuelLowThreshold = default_fuelLowThreshold
1877
+ end
1878
+ -- **************************************************************************
1879
+ -- callsign
1880
+ -- **************************************************************************
1881
+ if type(config.callsign) == "table" then
1882
+ awacsConfigJson.callsign = ParseAwacsCallsignConfigJson(config.callsign, parser_name)
1883
+ if next(awacsConfigJson.callsign) == nil then
1884
+ Jtff_log.warn("AWACS callsign is not a valid Callsign object, defaulting AWACS Callsign configuration", parser_name)
1885
+ awacsConfigJson.callsign = default_callsign
1886
+ end
1887
+ else
1888
+ Jtff_log.warn("AWACS callsign is not a table, skipping AWACS configuration", parser_name)
1889
+ awacsConfigJson.callsign = default_callsign
1890
+ end
1891
+ return awacsConfigJson
1892
+ end
1893
+
1894
+ -- @type AirbossIntegratedTankerConfig
1895
+ -- @field #boolean enable Enable tanker integrated patrol.
1896
+ -- @field #number nbEscort Number of escort assets.
1897
+ -- @field #boolean autorespawn Enable auto respawn of the tanker.
1898
+ -- @field #number missionmaxduration Maximum duration of the mission in minutes.
1899
+ -- @field #number refuelSystem Refueling system (0=boom, 1=probe).
1900
+ -- @field #TacanConfig tacan TACAN configuration.
1901
+ -- @field #RadioConfig radio Radio configuration.
1902
+ -- @field #number fuelLowThreshold Fuel warning level in %.
1903
+ -- @field #RelativeRacetrackConfig racetrack Racetrack configuration for the tanker.
1904
+ -- @field #TankerCallsignConfig callsign Callsign configuration.
1905
+
1906
+ --- Parse a Naval tanker config Object.
1907
+ -- @param #JsonObject config Config object to parse
1908
+ -- @param #string parser_name Parser name ("AIRBASE", "AIRBOSS", etc...).
1909
+ -- @return #AirbossIntegratedTankerConfig tankerConfigJson Parsed tanker configuration object
1910
+ function ParseNavalTankerConfigJson(config, parser_name)
1911
+ local tankerConfigJson = {}
1912
+ local default_enable = false
1913
+ local default_escorts = 0
1914
+ local default_autorespawn = false
1915
+ local default_missionmaxduration = 180
1916
+ local default_fuelLowThreshold = 30
1917
+ local default_refuelSystem = Unit.RefuelingSystem.BOOM_AND_RECEPTACLE
1918
+ -- **************************************************************************
1919
+ -- enable
1920
+ -- **************************************************************************
1921
+ if type(config.enable) == "boolean" then
1922
+ tankerConfigJson.enable = config.enable
1923
+ else
1924
+ Jtff_log.warn(
1925
+ "Tanker enable is not a boolean, defaulting to false",
1926
+ parser_name
1927
+ )
1928
+ tankerConfigJson.enable = default_enable
1929
+ return tankerConfigJson
1930
+ end
1931
+ -- **************************************************************************
1932
+ -- racetrack
1933
+ -- **************************************************************************
1934
+ if type(config.racetrack) == "table" then
1935
+ tankerConfigJson.racetrack = ParseRelativeRacetrackConfigJson(config.racetrack, parser_name)
1936
+ if next(tankerConfigJson.racetrack) == nil then
1937
+ Jtff_log.error("Tanker racetrack is not a valid Racetrack object, skipping tanker configuration", parser_name)
1938
+ config.enable = false
1939
+ return config
1940
+ end
1941
+ else
1942
+ Jtff_log.error("Tanker racetrack is not a table, skipping tanker configuration", parser_name)
1943
+ config.enable = false
1944
+ return config
1945
+ end
1946
+ -- **************************************************************************
1947
+ -- nbEscort
1948
+ -- **************************************************************************
1949
+ if type(config.nbEscort) == "number" then
1950
+ tankerConfigJson.nbEscort = config.nbEscort or default_escorts
1951
+ else
1952
+ Jtff_log.warn(
1953
+ string.format(
1954
+ "Tanker escorts is not a number, defaulting to %d",
1955
+ default_escorts
1956
+ ),
1957
+ parser_name
1958
+ )
1959
+ tankerConfigJson.nbEscort = default_escorts
1960
+ end
1961
+ -- **************************************************************************
1962
+ -- autorespawn
1963
+ -- **************************************************************************
1964
+ if type(config.autorespawn) == "boolean" then
1965
+ tankerConfigJson.autorespawn = config.autorespawn or default_autorespawn
1966
+ else
1967
+ Jtff_log.warn(
1968
+ "Tanker autorespawn is not a boolean, defaulting to false",
1969
+ parser_name
1970
+ )
1971
+ tankerConfigJson.autorespawn = default_autorespawn
1972
+ end
1973
+ -- **************************************************************************
1974
+ -- missionmaxduration
1975
+ -- **************************************************************************
1976
+ if type(config.missionmaxduration) == "number" then
1977
+ tankerConfigJson.missionmaxduration = config.missionmaxduration
1978
+ else
1979
+ Jtff_log.warn(
1980
+ string.format("Tanker missionmaxduration is not a number, defaulting to %d", default_missionmaxduration),
1981
+ parser_name)
1982
+ tankerConfigJson.missionmaxduration = default_missionmaxduration
1983
+ end
1984
+ -- **************************************************************************
1985
+ -- refuelSystem
1986
+ -- **************************************************************************
1987
+ if type(config.refuelSystem) == "number" then
1988
+ tankerConfigJson.refuelSystem = config.refuelSystem or default_refuelSystem
1989
+ else
1990
+ tankerConfigJson.refuelSystem = default_refuelSystem
1991
+ end
1992
+ -- **************************************************************************
1993
+ -- tacan
1994
+ -- **************************************************************************
1995
+ if type(config.tacan) == "table" then
1996
+ tankerConfigJson.tacan = ParseTacanConfigJson(config.tacan, parser_name)
1997
+ if next(tankerConfigJson.tacan) == nil then
1998
+ Jtff_log.error("Tanker tacan is not a valid TACAN object, skipping tanker configuration", parser_name)
1999
+ config.enable = false
2000
+ return config
2001
+ end
2002
+ else
2003
+ Jtff_log.error("Tanker tacan is not a table, skipping tanker configuration", parser_name)
2004
+ config.enable = false
2005
+ return config
2006
+ end
2007
+ -- **************************************************************************
2008
+ -- radio
2009
+ -- **************************************************************************
2010
+ if type(config.radio) == "table" then
2011
+ tankerConfigJson.radio = ParseRadioConfigJson(config.radio, parser_name)
2012
+ if next(tankerConfigJson.radio) == nil then
2013
+ Jtff_log.error("Tanker radio is not a valid Radio object, skipping tanker configuration", parser_name)
2014
+ config.enable = false
2015
+ return config
2016
+ end
2017
+ else
2018
+ Jtff_log.error("Tanker radio is not a table, skipping tanker configuration", parser_name)
2019
+ config.enable = false
2020
+ return config
2021
+ end
2022
+ -- **************************************************************************
2023
+ -- fuelLowThreshold
2024
+ -- **************************************************************************
2025
+ if type(config.fuelLowThreshold) == "number" then
2026
+ tankerConfigJson.fuelLowThreshold = config.fuelLowThreshold
2027
+ else
2028
+ Jtff_log.warn(
2029
+ string.format("Tanker fuelLowThreshold is not a number, defaulting to %d %%", default_fuelLowThreshold),
2030
+ parser_name)
2031
+ tankerConfigJson.fuelLowThreshold = default_fuelLowThreshold
2032
+ end
2033
+ -- **************************************************************************
2034
+ -- callsign
2035
+ -- **************************************************************************
2036
+ if type(config.callsign) == "table" then
2037
+ tankerConfigJson.callsign = ParseTankerCallsignConfigJson(config.callsign, parser_name)
2038
+ if next(tankerConfigJson.callsign) == nil then
2039
+ Jtff_log.error("Tanker callsign is not a valid Callsign object, skipping tanker configuration", parser_name)
2040
+ config.enable = false
2041
+ return config
2042
+ end
2043
+ else
2044
+ Jtff_log.error("Tanker callsign is not a table, skipping tanker configuration", parser_name)
2045
+ config.enable = false
2046
+ return config
2047
+ end
2048
+ return tankerConfigJson
2049
+ end
2050
+
2051
+ -- @type AirbossIntegratedRescueHeloConfig
2052
+ -- @field #boolean enable Enable rescuehelo integrated patrol.
2053
+ -- @field #RadioConfig radio Radio configuration.
2054
+ -- @field #RescueHeloCallsignConfig callsign Callsign configuration.
2055
+
2056
+ --- Parse a Naval rescue Helo config Object.
2057
+ -- @param #JsonObject config Config object to parse
2058
+ -- @param #string parser_name Parser name ("AIRBASE", "AIRBOSS", etc...).
2059
+ -- @return #AirbossIntegratedRescueHeloConfig rescueHeloConfigJson Parsed rescuehelo configuration object
2060
+ function ParseNavalRescueHeloConfigJson(config, parser_name)
2061
+ local rescueHeloConfigJson = {}
2062
+ local default_enable = false
2063
+ local default_radio = {
2064
+ freq = 35.100,
2065
+ modulation = radio.modulation.FM,
2066
+ power = 100,
2067
+ }
2068
+ local default_callsign = {
2069
+ name = CALLSIGN.Aircraft.Ford,
2070
+ alias = "Ford",
2071
+ number = 7,
2072
+ }
2073
+ -- **************************************************************************
2074
+ -- enable
2075
+ -- **************************************************************************
2076
+ if type(config.enable) == "boolean" then
2077
+ rescueHeloConfigJson.enable = config.enable
2078
+ else
2079
+ Jtff_log.warn(
2080
+ "RescueHelo enable is not a boolean, defaulting to false",
2081
+ parser_name
2082
+ )
2083
+ rescueHeloConfigJson.enable = default_enable
2084
+ return rescueHeloConfigJson
2085
+ end
2086
+ -- **************************************************************************
2087
+ -- radio
2088
+ -- **************************************************************************
2089
+ if type(config.radio) == "table" then
2090
+ rescueHeloConfigJson.radio = ParseRadioConfigJson(config.radio, parser_name)
2091
+ if next(rescueHeloConfigJson.radio) == nil then
2092
+ Jtff_log.error("RescueHelo radio is not a valid Radio object, skipping tanker configuration", parser_name)
2093
+ config.enable = false
2094
+ return config
2095
+ end
2096
+ else
2097
+ Jtff_log.warn(
2098
+ string.format(
2099
+ "RescueHelo radio is not a table, defaulting RescueHelo configuration to %.3f MHz %s power %d",
2100
+ default_radio.freq,
2101
+ UTILS.GetModulationName(default_radio.modulation),
2102
+ default_radio.power
2103
+ ),
2104
+ parser_name
2105
+ )
2106
+ rescueHeloConfigJson.radio = default_radio
2107
+ return rescueHeloConfigJson
2108
+ end
2109
+ -- **************************************************************************
2110
+ -- callsign
2111
+ -- **************************************************************************
2112
+ if type(config.callsign) == "table" then
2113
+ rescueHeloConfigJson.callsign = ParseRescueHeloCallsignConfigJson(config.callsign, parser_name)
2114
+ if next(rescueHeloConfigJson.callsign) == nil then
2115
+ Jtff_log.warn(
2116
+ string.format(
2117
+ "RescueHelo callsign is not a table, defaulting RescueHelo callsign configuration to %s-%d-1",
2118
+ CALLSIGN.Aircraft.Ford,
2119
+ "Ford",
2120
+ 7
2121
+ ),
2122
+ parser_name
2123
+ )
2124
+ rescueHeloConfigJson.callsign = default_callsign
2125
+ end
2126
+ else
2127
+ Jtff_log.warn(
2128
+ string.format(
2129
+ "RescueHelo callsign is not a table, defaulting RescueHelo callsign configuration to %s-%d-1",
2130
+ default_callsign.name,
2131
+ default_callsign.number
2132
+ ),
2133
+ parser_name
2134
+ )
2135
+ rescueHeloConfigJson.callsign = default_callsign
2136
+ end
2137
+ return rescueHeloConfigJson
2138
+ end
2139
+ -- @type AirbossIntegratedPatrolsConfig
2140
+ -- @field #AirbossTankerConfig tanker tanker integrated patrol configuration.
2141
+ -- @field #AirbossRescueheloConfig rescuehelo rescuehelo integrated patrol configuration.
2142
+ -- @field #AirbossAwacsConfig awacs awacs integrated patrol configuration.
2143
+
2144
+ --- Parse an naval integrated patrols config Object.
2145
+ -- @param #JsonObject config Config object to parse
2146
+ -- @param #string parser_name Parser name ("AIRBASE", "AIRBOSS", etc...).
2147
+ -- @return #AirbossIntegratedPatrolsConfig integratedPatrolConfigJson Parsed integrated patrols configuration object
2148
+ function ParseIntegratedPatrolConfigJson(config, parser_name)
2149
+ local integratedPatrolConfigJson = {}
2150
+ local default_integratedpatrols = {
2151
+ tanker = {
2152
+ enable = false,
2153
+ },
2154
+ rescuehelo = {
2155
+ enable = false,
2156
+ },
2157
+ awacs = {
2158
+ enable = false,
2159
+ },
2160
+ }
2161
+ -- **************************************************************************
2162
+ -- tanker
2163
+ -- **************************************************************************
2164
+ if type(config.tanker) == "table" then
2165
+ integratedPatrolConfigJson.tanker = ParseNavalTankerConfigJson(config.tanker, parser_name)
2166
+ else
2167
+ Jtff_log.warn(
2168
+ "Tanker integrated patrol configuration is not a table, skipping tanker integrated patrol configuration",
2169
+ parser_name
2170
+ )
2171
+ integratedPatrolConfigJson.tanker = default_integratedpatrols.tanker
2172
+ end
2173
+ -- **************************************************************************
2174
+ -- rescuehelo
2175
+ -- **************************************************************************
2176
+ if type(config.rescuehelo) == "table" then
2177
+ integratedPatrolConfigJson.rescuehelo = ParseNavalRescueHeloConfigJson(config.rescuehelo, parser_name)
2178
+ else
2179
+ Jtff_log.warn(
2180
+ "Rescuehelo integrated patrol configuration is not a table, skipping rescuehelo integrated patrol configuration",
2181
+ parser_name
2182
+ )
2183
+ integratedPatrolConfigJson.rescuehelo = default_integratedpatrols.rescuehelo
2184
+ end
2185
+ -- **************************************************************************
2186
+ -- awacs
2187
+ -- **************************************************************************
2188
+ if type(config.awacs) == "table" then
2189
+ integratedPatrolConfigJson.awacs = ParseNavalAwacsConfigJson(config.awacs, parser_name)
2190
+ else
2191
+ Jtff_log.warn(
2192
+ "AWACS integrated patrol configuration is not a table, skipping AWACS integrated patrol configuration",
2193
+ parser_name
2194
+ )
2195
+ integratedPatrolConfigJson.awacs = default_integratedpatrols.awacs
2196
+ end
2197
+ return integratedPatrolConfigJson
2198
+ end
2199
+
2200
+ -- @type DL4Config
2201
+ -- @field #number freq DL4 frequency.
2202
+
2203
+ --- Parse an DL4 config Object.
2204
+ -- @param #JsonObject config Config object to parse
2205
+ -- @param #string parser_name Parser name ("AIRBASE", "AIRBOSS", etc...).
2206
+ -- @return #DL4Config DL4ConfigJson Parsed DL4Config object
2207
+ function ParseDL4ConfigJson(config, parser_name)
2208
+ local DL4ConfigJson = {}
2209
+ local default_freq = 336.000
2210
+ -- **************************************************************************
2211
+ -- freq
2212
+ -- **************************************************************************
2213
+ if type(config.freq) == "number" then
2214
+ DL4ConfigJson.freq = config.freq or default_freq
2215
+ else
2216
+ Jtff_log.error(
2217
+ string.format(
2218
+ "DL4 frequency is not a number, defaulting to %.3f MHz",
2219
+ default_freq
2220
+ ),
2221
+ parser_name
2222
+ )
2223
+ DL4ConfigJson.freq = default_freq
2224
+ end
2225
+ return DL4ConfigJson
2226
+ end
2227
+
2228
+ -- @type ICLSConfig
2229
+ -- @field #number channel ICLS channel.
2230
+ -- @field #string morse ICLS morse code.
2231
+
2232
+ --- Parse an ICLS config Object.
2233
+ -- @param #JsonObject config Config object to parse
2234
+ -- @param #string parser_name Parser name ("AIRBASE", "AIRBOSS", etc...).
2235
+ -- @return #ICLSConfig ICLSConfigJson Parsed ICLSConfig object
2236
+ function ParseICLSConfigJson(config, parser_name)
2237
+ local ICLSConfigJson = {}
2238
+ local default_channel = 11
2239
+ local default_morse = 'RSVLSO'
2240
+ -- **************************************************************************
2241
+ -- channel
2242
+ -- **************************************************************************
2243
+ ICLSConfigJson.channel = config.channel or default_channel
2244
+ -- **************************************************************************
2245
+ -- morse
2246
+ -- **************************************************************************
2247
+ ICLSConfigJson.morse = config.morse or default_morse
2248
+ return ICLSConfigJson
2249
+ end
2250
+
2251
+ -- @type OnDemandRecoveryConfig
2252
+ -- @field #number recovery_duration_minutes Recovery duration in minutes.
2253
+
2254
+ -- @type CyclicRecoveryConfig
2255
+ -- @field #number event_duration_minutes Event duration in minutes.
2256
+ -- @field #number event_ia_reserved_minutes minutes reserved for IA unit at the begining of the Event.
2257
+
2258
+ -- type AlphaRecoveryEventConfig
2259
+ -- @field #number recovery_start_minutes Recovery start time in minutes.
2260
+ -- @field #number recovery_duration_minutes Recovery duration in minutes.
2261
+
2262
+ -- @type AlphaRecoveryConfig
2263
+ -- @field #AlphaRecoveryEventConfig[] recoveries Alpha Strike recovery operations configuration.
2264
+
2265
+ -- @type RecoveryopsConfig
2266
+ -- @field #string mode Recovery operations mode.
2267
+ -- @field #OnDemandRecoveryConfig ondemand On demand recovery operations configuration.
2268
+ -- @field #AlphaRecoveryConfig alpha Alpha Strike recovery operations configuration.
2269
+ -- @field #CyclicRecoveryConfig cyclic Cyclic recovery operations configuration.
2270
+
2271
+ --- Parse an RecoveryOps config Object.
2272
+ -- @param #JsonObject config Config object to parse
2273
+ -- @param #string parser_name Parser name ("AIRBASE", "AIRBOSS", etc...).
2274
+ -- @return #RecoveryopsConfig recoveryOpsConfigJson Parsed RecoveryopsConfig object
2275
+ function ParseRecoveryOpsConfigJson(config, parser_name)
2276
+ local recoveryOpsConfigJson = {}
2277
+ local default_mode = 'ondemand'
2278
+ local default_ondemand = {
2279
+ recovery_duration_minutes = 45,
2280
+ }
2281
+ local default_alpha_duration = 60
2282
+ local default_cyclic = {
2283
+ event_duration_minutes = 60,
2284
+ event_ia_reserved_minutes = 15,
2285
+ }
2286
+ -- **************************************************************************
2287
+ -- mode
2288
+ -- **************************************************************************
2289
+ if type(config.mode) == "string" then
2290
+ recoveryOpsConfigJson.mode = config.mode
2291
+ else
2292
+ Jtff_log.error(
2293
+ string.format(
2294
+ "RecoveryOps mode is not a string, defaulting to %s mode",
2295
+ default_mode
2296
+ ),
2297
+ parser_name
2298
+ )
2299
+ recoveryOpsConfigJson.mode = default_mode
2300
+ end
2301
+
2302
+ if recoveryOpsConfigJson.mode == 'ondemand' then
2303
+ -- *********************************************************************
2304
+ -- ondemand
2305
+ -- *********************************************************************
2306
+ if type(config.ondemand) == "table" then
2307
+ if type(config.ondemand.recovery_duration_minutes) == "number" then
2308
+ recoveryOpsConfigJson.ondemand = {
2309
+ recovery_duration_minutes = config.ondemand.recovery_duration_minutes,
2310
+ }
2311
+ else
2312
+ Jtff_log.error(
2313
+ string.format(
2314
+ "RecoveryOps ondemand recovery_duration_minutes is not a number, defaulting to %d minutes long events",
2315
+ default_ondemand.recovery_duration_minutes
2316
+ ),
2317
+ parser_name
2318
+ )
2319
+ recoveryOpsConfigJson.ondemand = default_ondemand
2320
+ end
2321
+ else
2322
+ Jtff_log.error(
2323
+ string.format(
2324
+ "RecoveryOps ondemand is not a table, defaulting to %d minutes long events",
2325
+ default_ondemand.recovery_duration_minutes
2326
+ ),
2327
+ parser_name
2328
+ )
2329
+ recoveryOpsConfigJson.ondemand = default_ondemand
2330
+ end
2331
+ elseif recoveryOpsConfigJson.mode == 'alpha' then
2332
+ -- *********************************************************************
2333
+ -- alpha
2334
+ -- *********************************************************************
2335
+ if type(config.alpha) == 'table' then
2336
+ if type(config.recoveryops.alpha.recoveries) ~= 'table' or next(config.recoveryops.alpha.recoveries) == nil then
2337
+ Jtff_log.error(
2338
+ string.format(
2339
+ "no recoveries defined in alpha mode, switching to ondemand mode",
2340
+ config.alias or ""
2341
+ ),
2342
+ parser_name
2343
+ )
2344
+ recoveryOpsConfigJson.mode = 'ondemand'
2345
+ recoveryOpsConfigJson.ondemand = default_ondemand
2346
+ return recoveryOpsConfigJson
2347
+ end
2348
+ local alpha_recoveries = {}
2349
+ for alphaindex, alphaevent in ipairs(config.recoveryops.alpha.recoveries) do
2350
+ if type(alphaevent.recovery_start_minutes) ~= 'number' then
2351
+ Jtff_log.warn(
2352
+ string.format(
2353
+ "No start time for this alpha event, skipping event %i",
2354
+ alphaindex
2355
+ ),
2356
+ parser_name
2357
+ )
2358
+ else
2359
+ table.insert(
2360
+ alpha_recoveries, {
2361
+ recovery_start_minutes = alphaevent.recovery_start_minutes,
2362
+ recovery_duration_minutes = alphaevent.recovery_duration_minutes or default_alpha_duration,
2363
+ }
2364
+ )
2365
+ end
2366
+ end
2367
+ recoveryOpsConfigJson.alpha = {
2368
+ recoveries = alpha_recoveries,
2369
+ }
2370
+ else
2371
+ Jtff_log.error(
2372
+ string.format(
2373
+ "RecoveryOps alpha is not a table, ondemand config"
2374
+ ),
2375
+ parser_name
2376
+ )
2377
+ recoveryOpsConfigJson.mode = 'ondemand'
2378
+ recoveryOpsConfigJson.ondemand = default_ondemand
2379
+ end
2380
+ elseif recoveryOpsConfigJson.mode == 'cyclic' then
2381
+ -- **************************************************************************
2382
+ -- cyclic
2383
+ -- **************************************************************************
2384
+ if type(config.cyclic) == "table" then
2385
+ if type(config.cyclic.event_duration_minutes) == "number" then
2386
+ recoveryOpsConfigJson.cyclic = {
2387
+ event_duration_minutes = config.cyclic.event_duration_minutes or default_cyclic.event_duration_minutes,
2388
+ }
2389
+ else
2390
+ Jtff_log.error(
2391
+ string.format(
2392
+ "RecoveryOps cyclic event_duration_minutes is not a number, defaulting to %d minutes long events",
2393
+ default_cyclic.event_duration_minutes
2394
+ ),
2395
+ parser_name
2396
+ )
2397
+ recoveryOpsConfigJson.cyclic = default_cyclic
2398
+ end
2399
+ if type(config.cyclic.event_ia_reserved_minutes) == "number" then
2400
+ recoveryOpsConfigJson.cyclic.event_ia_reserved_minutes = config.cyclic.event_ia_reserved_minutes or default_cyclic.event_ia_reserved_minutes
2401
+ else
2402
+ Jtff_log.warn(
2403
+ string.format(
2404
+ "RecoveryOps cyclic event_ia_reserved_minutes is not a number, defaulting to %d minutes reserved for IA at the begining of each Event",
2405
+ default_cyclic.event_ia_reserved_minutes
2406
+ ),
2407
+ parser_name
2408
+ )
2409
+ recoveryOpsConfigJson.cyclic.event_ia_reserved_minutes = default_cyclic.event_ia_reserved_minutes
2410
+ end
2411
+ else
2412
+ Jtff_log.warn(
2413
+ string.format(
2414
+ "RecoveryOps cyclic is not a table, defaulting to %d min events with %d min reserved for IA at the begining of each Event",
2415
+ default_cyclic.event_duration_minutes,
2416
+ default_cyclic.event_ia_reserved_minutes
2417
+ ),
2418
+ parser_name
2419
+ )
2420
+ recoveryOpsConfigJson.cyclic = default_cyclic
2421
+ end
2422
+ else
2423
+ Jtff_log.error(
2424
+ string.format(
2425
+ "RecoveryOps mode is not a valid mode, defaulting to %s mode",
2426
+ default_mode
2427
+ ),
2428
+ parser_name
2429
+ )
2430
+ recoveryOpsConfigJson.mode = default_mode
2431
+ recoveryOpsConfigJson.ondemand = default_ondemand
2432
+ end
2433
+ return recoveryOpsConfigJson
2434
+ end
2435
+
2436
+
2437
+ -- @type AirBossConfig
2438
+ -- @field #boolean enable Enable AirBoss creation.
2439
+ -- @field #string carriername Carrier name.
2440
+ -- @field #string alias AirBoss alias.
2441
+ -- @field #RecoveryopsConfig recoveryops Recovery operations configuration.
2442
+ -- @field #tacanConfig tacan TACAN configuration.
2443
+ -- @field #ICLSConfig icls ICLS configuration.
2444
+ -- @field #dl4Config dl4 Datalink 4 configuration.
2445
+ -- @field #boolean infinitepatrol Infinite patrol configuration.
2446
+ -- @field #boolean menumarkzones Menu mark zones configuration.
2447
+ -- @field #boolean menusmokezones Menu smoke zones configuration.
2448
+ -- @field #boolean niceguy Nice guy configuration.
2449
+ -- @field #boolean singlecarrier Single carrier configuration.
2450
+ -- @field #boolean wirecorrection Wire correction configuration.
2451
+ -- @field #boolean handleAI Handle AI aircrafts configuration.
2452
+ -- @field #boolean respawnAI Respawn AI aircrafts configuration.
2453
+ -- @field #number controlarea Control area radius in nautical miles.
2454
+ -- @field #number maxpatterns Maximum number of patterns.
2455
+ -- @field #number maxstacks Maximum number of stacks.
2456
+ -- @field #string difficulty Difficulty level.
2457
+ -- @field #string operationsstatspath Operations status path.
2458
+ -- @field #string operationstrapsheetpath Operationstrapsheet path.
2459
+ -- @field #table menurecovery Menu recovery configuration.
2460
+ -- @field #table srs SRS configuration.
2461
+ -- @field #table freq frequency configuration.
2462
+ -- @field #table releayunit reley unit configuration.
2463
+ -- @field #AirwingConfig airwing Airwing configuration.
2464
+ -- @field #table integratedpatrols Integrated patrols configuration.
2465
+
2466
+
2467
+ -- TODO: specify types and Parsefunction for :
2468
+ -- menurecovery
2469
+ -- srs
2470
+ -- freq
2471
+ -- releayunit
2472
+
2473
+
2474
+ --- Parse AirBoss config Object.
2475
+ -- @param #JsonObject config Config object to parse
2476
+ -- @return #AirBossConfig airbossConfigJson Parsed AirBossConfig object
2477
+ function ParseAirbossConfigJson(config)
2478
+ local json = require('Scripts/json')
2479
+ local parser_name = "AIRBOSS"
2480
+ -- ************************************************************************
2481
+ -- Default Values
2482
+ -- ************************************************************************
2483
+ local default_enable = false
2484
+ local default_radio_freqs = {
2485
+ base = 127.300,
2486
+ marshall = 127.500,
2487
+ lso = 127.400
2488
+ }
2489
+ local default_infinite_patrol = true
2490
+ local default_cca_radius_nm = 60
2491
+ local default_max_patterns = 5
2492
+ local default_max_stacks = 10
1022
2493
  local default_difficulty = AIRBOSS.Difficulty.NORMAL
1023
- local default_coalition = coalition.side.BLUE
1024
2494
  local default_handleAI = true
1025
- local default_respawnAI = true
2495
+ local default_respawnAI = false
1026
2496
  local default_menumarkzones = false
1027
2497
  local default_menusmokezones = false
1028
2498
  local default_menurecovery = {
@@ -1049,234 +2519,250 @@ function parseAirbossConfigJson(config)
1049
2519
  local default_operationsstatspath = "C:/airboss-stats"
1050
2520
  local default_operationstrapsheetpath = "C:/airboss-trapsheets"
1051
2521
  local default_singlecarrier = false
1052
- local default_recoveryops = {
1053
- mode = 'ondemand',
1054
- ondemand = {
1055
- recovery_duration_minutes = 45,
2522
+ local default_integratedpatrols = {
2523
+ tanker = {
2524
+ enable = false,
2525
+ },
2526
+ awacs = {
2527
+ enable = false,
2528
+ },
2529
+ pedro = {
2530
+ enable = false,
1056
2531
  }
1057
2532
  }
2533
+ local airbossConfigJson = {
2534
+ enable = default_enable,
2535
+ }
2536
+ -- ************************************************************************
2537
+ -- enable
2538
+ -- ************************************************************************
2539
+ if type(config.enable) ~= 'boolean' then
2540
+ Jtff_log.warn(string.format("no proper switch enable config defined, skipping config for %s Airboss Object",tostring(default_enable),config.alias or ""),parser_name)
2541
+ airbossConfigJson.enable = false
2542
+ else
2543
+ airbossConfigJson.enable = config.enable
2544
+ end
2545
+ -- ************************************************************************
2546
+ -- carriername
2547
+ -- ************************************************************************
1058
2548
  if type(config.carriername ) == 'nil' then
1059
- jtff_log.error(string.format("no carriername field in config Object, skipping %s Airboss Object",config.alias or ""),"AIRBOSS")
2549
+ Jtff_log.error(
2550
+ string.format(
2551
+ "no carriername field in config Object, skipping %s Airboss Object",
2552
+ config.alias or ""
2553
+ ),
2554
+ parser_name
2555
+ )
1060
2556
  config.enable = false
1061
2557
  return config
1062
2558
  end
1063
2559
  if type(UNIT:FindByName(config.carriername)) == 'nil' then
1064
- jtff_log.error(string.format("Unit %s not found, skipping %s Airboss Object",config.carriername, config.alias or ""),"AIRBOSS")
2560
+ Jtff_log.error(string.format("Unit %s not found, skipping %s Airboss Object",config.carriername, config.alias or ""),parser_name)
1065
2561
  config.enable = false
1066
2562
  return config
1067
2563
  end
1068
2564
  airbossConfigJson.carriername = config.carriername
1069
- airbossConfigJson.alias = config.alias or config.carriername
1070
- if type(config.recoveryops) == 'nil' then
1071
- jtff_log.warn(string.format("no recoveryops Object in config Object, defaulting to ondemand mode for %s Airboss Object",config.alias or ""),"AIRBOSS")
1072
- airbossConfigJson.recoveryops = default_recoveryops
1073
- else
1074
- if type(config.recoveryops.mode) == 'nil' then
1075
- jtff_log.warn(string.format("no recoveryops mode defined, defaulting to ondemand mode for %s Airboss Object",config.alias or ""),"AIRBOSS")
1076
- airbossConfigJson.recoveryops = default_recoveryops
1077
- else
1078
- if (config.recoveryops.mode == "ondemand") then
1079
- if type(config.recoveryops.ondemand) == 'nil' then
1080
- jtff_log.error(string.format("no recoveryops configuration defined in ondemand mode, skipping %s Airboss Object",config.alias or ""),"AIRBOSS")
1081
- config.enable = false
1082
- return config
1083
- end
1084
- airbossConfigJson.recoveryops = {
1085
- mode = 'ondemand',
1086
- ondemand = {
1087
- recovery_duration_minutes = config.recoveryops.ondemand.recovery_duration_minutes or 45,
1088
- }
1089
- }
1090
- elseif (config.recoveryops.mode == "alpha") then
1091
- if type(config.recoveryops.alpha) == 'nil' then
1092
- jtff_log.error(string.format("no recoveryops configuration defined in alpha mode, skipping %s Airboss Object",config.alias or ""),"AIRBOSS")
1093
- config.enable = false
1094
- return config
1095
- end
1096
- local alpha_recoveries = default_alpha_recovery_config
1097
- if type(config.recoveryops.alpha.recoveries) ~= 'table' then
1098
- jtff_log.warn(string.format("no recoveries defined in alpha mode, using empty recoveries config for %s Airboss Object",config.alias or ""),"AIRBOSS")
1099
- end
1100
- for alphaindex, alphaevent in ipairs(config.recoveryops.alpha.recoveries) do
1101
- if type(alphaevent.recovery_start_minutes) ~= 'number' then
1102
- jtff_log.warn(string.format("no start time for this alpha event, skipping event %i for %s Airboss Object",alphaindex, config.alias or ""),"AIRBOSS")
1103
- else
1104
- alpha_recoveries[#alpha_recoveries +1] = {
1105
- recovery_start_minutes = alphaevent.recovery_start_minutes,
1106
- recovery_duration_minutes = alphaevent.recovery_duration_minutes or 60,
1107
- }
1108
- end
1109
- end
1110
- airbossConfigJson.recoveryops = {
1111
- mode = 'alpha',
1112
- alpha = {
1113
- recoveries = alpha_recoveries,
1114
- },
2565
+ -- ************************************************************************
2566
+ -- Alias
2567
+ -- ************************************************************************
1115
2568
 
1116
- }
1117
- elseif (config.recoveryops.mode == "cyclic") then
1118
- if type(config.recoveryops.cyclic) == 'nil'then
1119
- jtff_log.warn(string.format("no cyclic recovery config defined, defaulting to standard for %s Airboss Object",config.alias or ""),"AIRBOSS")
1120
- airbossConfigJson.recoveryops = {
1121
- mode = 'cyclic',
1122
- cyclic = default_cyclic_recovery_config,
1123
- }
1124
- else
1125
- airbossConfigJson.recoveryops = {
1126
- mode = 'cyclic',
1127
- cyclic = {
1128
- event_duration_minutes = config.recoveryops.cyclic.event_duration_minutes or default_cyclic_recovery_config.event_duration_minutes,
1129
- event_ia_reserved_minutes = config.recoveryops.cyclic.event_ia_reserved_minutes or default_cyclic_recovery_config.event_ia_reserved_minutes,
1130
- },
1131
- }
1132
- end
1133
- else
1134
- jtff_log.warn(string.format("no valid recovery mode defined, defaulting to ondemand mode for %s Airboss Object",config.alias or ""),"AIRBOSS")
1135
- airbossConfigJson.recoveryops = {
1136
- mode = 'ondemand',
1137
- ondemand = {
1138
- recovery_duration_minutes = 45,
1139
- }
1140
- }
1141
- end
2569
+ airbossConfigJson.alias = config.alias or config.carriername
2570
+ -- ************************************************************************
2571
+ -- RecoveryOps
2572
+ -- ************************************************************************
2573
+ if type(config.recoveryops) == "table" then
2574
+ airbossConfigJson.recoveryops = ParseRecoveryOpsConfigJson(config.recoveryops, parser_name)
2575
+ if next(airbossConfigJson.recoveryops) == nil then
2576
+ Jtff_log.error("AirBoss RecoveryOps is not a valid RecoveryopsConfig object, skipping AirBoss configuration", parser_name)
2577
+ config.enable = false
2578
+ return config
1142
2579
  end
2580
+ else
2581
+ Jtff_log.error("AirBoss RecoveryOps config is not a table, skipping AirBoss configuration", parser_name)
2582
+ config.enable = false
2583
+ return config
1143
2584
  end
1144
- if type(config.tacan) == 'nil' then
1145
- jtff_log.warn(string.format("no TACAN config defined, disabling TACAN for %s Airboss Object",config.alias or ""),"AIRBOSS")
1146
- airbossConfigJson.tacan = nil
2585
+ -- ************************************************************************
2586
+ -- Tacan
2587
+ -- ************************************************************************
2588
+ if type(config.tacan) == "table" then
2589
+ airbossConfigJson.tacan = ParseTacanConfigJson(config.tacan, parser_name)
2590
+ if next(airbossConfigJson.tacan) == nil then
2591
+ Jtff_log.error("AirBoss TACAN is not a valid TACAN object, skipping AirBoss configuration", parser_name)
2592
+ config.enable = false
2593
+ return config
2594
+ end
1147
2595
  else
1148
- airbossConfigJson.tacan = {
1149
- channel = config.tacan.channel,
1150
- mode = config.tacan.mode,
1151
- morse = config.tacan.morse or string.sub(string.upper(config.carriername),1,3)
1152
- }
2596
+ Jtff_log.error("AirBoss TACAN config is not a table, skipping AirBoss configuration", parser_name)
2597
+ config.enable = false
2598
+ return config
1153
2599
  end
1154
- if type(config.icls) == 'nil' then
1155
- jtff_log.warn(string.format("no ICLS config defined, disabling ICLS for %s Airboss Object",config.alias or ""),"AIRBOSS")
1156
- airbossConfigJson.icls = nil
2600
+ -- ************************************************************************
2601
+ -- ICLS
2602
+ -- ************************************************************************
2603
+ if type(config.icls) == "table" then
2604
+ airbossConfigJson.icls = ParseICLSConfigJson(config.icls, parser_name)
2605
+ if next(airbossConfigJson.icls) == nil then
2606
+ Jtff_log.error("AirBoss ICLS is not a valid ICLS object, skipping AirBoss configuration", parser_name)
2607
+ config.enable = false
2608
+ return config
2609
+ end
1157
2610
  else
1158
- airbossConfigJson.icls = {
1159
- channel = config.icls.channel,
1160
- morse = config.icls.morse or string.sub(string.upper(config.carriername),1,3)
1161
- }
2611
+ Jtff_log.error("AirBoss ICLS config is not a table, skipping AirBoss configuration", parser_name)
2612
+ config.enable = false
2613
+ return config
1162
2614
  end
1163
- if type(config.dl4) == 'nil' then
1164
- jtff_log.warn(string.format("no DL4 config defined, defaulting to %.3f for %s Airboss Object",dl4_default_freq,config.alias or ""),"AIRBOSS")
1165
- airbossConfigJson.dl4 = {
1166
- freq = dl4_default_freq
1167
- }
2615
+ -- ************************************************************************
2616
+ -- Datalink 4
2617
+ -- ************************************************************************
2618
+ if type(config.dl4) == "table" then
2619
+ airbossConfigJson.dl4 = ParseDL4ConfigJson(config.dl4, parser_name)
2620
+ if next(airbossConfigJson.dl4) == nil then
2621
+ Jtff_log.error("AirBoss DL4 is not a valid DL4Config object, skipping AirBoss configuration", parser_name)
2622
+ config.enable = false
2623
+ return config
2624
+ end
1168
2625
  else
1169
- airbossConfigJson.dl4 = {
1170
- freq = config.dl4.freq or dl4_default_freq,
1171
- }
2626
+ Jtff_log.error("AirBoss DL4 config is not a table, skipping AirBoss configuration", parser_name)
2627
+ config.enable = false
2628
+ return config
1172
2629
  end
2630
+ -- ************************************************************************
2631
+ -- InfinitePatrol
2632
+ -- ************************************************************************
1173
2633
  if type(config.infinitepatrol) ~= 'boolean' then
1174
- jtff_log.warn(string.format("no proper switch infinitepatrol config defined, defaulting to %s for %s Airboss Object",tostring(default_infinite_patrol),config.alias or ""),"AIRBOSS")
2634
+ Jtff_log.warn(string.format("no proper switch infinitepatrol config defined, defaulting to %s for %s Airboss Object",tostring(default_infinite_patrol),config.alias or ""),parser_name)
1175
2635
  airbossConfigJson.infinitepatrol = default_infinite_patrol
1176
2636
  else
1177
2637
  airbossConfigJson.infinitepatrol = config.infinitepatrol or default_infinite_patrol
1178
2638
  end
2639
+ -- ************************************************************************
2640
+ -- MenuMarkZones
2641
+ -- ************************************************************************
1179
2642
  if type(config.enable_menumarkzones) ~= 'boolean' then
1180
- jtff_log.warn(string.format("no proper switch enable_menumarkzones config defined, defaulting to %s for %s Airboss Object",tostring(default_menumarkzones),config.alias or ""),"AIRBOSS")
2643
+ Jtff_log.warn(string.format("no proper switch enable_menumarkzones config defined, defaulting to %s for %s Airboss Object",tostring(default_menumarkzones),config.alias or ""),parser_name)
1181
2644
  airbossConfigJson.enable_menumarkzones = default_menumarkzones
1182
2645
  else
1183
2646
  airbossConfigJson.enable_menumarkzones = config.enable_menumarkzones or default_menumarkzones
1184
2647
  end
2648
+ -- ************************************************************************
2649
+ -- MenuSmokeZones
2650
+ -- ************************************************************************
1185
2651
  if type(config.enable_menusmokezones) ~= 'boolean' then
1186
- jtff_log.warn(string.format("no proper switch enable_menusmokezones config defined, defaulting to %s for %s Airboss Object",tostring(default_menusmokezones),config.alias or ""),"AIRBOSS")
2652
+ Jtff_log.warn(string.format("no proper switch enable_menusmokezones config defined, defaulting to %s for %s Airboss Object",tostring(default_menusmokezones),config.alias or ""),parser_name)
1187
2653
  airbossConfigJson.enable_menusmokezones = default_menusmokezones
1188
2654
  else
1189
2655
  airbossConfigJson.enable_menusmokezones = config.enable_menusmokezones or default_menusmokezones
1190
2656
  end
2657
+ -- ************************************************************************
2658
+ -- Airboss Nice Guy
2659
+ -- ************************************************************************
1191
2660
  if type(config.enable_niceguy) ~= 'boolean' then
1192
- jtff_log.warn(string.format("no proper switch enable_niceguy config defined, defaulting to %s for %s Airboss Object",tostring(default_niceguy),config.alias or ""),"AIRBOSS")
2661
+ Jtff_log.warn(string.format("no proper switch enable_niceguy config defined, defaulting to %s for %s Airboss Object",tostring(default_niceguy),config.alias or ""),parser_name)
1193
2662
  airbossConfigJson.enable_niceguy = default_niceguy
1194
2663
  else
1195
2664
  airbossConfigJson.enable_niceguy = config.enable_niceguy or default_niceguy
1196
2665
  end
2666
+ -- ************************************************************************
2667
+ -- Single Carrier
2668
+ -- ************************************************************************
1197
2669
  if type(config.singlecarrier) ~= 'boolean' then
1198
- jtff_log.warn(string.format("no proper switch singlecarrier config defined, defaulting to %s for %s Airboss Object",tostring(default_singlecarrier),config.alias or ""),"AIRBOSS")
2670
+ Jtff_log.warn(string.format("no proper switch singlecarrier config defined, defaulting to %s for %s Airboss Object",tostring(default_singlecarrier),config.alias or ""),parser_name)
1199
2671
  airbossConfigJson.singlecarrier = default_singlecarrier
1200
2672
  else
1201
2673
  airbossConfigJson.singlecarrier = config.singlecarrier or default_singlecarrier
1202
2674
  end
2675
+ -- ************************************************************************
2676
+ -- Multi Player Wire Correction
2677
+ -- ************************************************************************
1203
2678
  if type(config.wirecorrection) ~= 'boolean' then
1204
- jtff_log.warn(string.format("no proper switch wirecorrection config defined, defaulting to %s for %s Airboss Object",tostring(default_wirecorrection),config.alias or ""),"AIRBOSS")
2679
+ Jtff_log.warn(string.format("no proper switch wirecorrection config defined, defaulting to %s for %s Airboss Object",tostring(default_wirecorrection),config.alias or ""),parser_name)
1205
2680
  airbossConfigJson.wirecorrection = default_wirecorrection
1206
2681
  else
1207
2682
  airbossConfigJson.wirecorrection = config.wirecorrection or default_wirecorrection
1208
2683
  end
2684
+ -- ************************************************************************
2685
+ -- Airboss Handle AI aircrafts
2686
+ -- ************************************************************************
1209
2687
  if type(config.handleAI) ~= 'boolean' then
1210
- jtff_log.warn(string.format("no proper switch handleAI config defined, defaulting to %s for %s Airboss Object",tostring(default_handleAI),config.alias or ""),"AIRBOSS")
2688
+ Jtff_log.warn(string.format("no proper switch handleAI config defined, defaulting to %s for %s Airboss Object",tostring(default_handleAI),config.alias or ""),parser_name)
1211
2689
  airbossConfigJson.handleAI = default_handleAI
1212
2690
  else
1213
2691
  airbossConfigJson.handleAI = config.handleAI or default_handleAI
1214
2692
  end
2693
+ -- ************************************************************************
2694
+ -- Airboss Respawn AI aircrafts
2695
+ -- ************************************************************************
1215
2696
  if type(config.respawnAI) ~= 'boolean' then
1216
- jtff_log.warn(string.format("no proper switch respawnAI config defined, defaulting to %s for %s Airboss Object",tostring(default_respawnAI),config.alias or ""),"AIRBOSS")
2697
+ Jtff_log.warn(string.format("no proper switch respawnAI config defined, defaulting to %s for %s Airboss Object",tostring(default_respawnAI),config.alias or ""),parser_name)
1217
2698
  airbossConfigJson.respawnAI = default_respawnAI
1218
2699
  else
1219
2700
  airbossConfigJson.respawnAI = config.respawnAI or default_respawnAI
1220
2701
  end
2702
+ -- ************************************************************************
2703
+ -- Airboss CCA
2704
+ -- ************************************************************************
1221
2705
  if type(config.controlarea) ~= 'number' then
1222
- jtff_log.warn(string.format("no proper controlarea defined, defaulting to %d for %s Airboss Object",default_cca_radius_nm,config.alias or ""),"AIRBOSS")
2706
+ Jtff_log.warn(string.format("no proper controlarea defined, defaulting to %d for %s Airboss Object",default_cca_radius_nm,config.alias or ""),parser_name)
1223
2707
  airbossConfigJson.controlarea = default_cca_radius_nm
1224
2708
  else
1225
2709
  airbossConfigJson.controlarea = config.controlarea or default_cca_radius_nm
1226
2710
  end
2711
+ -- ************************************************************************
2712
+ -- Airboss Max Patterns
2713
+ -- ************************************************************************
1227
2714
  if type(config.maxpatterns) ~= 'number' then
1228
- jtff_log.warn(string.format("no proper maxpatterns defined, defaulting to %d for %s Airboss Object",default_max_patterns,config.alias or ""),"AIRBOSS")
2715
+ Jtff_log.warn(string.format("no proper maxpatterns defined, defaulting to %d for %s Airboss Object",default_max_patterns,config.alias or ""),parser_name)
1229
2716
  airbossConfigJson.maxpatterns = default_max_patterns
1230
2717
  else
1231
2718
  airbossConfigJson.maxpatterns = config.maxpatterns or default_max_patterns
1232
2719
  end
2720
+ -- ************************************************************************
2721
+ -- Airboss Max Stacks
2722
+ -- ************************************************************************
1233
2723
  if type(config.maxstacks) ~= 'number' then
1234
- jtff_log.warn(string.format("no proper maxstacks defined, defaulting to %d for %s Airboss Object",default_max_stacks,config.alias or ""),"AIRBOSS")
2724
+ Jtff_log.warn(string.format("no proper maxstacks defined, defaulting to %d for %s Airboss Object",default_max_stacks,config.alias or ""),parser_name)
1235
2725
  airbossConfigJson.maxstacks = default_max_stacks
1236
2726
  else
1237
2727
  airbossConfigJson.maxstacks = config.maxstacks or default_max_stacks
1238
2728
  end
2729
+ -- ************************************************************************
2730
+ -- Airboss Difficulty
2731
+ -- ************************************************************************
1239
2732
  if type(config.difficulty) ~= 'string' then
1240
- jtff_log.warn(string.format("no proper difficulty defined, defaulting to %s for %s Airboss Object",default_difficulty,config.alias or ""),"AIRBOSS")
2733
+ Jtff_log.warn(string.format("no proper difficulty defined, defaulting to %s for %s Airboss Object",default_difficulty,config.alias or ""),parser_name)
1241
2734
  airbossConfigJson.difficulty = default_difficulty
1242
2735
  else
1243
2736
  if ((config.difficulty ~= AIRBOSS.Difficulty.EASY) and (config.difficulty ~= AIRBOSS.Difficulty.NORMAL) and (config.difficulty ~= AIRBOSS.Difficulty.HARD)) then
1244
- jtff_log.warn(string.format("invalid difficulty string defined, defaulting to %s for %s Airboss Object",default_difficulty,config.alias or ""),"AIRBOSS")
2737
+ Jtff_log.warn(string.format("invalid difficulty string defined, defaulting to %s for %s Airboss Object",default_difficulty,config.alias or ""),parser_name)
1245
2738
  airbossConfigJson.difficulty = default_difficulty
1246
2739
  else
1247
2740
  airbossConfigJson.difficulty = config.difficulty or default_difficulty
1248
2741
  end
1249
2742
  end
2743
+ -- ************************************************************************
2744
+ -- Airboss Operations Status Path
2745
+ -- ************************************************************************
1250
2746
  if type(config.operationsstatspath) ~= 'string' then
1251
- jtff_log.warn(string.format("no proper operationsstatspath defined, defaulting to %s for %s Airboss Object",default_operationsstatspath,config.alias or ""),"AIRBOSS")
2747
+ Jtff_log.warn(string.format("no proper operationsstatspath defined, defaulting to %s for %s Airboss Object",default_operationsstatspath,config.alias or ""),parser_name)
1252
2748
  airbossConfigJson.operationsstatspath = default_operationsstatspath
1253
2749
  else
1254
2750
  airbossConfigJson.operationsstatspath = config.operationsstatspath or default_operationsstatspath
1255
2751
  end
2752
+ -- ************************************************************************
2753
+ -- Airboss Operationstrapsheet Path
2754
+ -- ************************************************************************
1256
2755
  if type(config.operationstrapsheetpath) ~= 'string' then
1257
- jtff_log.warn(string.format("no proper operationstrapsheetpath defined, defaulting to %s for %s Airboss Object",default_operationstrapsheetpath,config.alias or ""),"AIRBOSS")
2756
+ Jtff_log.warn(string.format("no proper operationstrapsheetpath defined, defaulting to %s for %s Airboss Object",default_operationstrapsheetpath,config.alias or ""),parser_name)
1258
2757
  airbossConfigJson.operationstrapsheetpath = default_operationstrapsheetpath
1259
2758
  else
1260
2759
  airbossConfigJson.operationstrapsheetpath = config.operationstrapsheetpath or default_operationstrapsheetpath
1261
2760
  end
1262
- if type(config.recoverytanker) ~= 'string' then
1263
- jtff_log.warn(string.format("no proper recoverytanker defined, skipping recoverytanker config for %s Airboss Object",config.alias or ""),"AIRBOSS")
1264
- elseif type(GROUP:FindByName(config.recoverytanker)) == 'nil' then
1265
- jtff_log.warn(string.format("recoverytanker %s group not found, skipping recoverytanker config for %s Airboss Object",config.recoverytanker, config.alias or ""),"AIRBOSS")
1266
- else
1267
- airbossConfigJson.recoverytanker = config.recoverytanker
1268
- end
1269
- if type(config.coalition) ~= 'string' then
1270
- jtff_log.warn(string.format("no proper coalition defined, defaulting to %s for %s Airboss Object",default_coalition,config.alias or ""),"AIRBOSS")
1271
- airbossConfigJson.coalition = default_coalition
1272
- elseif ((config.coalition ~= coalition.side.BLUE) and (config.coalition ~= coalition.side.RED) and (config.coalition ~= coalition.side.NEUTRAL)) then
1273
- jtff_log.warn(string.format("no proper coalition defined, defaulting to %s for %s Airboss Object",default_coalition,config.alias or ""),"AIRBOSS")
1274
- airbossConfigJson.coalition = default_coalition
1275
- else
1276
- airbossConfigJson.coalition = config.coalition or default_coalition
1277
- end
2761
+ -- ************************************************************************
2762
+ -- Airboss Menu Recovery
2763
+ -- ************************************************************************
1278
2764
  if type(config.menurecovery) ~= 'table' then
1279
- jtff_log.warn(string.format("no proper menurecovery defined, defaulting menurecovery config for %s Airboss Object",config.alias or ""),"AIRBOSS")
2765
+ Jtff_log.warn(string.format("no proper menurecovery defined, defaulting menurecovery config for %s Airboss Object",config.alias or ""),parser_name)
1280
2766
  airbossConfigJson.menurecovery = default_menurecovery
1281
2767
  else
1282
2768
  airbossConfigJson.menurecovery = {
@@ -1287,8 +2773,11 @@ function parseAirbossConfigJson(config)
1287
2773
  uturn = config.menurecovery.uturn or default_menurecovery.uturn,
1288
2774
  }
1289
2775
  end
2776
+ -- ************************************************************************
2777
+ -- Airboss SRS
2778
+ -- ************************************************************************
1290
2779
  if type(config.srs) ~= 'table' then
1291
- jtff_log.warn(string.format("no proper SRS config defined, defaulting SRS config for %s Airboss Object",config.alias or ""),"AIRBOSS")
2780
+ Jtff_log.warn(string.format("no proper SRS config defined, defaulting SRS config for %s Airboss Object",config.alias or ""),parser_name)
1292
2781
  airbossConfigJson.srs = default_srs
1293
2782
  else
1294
2783
  airbossConfigJson.srs = {
@@ -1296,7 +2785,7 @@ function parseAirbossConfigJson(config)
1296
2785
  }
1297
2786
  if airbossConfigJson.srs.useSRS then
1298
2787
  if type(config.srs.voices) ~= 'table' then
1299
- jtff_log.warn(string.format("no proper voices defined, defaulting voices config for %s Airboss Object",config.alias or ""),"AIRBOSS")
2788
+ Jtff_log.warn(string.format("no proper voices defined, defaulting voices config for %s Airboss Object",config.alias or ""),parser_name)
1300
2789
  airbossConfigJson.srs.voices = default_srs.voices
1301
2790
  else
1302
2791
  airbossConfigJson.srs.voices = {
@@ -1308,7 +2797,7 @@ function parseAirbossConfigJson(config)
1308
2797
  airbossConfigJson.srs.voiceovers = default_srs.voiceovers
1309
2798
  else
1310
2799
  if type(config.srs.voiceovers) ~= 'table' then
1311
- jtff_log.warn(string.format("no proper voiceovers defined, defaulting voiceovers config for %s Airboss Object",config.alias or ""),"AIRBOSS")
2800
+ Jtff_log.warn(string.format("no proper voiceovers defined, defaulting voiceovers config for %s Airboss Object",config.alias or ""),parser_name)
1312
2801
  airbossConfigJson.srs.voiceovers = default_srs.voiceovers
1313
2802
  else
1314
2803
  airbossConfigJson.srs.voiceovers = {
@@ -1319,8 +2808,11 @@ function parseAirbossConfigJson(config)
1319
2808
  airbossConfigJson.srs.voices = default_srs.voices
1320
2809
  end
1321
2810
  end
2811
+ -- ************************************************************************
2812
+ -- Airboss Radio Frequencies
2813
+ -- ************************************************************************
1322
2814
  if type(config.freq) ~= 'table' then
1323
- jtff_log.warn(string.format("no proper radio freqs defined, defaulting config for %s Airboss Object",config.alias or ""),"AIRBOSS")
2815
+ Jtff_log.warn(string.format("no proper radio freqs defined, defaulting config for %s Airboss Object",config.alias or ""),parser_name)
1324
2816
  airbossConfigJson.freq = default_radio_freqs
1325
2817
  else
1326
2818
  airbossConfigJson.freq = {
@@ -1329,8 +2821,11 @@ function parseAirbossConfigJson(config)
1329
2821
  lso = config.freq.lso or default_radio_freqs.lso,
1330
2822
  }
1331
2823
  end
2824
+ -- ************************************************************************
2825
+ -- Airboss Radio Relay Units
2826
+ -- ************************************************************************
1332
2827
  if type(config.releayunit) ~= 'table' then
1333
- jtff_log.warn(string.format("no proper radio releayunit defined, skipping freqs config for %s Airboss Object",config.alias or ""),"AIRBOSS")
2828
+ Jtff_log.warn(string.format("no proper radio releayunit defined, skipping freqs config for %s Airboss Object",config.alias or ""),parser_name)
1334
2829
  else
1335
2830
  local airboss_found = config.releayunit.airboss or nil
1336
2831
  local marshall_found = config.releayunit.marshall or nil
@@ -1345,7 +2840,7 @@ function parseAirbossConfigJson(config)
1345
2840
  lso_found = nil
1346
2841
  end
1347
2842
  if not(airboss_found or marshall_found or lso_found) then
1348
- jtff_log.warn(string.format("relayunit config empty, skipping freqs config for %s Airboss Object",config.alias or ""),"AIRBOSS")
2843
+ Jtff_log.warn(string.format("relayunit config empty, skipping freqs config for %s Airboss Object",config.alias or ""),parser_name)
1349
2844
  else
1350
2845
  airbossConfigJson.releayunit = {
1351
2846
  airboss = airboss_found or nil,
@@ -1354,195 +2849,108 @@ function parseAirbossConfigJson(config)
1354
2849
  }
1355
2850
  end
1356
2851
  end
1357
- jtff_log.info(string.format("parsed Airboss config for %s Airboss, resulting config :\n%s",config.alias or "", json:encode(airbossConfigJson, { indent = true })),"AIRBOSS")
1358
- return airbossConfigJson
1359
- end
1360
-
1361
- function resetAirbossDeck(objAirboss, delay)
1362
- local delay_second = delay or 5
1363
- jtff_log.info(string.format("reset all Deck Operations, closing the Deck on %s in %i seconds",objAirboss.customconfig.alias, delay_second),"AIRBOSS")
1364
- objAirboss:CloseCurrentRecoveryWindow(delay_second)
1365
- objAirboss:DeleteAllRecoveryWindows(delay_second+1)
1366
- end
1367
-
1368
- function initCSGAirbossMenus(airbossObject)
1369
- local MenuCoalitionCSGCommands
1370
- local rootMenuObject
1371
- local deckLayoutmenuObject
1372
- if airbossObject.customconfig.coalition == coalition.side.BLUE then
1373
- MenuCoalitionCSGCommands = MenuCoalitionCSGCommandsBlue
2852
+ -- ************************************************************************
2853
+ -- Airboss AirWing
2854
+ -- ************************************************************************
2855
+ if type(config.airwing) == "table" then
2856
+ airbossConfigJson.airwing = ParseAirwingConfigJson(config.airwing, parser_name)
1374
2857
  else
1375
- MenuCoalitionCSGCommands = MenuCoalitionCSGCommandsRed
2858
+ Jtff_log.error("Airboss airwing is not a table, aborting Airboss configuration", parser_name)
2859
+ config.enable = false
2860
+ return config
1376
2861
  end
1377
- rootMenuObject = MENU_COALITION:New(
1378
- airbossObject.customconfig.coalition,
1379
- airbossObject.customconfig.alias,
1380
- MenuCoalitionCSGCommands
1381
- )
1382
- MENU_COALITION_COMMAND:New(
1383
- airbossObject.customconfig.coalition,
1384
- "DEFCON 2 - duration 5 minutes",
1385
- rootMenuObject,
1386
- switchCarrierDefCon2,
1387
- {
1388
- airbossObject.customconfig.carriername,
1389
- 5
1390
- }
1391
- )
1392
- MENU_COALITION_COMMAND:New(
1393
- airbossObject.customconfig.coalition,
1394
- "DEFCON 2 - duration 10 minutes",
1395
- rootMenuObject,
1396
- switchCarrierDefCon2,
1397
- {
1398
- airbossObject.customconfig.carriername,
1399
- 10
1400
- }
1401
- )
1402
- MENU_COALITION_COMMAND:New(
1403
- airbossObject.customconfig.coalition,
1404
- "Release : DEFCON 4",
1405
- rootMenuObject,
1406
- forceCarrierDefCon4,
1407
- {
1408
- airbossObject.customconfig.carriername
1409
- }
1410
- )
1411
- if (
1412
- (airbossObject.carriertype == AIRBOSS.CarrierType.ROOSEVELT) or
1413
- (airbossObject.carriertype == AIRBOSS.CarrierType.LINCOLN) or
1414
- (airbossObject.carriertype == AIRBOSS.CarrierType.WASHINGTON) or
1415
- (airbossObject.carriertype == AIRBOSS.CarrierType.TRUMAN)
1416
- ) then
1417
- deckLayoutmenuObject = MENU_COALITION:New(
1418
- airbossObject.customconfig.coalition,
1419
- "Deck Layout",
1420
- rootMenuObject
1421
- )
1422
- MENU_COALITION_COMMAND:New(
1423
- airbossObject.customconfig.coalition,
1424
- "Clean Layout",
1425
- deckLayoutmenuObject,
1426
- cleanDeckLayout,
1427
- airbossObject
1428
- )
1429
- MENU_COALITION_COMMAND:New(
1430
- airbossObject.customconfig.coalition,
1431
- "Flex 3 Spawns",
1432
- deckLayoutmenuObject,
1433
- flexDeck3SpawnLayout,
1434
- airbossObject
1435
- )
1436
- MENU_COALITION_COMMAND:New(
1437
- airbossObject.customconfig.coalition,
1438
- "Flex 7 Spawns",
1439
- deckLayoutmenuObject,
1440
- flexDeck7SpawnLayout,
1441
- airbossObject
1442
- )
1443
- MENU_COALITION_COMMAND:New(
1444
- airbossObject.customconfig.coalition,
1445
- "Launch 7 Spawns",
1446
- deckLayoutmenuObject,
1447
- launchDeck7SpawnLayout,
1448
- airbossObject
1449
- )
1450
- MENU_COALITION_COMMAND:New(
1451
- airbossObject.customconfig.coalition,
1452
- "Launch 1 Spawn",
1453
- deckLayoutmenuObject,
1454
- launchDeck1SpawnLayout,
1455
- airbossObject
1456
- )
1457
- MENU_COALITION_COMMAND:New(
1458
- airbossObject.customconfig.coalition,
1459
- "Wipe All",
1460
- deckLayoutmenuObject,
1461
- wipeDeckLayout,
1462
- airbossObject
1463
- )
2862
+ -- ************************************************************************
2863
+ -- Airboss Integrated Patrols
2864
+ -- ************************************************************************
2865
+ if type(config.integratedpatrols) == "table" then
2866
+ airbossConfigJson.integratedpatrols = ParseIntegratedPatrolConfigJson(config.integratedpatrols, parser_name)
2867
+ else
2868
+ Jtff_log.warn(string.format("no proper integratedpatrols defined, defaulting integratedpatrols config for %s Airboss Object",config.alias or ""),parser_name)
2869
+ airbossConfigJson.integratedpatrols = default_integratedpatrols
1464
2870
  end
1465
- if (airbossObject.customconfig.recoveryops.mode == 'ondemand') then
1466
- MENU_COALITION_COMMAND:New(
1467
- airbossObject.customconfig.coalition,
1468
- "OnDemand Recovery : will start turning in 5 minutes",
1469
- rootMenuObject,
1470
- startRecoveryOnDemand,
1471
- airbossObject
1472
- )
1473
- MENU_COALITION_COMMAND:New(
1474
- airbossObject.customconfig.coalition,
1475
- "OnDemand Recovery Forced Case I: will start turning in 5 minutes",
1476
- rootMenuObject,
1477
- startRecoveryOnDemand,
1478
- airbossObject,
1479
- 1
1480
- )
1481
- MENU_COALITION_COMMAND:New(
1482
- airbossObject.customconfig.coalition,
1483
- "OnDemand Recovery Forced Case II: will start turning in 5 minutes",
1484
- rootMenuObject,
1485
- startRecoveryOnDemand,
1486
- airbossObject,
1487
- 2
1488
- )
1489
- MENU_COALITION_COMMAND:New(
1490
- airbossObject.customconfig.coalition,
1491
- "OnDemand Recovery Forced Case III: will start turning in 5 minutes",
1492
- rootMenuObject,
1493
- startRecoveryOnDemand,
1494
- airbossObject,
1495
- 3
1496
- )
2871
+
2872
+
2873
+
2874
+
2875
+
2876
+ if type(config.integratedpatrols) ~= 'table' then
2877
+ Jtff_log.warn(string.format("no proper integratedpatrols defined, defaulting integratedpatrols config for %s Airboss Object",config.alias or ""),parser_name)
2878
+ airbossConfigJson.integratedpatrols = default_integratedpatrols
2879
+ else
2880
+ airbossConfigJson.integratedpatrols = config.integratedpatrols or default_integratedpatrols
2881
+ -- ********************************************************************
2882
+ -- Airboss Integrated Patrols - Tanker
2883
+ -- ********************************************************************
2884
+ if type(config.integratedpatrols.tanker) ~= 'table' then
2885
+ Jtff_log.warn(string.format("no proper integratedpatrols.tanker defined, defaulting integratedpatrols.tanker config for %s Airboss Object",config.alias or ""),parser_name)
2886
+ airbossConfigJson.integratedpatrols.tanker = default_integratedpatrols.tanker
2887
+ else
2888
+ airbossConfigJson.integratedpatrols.tanker = config.integratedpatrols.tanker or default_integratedpatrols.tanker
2889
+ end
2890
+ -- ********************************************************************
2891
+ -- Airboss Integrated Patrols - AWACS
2892
+ -- ********************************************************************
2893
+ if type(config.integratedpatrols.awacs) ~= 'table' then
2894
+ Jtff_log.warn(string.format("no proper integratedpatrols.awacs defined, defaulting integratedpatrols.awacs config for %s Airboss Object",config.alias or ""),parser_name)
2895
+ airbossConfigJson.integratedpatrols.awacs = default_integratedpatrols.awacs
2896
+ else
2897
+ airbossConfigJson.integratedpatrols.awacs = config.integratedpatrols.awacs or default_integratedpatrols.awacs
2898
+ end
2899
+ -- ********************************************************************
2900
+ -- Airboss Integrated Patrols - Pedro
2901
+ -- ********************************************************************
2902
+ if type(config.integratedpatrols.pedro) ~= 'table' then
2903
+ Jtff_log.warn(string.format("no proper integratedpatrols.pedro defined, defaulting integratedpatrols.pedro config for %s Airboss Object",config.alias or ""),parser_name)
2904
+ airbossConfigJson.integratedpatrols.pedro = default_integratedpatrols.pedro
2905
+ else
2906
+ airbossConfigJson.integratedpatrols.pedro = config.integratedpatrols.pedro or default_integratedpatrols.pedro
2907
+ end
1497
2908
  end
1498
- MENU_COALITION_COMMAND:New(
1499
- airbossObject.customconfig.coalition,
1500
- "Recovery : close the deck and reset Airboss",
1501
- rootMenuObject,
1502
- resetAirbossDeck,
1503
- airbossObject
2909
+ Jtff_log.info(
2910
+ string.format(
2911
+ "parsed Airboss config for %s Airboss, resulting config :\n%s",
2912
+ config.alias or "",
2913
+ json:encode(
2914
+ airbossConfigJson,
2915
+ { indent = true }
2916
+ )
2917
+ ),
2918
+ parser_name
1504
2919
  )
1505
- return rootMenuObject, MenuCoalitionCSGCommands, deckLayoutmenuObject
2920
+ return airbossConfigJson
1506
2921
  end
2922
+ -- endregion AirBossConfig
1507
2923
 
1508
- function activateDL4(customconfig)
1509
- if (customconfig.dl4) then
1510
- local cvUnit = UNIT:FindByName(customconfig.carriername)
1511
- cvUnit:SetCommand(
1512
- {
1513
- id = "ActivateLink4",
1514
- params =
1515
- {
1516
- ["unitId"] = cvUnit:GetID(),
1517
- ["frequency"] = customconfig.dl4.freq * 1000000
1518
- },
1519
- }
1520
- )
1521
- cvUnit:SetCommand(
1522
- {
1523
- id = "ActivateACLS",
1524
- params =
1525
- {
1526
- ["unitId"] = cvUnit:GetID(),
1527
- },
1528
- }
1529
- )
1530
- end
2924
+ AIRBOSSArray = {}
2925
+ local compteur = #AIRBOSSArray
2926
+
2927
+ MenuCoalitionCSGCommands = {}
2928
+ for _k,_coalition in pairs(coalition.side) do
2929
+ MenuCoalitionCSGCommands[UTILS.GetCoalitionName(_coalition)] = MENU_COALITION:New(
2930
+ _coalition,
2931
+ "CSG Commands",
2932
+ MenuCoalition[UTILS.GetCoalitionName(_coalition)]
2933
+ )
1531
2934
  end
1532
2935
 
1533
- AIRBOSSArray = {}
1534
- compteur = 0
1535
- MenuCoalitionCSGCommandsBlue = MENU_COALITION:New(coalition.side.BLUE, "CSG Commands", MenuCoalitionBlue)
1536
- MenuCoalitionCSGCommandsRed = MENU_COALITION:New(coalition.side.RED, "CSG Commands", MenuCoalitionRed)
1537
2936
  for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1538
- local airbossconfig = parseAirbossConfigJson(currentAirbossConfigObject)
2937
+ local airbossconfig = ParseAirbossConfigJson(currentAirbossConfigObject)
1539
2938
  if airbossconfig.enable == true then
1540
2939
  compteur = compteur +1
1541
- local MenuCoalitionCSGCommands
1542
- local objAirboss = AIRBOSS:New(airbossconfig.carriername, airbossconfig.alias)
2940
+
2941
+ -- region AirBossSetUp
2942
+ Jtff_log.info(
2943
+ string.format(
2944
+ 'configuration AirBoss %s: ',
2945
+ airbossconfig.alias
2946
+ ),
2947
+ "AIRBOSS"
2948
+ )
2949
+ local menuCoalitionCSGCommands
2950
+ local objAirboss = AIRBOSS:New(airbossconfig.carriername, airbossconfig.alias) or {}
1543
2951
  objAirboss.autosave = false
1544
2952
  objAirboss.customconfig = airbossconfig
1545
- objAirboss.menuObject, MenuCoalitionCSGCommands, objAirboss.deckLayoutmenuObject = initCSGAirbossMenus(objAirboss)
2953
+ objAirboss.menuObject, menuCoalitionCSGCommands, objAirboss.deckLayoutmenuObject = InitCSGAirbossMenus(objAirboss)
1546
2954
  --TACAN
1547
2955
  objAirboss:SetTACANoff()
1548
2956
  objAirboss:SetTACAN(airbossconfig.tacan.channel, airbossconfig.tacan.mode, airbossconfig.tacan.morse)
@@ -1550,14 +2958,15 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1550
2958
  objAirboss:SetICLSoff()
1551
2959
  objAirboss:SetICLS(airbossconfig.icls.channel, airbossconfig.icls.morse)
1552
2960
  --ACLS
1553
- activateDL4(airbossconfig)
2961
+ ActivateDL4(airbossconfig)
1554
2962
  --Control parameters
1555
2963
  --CCA
1556
2964
  objAirboss:SetCarrierControlledArea(airbossconfig.controlarea)
2965
+ objAirboss:SetCarrierControlledZone(7)
1557
2966
  --Static weather
1558
2967
  objAirboss:SetStaticWeather(true)
1559
2968
  --Set Recovery case
1560
- objAirboss:SetRecoveryCase(getCaseTypeFromWeather(
2969
+ objAirboss:SetRecoveryCase(GetCaseTypeFromWeather(
1561
2970
  objAirboss:GetCoordinate(),
1562
2971
  timer.getAbsTime(),
1563
2972
  timer.getAbsTime() + airbossconfig.menurecovery.duration * 60
@@ -1597,16 +3006,6 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1597
3006
  end
1598
3007
  --Patrol control utility
1599
3008
  objAirboss:SetPatrolAdInfinitum(airbossconfig.infinitepatrol)
1600
- --Nanny
1601
- if airbossconfig.recoverytanker then
1602
- for index,value in pairs(tankersArray) do
1603
- if ((value.customconfig.airboss_recovery == true) and (value.customconfig.groupName == airbossconfig.recoverytanker)) then
1604
- objAirboss:SetRecoveryTanker(tankersArray[index])
1605
- objAirboss:MessageToMarshal('Recovery Tanker Setup : '..airbossconfig.recoverytanker, airbossconfig.alias, "", 30, false, 0)
1606
- break
1607
- end
1608
- end
1609
- end
1610
3009
  --Menus Management
1611
3010
  if airbossconfig.menurecovery.enable == true then
1612
3011
  objAirboss:SetMenuRecovery(airbossconfig.menurecovery.duration,
@@ -1617,6 +3016,10 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1617
3016
  objAirboss:SetMenuMarkZones(airbossconfig.enable_menumarkzones)
1618
3017
  objAirboss:SetMenuSmokeZones(airbossconfig.enable_menusmokezones)
1619
3018
  objAirboss:SetAirbossNiceGuy(airbossconfig.enable_niceguy)
3019
+ objAirboss:SetMarshalRadius()
3020
+ objAirboss:SetRecoveryTurnTime(60)
3021
+ objAirboss:SetRefuelAI(20)
3022
+ objAirboss:SetWelcomePlayers(false)
1620
3023
  if airbossconfig.singlecarrier == true then
1621
3024
  objAirboss:SetMenuSingleCarrier()
1622
3025
  end
@@ -1630,26 +3033,26 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1630
3033
  objAirboss:SetAirbossRadio(airbossconfig.freq.base, radio.modulation.AM, airbossconfig.srs.voices.airboss)
1631
3034
  else
1632
3035
  --we use voice overs from airboss : need to include soundfiles in the mission
1633
- objAirboss:SetSoundfilesFolder(soundFilesPrefix .. "AIRBOSS/Airboss Soundfiles/")
3036
+ objAirboss:SetSoundfilesFolder(SoundFilesPrefix .. "AIRBOSS/Airboss Soundfiles/")
1634
3037
  if airbossconfig.srs.voices.marshall then
1635
3038
  if airbossconfig.srs.voices.marshall == "Raynor" then
1636
- objAirboss:SetVoiceOversMarshalByRaynor(soundFilesPrefix .. 'AIRBOSS/Airboss Soundpack Marshal Raynor/')
3039
+ objAirboss:SetVoiceOversMarshalByRaynor(SoundFilesPrefix .. 'AIRBOSS/Airboss Soundpack Marshal Raynor/')
1637
3040
  elseif airbossconfig.srs.voices.marshall == "Gabriella" then
1638
- objAirboss:SetVoiceOversMarshalByGabriella(soundFilesPrefix .. 'AIRBOSS/Airboss Soundpack Marshal Gabriella/')
3041
+ objAirboss:SetVoiceOversMarshalByGabriella(SoundFilesPrefix .. 'AIRBOSS/Airboss Soundpack Marshal Gabriella/')
1639
3042
  elseif airbossconfig.srs.voices.marshall == "FF" then
1640
- objAirboss:SetVoiceOversMarshalByFF(soundFilesPrefix .. 'AIRBOSS/Airboss Soundpack Marshal FF/')
3043
+ objAirboss:SetVoiceOversMarshalByFF(SoundFilesPrefix .. 'AIRBOSS/Airboss Soundpack Marshal FF/')
1641
3044
  end
1642
3045
  else
1643
- objAirboss:SetVoiceOversMarshalByRaynor(soundFilesPrefix .. 'AIRBOSS/Airboss Soundpack Marshal Raynor/')
3046
+ objAirboss:SetVoiceOversMarshalByRaynor(SoundFilesPrefix .. 'AIRBOSS/Airboss Soundpack Marshal Raynor/')
1644
3047
  end
1645
3048
  if airbossconfig.srs.voices.lso then
1646
3049
  if airbossconfig.srs.voices.lso == "Raynor" then
1647
- objAirboss:SetVoiceOversLSOByRaynor(soundFilesPrefix .. 'AIRBOSS/Airboss Soundpack LSO Raynor/')
3050
+ objAirboss:SetVoiceOversLSOByRaynor(SoundFilesPrefix .. 'AIRBOSS/Airboss Soundpack LSO Raynor/')
1648
3051
  elseif airbossconfig.srs.voices.lso == "FF" then
1649
- objAirboss:SetVoiceOversLSOByFF(soundFilesPrefix .. 'AIRBOSS/Airboss Soundpack LSO FF/')
3052
+ objAirboss:SetVoiceOversLSOByFF(SoundFilesPrefix .. 'AIRBOSS/Airboss Soundpack LSO FF/')
1650
3053
  end
1651
3054
  else
1652
- objAirboss:SetVoiceOversLSOByRaynor(soundFilesPrefix .. 'AIRBOSS/Airboss Soundpack LSO Raynor/')
3055
+ objAirboss:SetVoiceOversLSOByRaynor(SoundFilesPrefix .. 'AIRBOSS/Airboss Soundpack LSO Raynor/')
1653
3056
  end
1654
3057
  objAirboss:SetLSORadio(airbossconfig.freq.lso, radio.modulation.AM)
1655
3058
  objAirboss:SetMarshalRadio(airbossconfig.freq.marshall, radio.modulation.AM)
@@ -1658,9 +3061,9 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1658
3061
  else
1659
3062
  --airbossconfig.srs does not exist
1660
3063
  --Should never happen as we parse the config
1661
- objAirboss:SetSoundfilesFolder(soundFilesPrefix .. "AIRBOSS/Airboss Soundfiles/")
1662
- objAirboss:SetVoiceOversMarshalByRaynor(soundFilesPrefix .. 'AIRBOSS/Airboss Soundpack Marshal Raynor/')
1663
- objAirboss:SetVoiceOversLSOByRaynor(soundFilesPrefix .. 'AIRBOSS/Airboss Soundpack LSO Raynor/')
3064
+ objAirboss:SetSoundfilesFolder(SoundFilesPrefix .. "AIRBOSS/Airboss Soundfiles/")
3065
+ objAirboss:SetVoiceOversMarshalByRaynor(SoundFilesPrefix .. 'AIRBOSS/Airboss Soundpack Marshal Raynor/')
3066
+ objAirboss:SetVoiceOversLSOByRaynor(SoundFilesPrefix .. 'AIRBOSS/Airboss Soundpack LSO Raynor/')
1664
3067
  objAirboss:SetLSORadio(airbossconfig.freq.lso, radio.modulation.AM)
1665
3068
  objAirboss:SetMarshalRadio(airbossconfig.freq.marshall, radio.modulation.AM)
1666
3069
  objAirboss:SetAirbossRadio(airbossconfig.freq.base, radio.modulation.AM)
@@ -1676,6 +3079,81 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1676
3079
  airbossconfig.recoveryops.cyclic.event_duration_minutes = 60
1677
3080
  end
1678
3081
  end
3082
+ -- endregion AirBossSetUp
3083
+
3084
+ -- region AirBossSetUpAirwing
3085
+ --Airwing generation
3086
+ objAirboss.airwing = AIRWING:New(
3087
+ objAirboss.carrier:GetName(),
3088
+ airbossconfig.airwing.name
3089
+ )
3090
+ objAirboss.airwing:SetAirboss(objAirboss)
3091
+ Commander[objAirboss.airwing:GetCoalitionName()]:AddAirwing(
3092
+ objAirboss.airwing
3093
+ )
3094
+
3095
+ for _, _squadronconfig in ipairs(airbossconfig.airwing.squadrons) do
3096
+ local squadronToCreate = SQUADRON:New(
3097
+ _squadronconfig.template,
3098
+ _squadronconfig.nb_aircrafts,
3099
+ _squadronconfig.name
3100
+ )
3101
+ squadronToCreate:SetFuelLowThreshold(_squadronconfig.fuellowthreshold)
3102
+ squadronToCreate:SetFuelLowRefuel(_squadronconfig.lowfuelrtb)
3103
+ squadronToCreate:SetGrouping(_squadronconfig.grouping)
3104
+ squadronToCreate:SetModex(_squadronconfig.modex)
3105
+ squadronToCreate:SetRadio(_squadronconfig.radio.freq, _squadronconfig.radio.modulation)
3106
+ squadronToCreate:SetSkill(_squadronconfig.skill)
3107
+ squadronToCreate:SetVerbosity(
3108
+ JTFF_verbosity_levels[JTFF_LOGLEVEL]
3109
+ )
3110
+ squadronToCreate:SetTurnoverTime(
3111
+ _squadronconfig.turnovertime,
3112
+ _squadronconfig.repairtime
3113
+ )
3114
+ -- TODO: improve this
3115
+ if type(_squadronconfig.livery) == 'string' then
3116
+ squadronToCreate:SetLivery(_squadronconfig.livery)
3117
+ end
3118
+ for _, _payload in ipairs(_squadronconfig.payloads) do
3119
+ local payloadTemplateGroup = GROUP:FindByName(_payload.name)
3120
+ if #(_payload.payloadconfigs) > 0 then
3121
+ for _, _payloadconfig in ipairs(_payload.payloadconfigs) do
3122
+ squadronToCreate:AddMissionCapability(_payloadconfig.roles)
3123
+ Jtff_log.debug(
3124
+ string.format(
3125
+ "Added mission capability %s perf=%d to squadron %s",
3126
+ _payload.name,
3127
+ _payloadconfig.perf,
3128
+ squadronToCreate:GetName()
3129
+ ),
3130
+ "AIRBOSS"
3131
+ )
3132
+ objAirboss.airwing:NewPayload(
3133
+ payloadTemplateGroup:GetUnit(1),
3134
+ _payloadconfig.qty,
3135
+ _payloadconfig.roles,
3136
+ _payloadconfig.perf
3137
+ )
3138
+ Jtff_log.debug(
3139
+ string.format(
3140
+ "Payload added qty=%d perf=%d template=%s to squadron %s",
3141
+ _payloadconfig.qty,
3142
+ _payloadconfig.perf,
3143
+ _payload.name,
3144
+ squadronToCreate:GetName()
3145
+ ),
3146
+ "AIRBOSS"
3147
+ )
3148
+ end
3149
+ end
3150
+ end
3151
+ objAirboss.airwing:AddSquadron(
3152
+ squadronToCreate
3153
+ )
3154
+ end
3155
+ -- endregion AirBossSetUpAirwing
3156
+
1679
3157
  --registering customconfig
1680
3158
  objAirboss.customconfig = airbossconfig
1681
3159
  --Apply DeckLayout
@@ -1685,16 +3163,40 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1685
3163
  (objAirboss.carriertype == AIRBOSS.CarrierType.TRUMAN) or
1686
3164
  (objAirboss.carriertype == AIRBOSS.CarrierType.WASHINGTON)
1687
3165
  ) then
1688
- jtff_log.info(string.format("CSG : %s is Supercarrier apply Deck Layout...", objAirboss.customconfig.alias),"AIRBOSS")
1689
- flexDeck7SpawnLayout(objAirboss)
3166
+ Jtff_log.info(
3167
+ string.format(
3168
+ "CSG : %s is Supercarrier apply Deck Layout...",
3169
+ objAirboss.customconfig.alias
3170
+ ),
3171
+ "AIRBOSS"
3172
+ )
3173
+ FlexDeck7SpawnLayout(objAirboss)
1690
3174
  else
1691
- jtff_log.info(string.format("CSG : %s is not Supercarrier (%s) skipping Deck Layout...", objAirboss.customconfig.alias, objAirboss.carriertype),"AIRBOSS")
3175
+ Jtff_log.info(
3176
+ string.format(
3177
+ "CSG : %s is not Supercarrier (%s) skipping Deck Layout...",
3178
+ objAirboss.customconfig.alias,
3179
+ objAirboss.carriertype
3180
+ ),
3181
+ "AIRBOSS"
3182
+ )
1692
3183
  end
1693
3184
 
3185
+ -- region AirBossCustomFunctions
1694
3186
  function objAirboss:detectShitHotBreak()
1695
3187
  local clientData={}
1696
3188
  local player_name=""
1697
- jtff_log.debug('detectShitHotBreak : '.. objAirboss.customconfig.alias .. ' has ' .. objAirboss.CVNClients:Count()..' clients in Set ...',"AIRBOSS")
3189
+ local clientsCount = objAirboss.CVNClients:Count()
3190
+ if clientsCount > 0 then
3191
+ Jtff_log.debug(
3192
+ string.format(
3193
+ "detectShitHotBreak : %s has %d clients in Set ...",
3194
+ objAirboss.customconfig.alias,
3195
+ clientsCount
3196
+ ),
3197
+ "AIRBOSS"
3198
+ )
3199
+ end
1698
3200
  objAirboss.CVNClients:ForEachClientInZone( objAirboss.CVN_UNITZone,
1699
3201
  function( MooseClient )
1700
3202
 
@@ -1710,7 +3212,7 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1710
3212
  local player_alt_feet = UTILS.MetersToFeet(MooseClient:GetAltitude())
1711
3213
  --trigger.action.outText('ForEachClientInZone: MooseClient name is '..player_name , 5)
1712
3214
 
1713
- local Play_SH_Sound = USERSOUND:New( soundFilesPrefix .. "AIRBOSS/Airboss Soundfiles/GreatBallsOfFire.ogg" )
3215
+ local Play_SH_Sound = USERSOUND:New( SoundFilesPrefix .. "AIRBOSS/Airboss Soundfiles/GreatBallsOfFire.ogg" )
1714
3216
  --trigger.action.outText(player_name..' altitude is '..player_alt_feet..' feet', 5)
1715
3217
  --trigger.action.outText(player_name..' speed is '..player_velocity, 5)
1716
3218
  local client_in_zone_flag = USERFLAG:New(MooseClient:GetUCID())
@@ -1719,7 +3221,7 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1719
3221
  if client_in_zone_flag:Get() == 0 and player_velocity > 475 and player_alt_feet < 700 then
1720
3222
  -- Requirements for Shit Hot break are velocity >475 knots and less than 700 feet
1721
3223
  trigger.action.outText(player_name..' performing a Sierra Hotel Break around ' .. objAirboss.customconfig.alias .. ' !', 10)
1722
- if (type(dcsbot) ~= 'nil') then
3224
+ if (type(Jtff_dcsbot) ~= 'nil') then
1723
3225
  local title = string.format('Shit Hot Break !!!')
1724
3226
  local description = string.format("[%s] is performing a Sierra Hotel Break at %.0f knots and %.0f feet over %s.",player_name , UTILS.Round(player_velocity, 0), player_alt_feet, objAirboss.customconfig.alias)
1725
3227
  local img = 'https://media1.tenor.com/m/s5P2w4A4H2MAAAAd/003.gif'
@@ -1728,13 +3230,13 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1728
3230
  ['CVN'] = objAirboss.customconfig.alias
1729
3231
  }
1730
3232
  local footer = 'Great balls of fire...'
1731
- dcsbot.sendEmbed(title, description, img, fields, footer)
3233
+ Jtff_dcsbot.sendEmbed(title, description, img, fields, footer)
1732
3234
  end
1733
3235
  Play_SH_Sound:ToClient(MooseClient)
1734
3236
  client_performing_sh:Set(1)
1735
3237
  client_in_zone_flag:Set(1)
1736
3238
  timer.scheduleFunction(resetFlag, MooseClient, timer.getTime() + 5 * 60)
1737
- jtff_log.info('Sierra Hotel Bravo detected : '.. player_name .. ' is breaking over ' .. objAirboss.customconfig.alias ..'...',"AIRBOSS")
3239
+ Jtff_log.info('Sierra Hotel Bravo detected : '.. player_name .. ' is breaking over ' .. objAirboss.customconfig.alias ..'...',"AIRBOSS")
1738
3240
  end
1739
3241
  end
1740
3242
  )
@@ -1751,8 +3253,8 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1751
3253
  local trapSheetBaseName = string.format("AIRBOSS-trapsheet-%s", player_name)
1752
3254
  local boolSendFunkman = true
1753
3255
 
1754
- local PerfectSound = USERSOUND:New( soundFilesPrefix .. "AIRBOSS/Airboss Soundfiles/ffyrtp.ogg" )
1755
- local FirstWireSound = USERSOUND:New( soundFilesPrefix .. "AIRBOSS/Airboss Soundfiles/GetYourButtsUptoVipersOffice.ogg" )
3256
+ local PerfectSound = USERSOUND:New( SoundFilesPrefix .. "AIRBOSS/Airboss Soundfiles/ffyrtp.ogg" )
3257
+ local FirstWireSound = USERSOUND:New( SoundFilesPrefix .. "AIRBOSS/Airboss Soundfiles/GetYourButtsUptoVipersOffice.ogg" )
1756
3258
 
1757
3259
  player_name = player_name:gsub('[%p]', '')
1758
3260
  local client_performing_sh = USERFLAG:New(UNIT:FindByName(unit_name):GetClient():GetUCID()..'_sh')
@@ -1761,11 +3263,11 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1761
3263
  client_performing_sh:Set(0)
1762
3264
  isSH = true
1763
3265
  bonusPoint = 1
1764
- jtff_log.debug('Adding bonus point to '.. player_name .. ' for his shit hot break over ' .. objAirboss.customconfig.alias ..'...',"AIRBOSS")
3266
+ Jtff_log.debug('Adding bonus point to '.. player_name .. ' for his shit hot break over ' .. objAirboss.customconfig.alias ..'...',"AIRBOSS")
1765
3267
  end
1766
3268
  if player_wire == 1 then
1767
3269
  malusPoint = 1
1768
- jtff_log.debug('Substracting malus point to '.. player_name .. ' for his 1-wire trap on ' .. objAirboss.customconfig.alias ..'...',"AIRBOSS")
3270
+ Jtff_log.debug('Substracting malus point to '.. player_name .. ' for his 1-wire trap on ' .. objAirboss.customconfig.alias ..'...',"AIRBOSS")
1769
3271
  timer.scheduleFunction(
1770
3272
  function()
1771
3273
  FirstWireSound:ToClient(UNIT:FindByName(unit_name):GetClient())
@@ -1773,7 +3275,7 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1773
3275
  {},
1774
3276
  timer.getTime() + 5
1775
3277
  )
1776
- if (type(dcsbot) ~= 'nil') then
3278
+ if (type(Jtff_dcsbot) ~= 'nil') then
1777
3279
  local title = string.format('Poor recovery !!!')
1778
3280
  local description = string.format("%s almost had a rampstrike with that 1-wire !",player_name)
1779
3281
  local img = 'https://theaviationgeekclub.com/wp-content/uploads/2019/05/VF-51-F-14A.jpg'
@@ -1782,7 +3284,7 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1782
3284
  ['CVN'] = objAirboss.customconfig.alias
1783
3285
  }
1784
3286
  local footer = 'Almost went direct to the parking...'
1785
- dcsbot.sendEmbed(title, description, img, fields, footer)
3287
+ Jtff_dcsbot.sendEmbed(title, description, img, fields, footer)
1786
3288
  end
1787
3289
  end
1788
3290
  if string_grade == "_OK_" then
@@ -1847,7 +3349,7 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1847
3349
  objAirboss.funkmanSocket:SendTable(result)
1848
3350
  objAirboss.funkmanSocket = nil
1849
3351
  end
1850
- jtff_log.info(string.format("%s trapped on %s in case %.0f with Grade %s and %.1f points.",player_name,objAirboss.customconfig.alias,playerData.case,myGrade.grade,myGrade.points),"AIRBOSS")
3352
+ Jtff_log.info(string.format("%s trapped on %s in case %.0f with Grade %s and %.1f points.",player_name,objAirboss.customconfig.alias,playerData.case,myGrade.grade,myGrade.points),"AIRBOSS")
1851
3353
  end
1852
3354
 
1853
3355
  function objAirboss:OnAfterRecoveryStart(From, Event, To, Case, Offset)
@@ -1861,7 +3363,7 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1861
3363
  if (airbossconfig.recoveryops.mode == 'cyclic') then
1862
3364
  nextRecoveryStart = timer.getAbsTime() + UTILS.Round(objAirboss.customconfig.recoveryops.cyclic.event_duration_minutes*60*1/3, 0)
1863
3365
  nextRecoveryStop = timer.getAbsTime() + UTILS.Round(objAirboss.customconfig.recoveryops.cyclic.event_duration_minutes*60*3/3, 0)
1864
- objAirboss:SetRecoveryCase(getCaseTypeFromWeather(
3366
+ objAirboss:SetRecoveryCase(GetCaseTypeFromWeather(
1865
3367
  objAirboss:GetCoordinate(),
1866
3368
  nextRecoveryStart,
1867
3369
  nextRecoveryStop
@@ -1876,8 +3378,8 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1876
3378
  objAirboss:SetMaxSectionSize(1)
1877
3379
  end
1878
3380
  objAirboss:AddRecoveryWindow(
1879
- UTILS.SecondsToClock(nextRecoveryStart,false,false),
1880
- UTILS.SecondsToClock(nextRecoveryStop,false,false),
3381
+ UTILS.SecondsToClock(nextRecoveryStart,false),
3382
+ UTILS.SecondsToClock(nextRecoveryStop,false),
1881
3383
  objAirboss.defaultcase,
1882
3384
  objAirboss.customconfig.menurecovery.offset,
1883
3385
  true,
@@ -1888,8 +3390,44 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1888
3390
  --LeaveRecovery(objAirboss)
1889
3391
  end
1890
3392
  end
3393
+ -- endregion AirBossCustomFunctions
3394
+
3395
+ --registering airboss object to AIRBOSSArray and starting it
1891
3396
  AIRBOSSArray[compteur] = objAirboss
1892
3397
  AIRBOSSArray[compteur]:Start()
3398
+
3399
+ -- region AirBossSetUpIntegratedPatrols
3400
+
3401
+ -- tanker integrated patrols
3402
+
3403
+ if airbossconfig.integratedpatrols.tanker.enable == true then
3404
+ local recoveryTankerMission, recoveryAirwing = GenerateRecoveryTankerMission(airbossconfig, true)
3405
+ if type(recoveryTankerMission) ~= 'nil' then
3406
+ AIRBOSSArray[compteur].airwing:AddMission(recoveryTankerMission)
3407
+ end
3408
+ end
3409
+
3410
+ -- rescue helo integrated patrols
3411
+
3412
+ if airbossconfig.integratedpatrols.rescuehelo.enable == true then
3413
+ local RescueHeloMission, recoveryAirwing = GenerateRescueHeloMission(airbossconfig, true)
3414
+ if type(RescueHeloMission) ~= 'nil' then
3415
+ AIRBOSSArray[compteur].airwing:AddMission(RescueHeloMission)
3416
+ end
3417
+ end
3418
+
3419
+ -- AWACS integrated patrols
3420
+
3421
+ if airbossconfig.integratedpatrols.awacs.enable == true then
3422
+ local navalAwacsMission, recoveryAirwing = GenerateNavalAwacsMission(airbossconfig, true)
3423
+ if type(navalAwacsMission) ~= 'nil' then
3424
+ AIRBOSSArray[compteur].airwing:AddMission(navalAwacsMission)
3425
+ end
3426
+ end
3427
+
3428
+ -- endregion AirBossSetUpIntegratedPatrols
3429
+
3430
+ -- region AirBossRecovery
1893
3431
  AIRBOSSArray[compteur].CVN_UNITZone = ZONE_UNIT:New(
1894
3432
  'cvnUnitZone-'..AIRBOSSArray[compteur].customconfig.alias,
1895
3433
  AIRBOSSArray[compteur].carrier,
@@ -1897,7 +3435,7 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1897
3435
  )
1898
3436
  AIRBOSSArray[compteur].CVNClients = SET_CLIENT:New()
1899
3437
  :FilterActive()
1900
- :FilterCoalitions(string.lower(UTILS.GetCoalitionName(objAirboss.customconfig.coalition)))
3438
+ :FilterCoalitions(string.lower(UTILS.GetCoalitionName(objAirboss:GetCoalition())))
1901
3439
  :FilterStart()
1902
3440
  local myscheduler
1903
3441
  local myschedulerID
@@ -1921,7 +3459,7 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1921
3459
  nextRecoveryStart = timer.getAbsTime() + 15*60 + UTILS.Round(airbossconfig.recoveryops.cyclic.event_duration_minutes*60*0/3, 0)
1922
3460
  nextRecoveryStop = timer.getAbsTime() + 15*60 + UTILS.Round(airbossconfig.recoveryops.cyclic.event_duration_minutes*60*2/3, 0)
1923
3461
  end
1924
- AIRBOSSArray[compteur]:SetRecoveryCase(getCaseTypeFromWeather(
3462
+ AIRBOSSArray[compteur]:SetRecoveryCase(GetCaseTypeFromWeather(
1925
3463
  AIRBOSSArray[compteur]:GetCoordinate(),
1926
3464
  nextRecoveryStart,
1927
3465
  nextRecoveryStop
@@ -1936,8 +3474,8 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1936
3474
  AIRBOSSArray[compteur]:SetMaxSectionSize(1)
1937
3475
  end
1938
3476
  AIRBOSSArray[compteur]:AddRecoveryWindow(
1939
- UTILS.SecondsToClock(nextRecoveryStart,false,false),
1940
- UTILS.SecondsToClock(nextRecoveryStop,false,false),
3477
+ UTILS.SecondsToClock(nextRecoveryStart,false),
3478
+ UTILS.SecondsToClock(nextRecoveryStop,false),
1941
3479
  AIRBOSSArray[compteur].defaultcase,
1942
3480
  airbossconfig.menurecovery.offset,
1943
3481
  true,
@@ -1950,7 +3488,7 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1950
3488
  for alphaindex, alphaevent in ipairs(airbossconfig.recoveryops.alpha.recoveries) do
1951
3489
  nextRecoveryStart = UTILS.Round(env.mission.start_time + (alphaevent.recovery_start_minutes * 60),0)
1952
3490
  nextRecoveryStop = UTILS.Round(env.mission.start_time + (( alphaevent.recovery_start_minutes + alphaevent.recovery_duration_minutes ) * 60),0)
1953
- AIRBOSSArray[compteur]:SetRecoveryCase(getCaseTypeFromWeather(
3491
+ AIRBOSSArray[compteur]:SetRecoveryCase(GetCaseTypeFromWeather(
1954
3492
  AIRBOSSArray[compteur]:GetCoordinate(),
1955
3493
  nextRecoveryStart,
1956
3494
  nextRecoveryStop
@@ -1972,7 +3510,7 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1972
3510
  end
1973
3511
  end
1974
3512
  else
1975
- AIRBOSSArray[compteur]:SetRecoveryCase(getCaseTypeFromWeather(
3513
+ AIRBOSSArray[compteur]:SetRecoveryCase(GetCaseTypeFromWeather(
1976
3514
  AIRBOSSArray[compteur]:GetCoordinate(),
1977
3515
  UTILS.Round(env.mission.start_time + (5 * 60),0),
1978
3516
  UTILS.Round(env.mission.start_time + (35 * 60),0)
@@ -1987,6 +3525,10 @@ for index, currentAirbossConfigObject in ipairs(AirBossConfig) do
1987
3525
  AIRBOSSArray[compteur]:SetMaxSectionSize(1)
1988
3526
  end
1989
3527
  end
3528
+ -- endregion AirBossRecovery
3529
+
3530
+ AIRBOSSArray[compteur].airwing:Start()
3531
+
1990
3532
  trigger.action.outText('AIRBOSS scripts Loaded for unit '..airbossconfig.carriername, 10)
1991
3533
  timer.scheduleFunction(
1992
3534
  function()