@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,363 +1,418 @@
1
- function playQRASoundToClient(client, time)
2
- soundQRA:ToClient(client)
3
- return nil
4
- end
5
-
6
- function QRALaunchBogey(params)
7
- local objQRA = params[1]
8
- local trigerringUnitName = params[2]
9
- local QRAIndex = params[3]
10
- local playerClient = CLIENT:FindByName(trigerringUnitName)
11
- local playerCoord = playerClient:GetCoordinate()
12
- local bogeyGroup = nil
13
- local bogeyRouteLengthNM = 200
14
- local bogeyRangeMin = 100
15
- local bogeyRangeMax = 300
16
- local bogeyFLMin = 5
17
- local bogeyFLMax = 250
18
- local bogeyAzimuthMin = 0
19
- local bogeyAzimuthMax = 359
20
- local bogeyGroundSpeedKnots = 600
21
- local bogeyAzimuth = math.floor(
22
- math.random(
23
- UTILS.FeetToMeters(bogeyAzimuthMin),
24
- UTILS.FeetToMeters(bogeyAzimuthMax)
25
- )
26
- )
27
- local bogeyFL = math.floor(
28
- math.random(
29
- UTILS.FeetToMeters(bogeyFLMin * 100),
30
- UTILS.FeetToMeters(bogeyFLMax * 100)
31
- )
32
- )
33
- local bogeyRangeMeters = math.floor(
34
- math.random(
35
- UTILS.NMToMeters(bogeyRangeMin),
36
- UTILS.NMToMeters(bogeyRangeMax)
37
- )
38
- )
39
- local bogeySpawnObj = QRAArray[QRAIndex].objSpawn
40
- local bogeyCoord = POINT_VEC3:NewFromVec3(
41
- {
42
- x = playerCoord.x + math.floor(bogeyRangeMeters * math.cos(math.rad(bogeyAzimuth))),
43
- y = math.max(
44
- math.min(
45
- bogeyFL,
46
- UTILS.FeetToMeters(32000)
47
- ),
48
- UTILS.FeetToMeters(500)
49
- ),
50
- z = playerCoord.z + math.floor(bogeyRangeMeters * math.sin(math.rad(bogeyAzimuth))),
51
- }
52
- )
53
- local bogeyDestination = playerCoord:GetRandomCoordinateInRadius(
54
- UTILS.NMToMeters(10),
55
- UTILS.NMToMeters(60)
56
- )
57
- local bogeyHeading = bogeyCoord:HeadingTo(bogeyDestination)
58
- jtff_log.info(
59
- string.format(
60
- "Spawning bogey based on %s with Heading of %i degrees",
61
- bogeySpawnObj.SpawnTemplatePrefix,
62
- bogeyHeading
63
- ),
64
- "QRA"
65
- )
66
- bogeyGroup = bogeySpawnObj:InitHeading(bogeyHeading):SpawnFromVec3(bogeyCoord)
67
- bogeyGroup:OptionROE(ENUMS.ROE.WeaponHold)
68
- bogeyGroup:OptionROT(ENUMS.ROT.NoReaction)
69
- bogeyGroup:OptionRTBBingoFuel(true)
70
- bogeyGroup:OptionRestrictBurner(false)
71
- bogeyGroup:EnableEmission(false)
72
- bogeyGroup:OptionAlarmStateGreen()
73
- bogeyGroup:OptionECM_Never()
74
- bogeyGroup:CommandEPLRS(true)
75
- local bogeyDestinationCoord = bogeyGroup:GetCoordinate():Translate(
76
- UTILS.NMToMeters(bogeyRouteLengthNM),
77
- bogeyHeading,
78
- true,
79
- false
80
- )
81
- bogeyGroup:Route(
82
- {
83
- bogeyDestinationCoord:WaypointAirTurningPoint(
84
- COORDINATE.WaypointAltType.BARO,
85
- UTILS.KnotsToKmph(bogeyGroundSpeedKnots),
86
- nil,
87
- "End QRA"
88
- ),
89
- bogeyDestinationCoord:GetClosestAirbase(
90
- --bogeyGroup:GetCategory(),
91
- --bogeyGroup:GetCoalition()
92
- ):GetCoordinate():WaypointAirLanding(
93
- UTILS.KnotsToKmph(bogeyGroundSpeedKnots),
94
- bogeyDestinationCoord:GetClosestAirbase(
95
- --bogeyGroup:GetCategory(),
96
- --bogeyGroup:GetCoalition()
97
- )
98
- )
99
- }
100
- )
101
- return bogeyGroup
102
- end
103
-
104
- function QRATrigger(params)
105
- local objQRA = params[1]
106
- local trigerringUnitName = params[2]
107
- local QRAIndex = params[3]
108
- local msgTriggeredGround = ""
109
- local msgTriggeredOthers = ""
110
- local triggerPlayerName = ""
111
- if (objQRA.customconfig.type == JTFF_QRA.Type.TangoAuto) then
112
- local playerClient = CLIENT:FindByName(trigerringUnitName)
113
- local playerName = playerClient:GetPlayer()
114
- triggerPlayerName = playerName
115
- local playerCoord = playerClient:GetCoordinate()
116
- QRAArray[QRAIndex].objBogeyGroup = QRALaunchBogey(params)
117
- local bullsCoord = COORDINATE.GetBullseyeCoordinate(objQRA.customconfig.benefit_coalition)
118
- local bogeyCoord = QRAArray[QRAIndex].objBogeyGroup:GetCoordinate()
119
- local bullsBearing = math.floor(bullsCoord:HeadingTo(bogeyCoord))
120
- local bullsRange = math.floor(UTILS.MetersToNM(bullsCoord:Get2DDistance(bogeyCoord)))
121
- local bogeyAngel = math.floor(UTILS.MetersToFeet(QRAArray[QRAIndex].objBogeyGroup:GetAltitude(false))/1000)
122
- local bogeyApproxDestination = playerCoord:GetClosestAirbase():GetName()
123
- jtff_log.info(
124
- string.format(
125
- "Bogey Spawned based on %s",
126
- QRAArray[QRAIndex].objSpawn.SpawnTemplatePrefix
127
- ),
128
- "QRA"
129
- )
130
- jtff_log.info(
131
- string.format("Bogey is Bulls %i for %i Angel %i, tracking to %s",
132
- bullsBearing,
133
- bullsRange,
134
- bogeyAngel,
135
- bogeyApproxDestination
136
- ),
137
- "QRA"
138
- )
139
- local formatString = "QRA %s has been triggered by %s!\n" ..
140
- "Type is : %s\n" ..
141
- "Bogey is Bulls %i for %i Angel %i, tracking %s\n" ..
142
- "If you're on Alert," ..
143
- " you have 10 minutes to take-off and intercept the bogey.\n" ..
144
- "If you're not, please give %s priority on the taxiway.\n"
145
- msgTriggeredGround = string.format(
146
- formatString,
147
- objQRA.customconfig.name,
148
- playerName,
149
- objQRA.customconfig.type,
150
- bullsBearing,
151
- bullsRange,
152
- bogeyAngel,
153
- bogeyApproxDestination,
154
- playerName
155
- )
156
- formatString = "<WARNING> : QRA Triggered by %s!\n" ..
157
- "A Bogey is approaching %s, " ..
158
- "stay away from the interception area\n" ..
159
- "...\n" ..
160
- "Bogey last position : Bulls %i for %i Angel %i, tracking to %s"
161
- msgTriggeredOthers = string.format(formatString,
162
- playerName,
163
- playerCoord:GetClosestAirbase():GetName(),
164
- bullsBearing,
165
- bullsRange,
166
- bogeyAngel,
167
- bogeyApproxDestination
168
- )
169
- elseif (objQRA.customconfig.type == JTFF_QRA.Type.TangoManual) then
170
- local playerClient
171
- local playerName
172
- local playerCoord
173
- if type(trigerringUnitName) == 'nil' then
174
- playerName = "GameMaster"
175
- playerClient = nil
176
- playerCoord = COORDINATE.GetBullseyeCoordinate(objQRA.customconfig.benefit_coalition)
177
- else
178
- playerClient = CLIENT:FindByName(trigerringUnitName)
179
- playerName = playerClient:GetPlayer()
180
- playerCoord = playerClient:GetCoordinate()
181
- end
182
- triggerPlayerName = playerName
183
- local formatString = "QRA %s has been triggered by %s !\n" ..
184
- "Type is : %s\n" ..
185
- "If you're on Alert," ..
186
- " you have 10 minutes to take-off and start intercepting the the bogey.\n" ..
187
- "You are cleared to start and wait your AIC for scramble information\n\n\n" ..
188
- "If you're not on alert, please monitor the ground frequency" ..
189
- " and let the scramble flight taxi in highest priority..."
190
- msgTriggeredGround = string.format(
191
- formatString,
192
- objQRA.customconfig.name,
193
- playerName,
194
- objQRA.customconfig.type
195
- )
196
- formatString = "<WARNING> : QRA Training triggered by %s!\n" ..
197
- "Stay away from the interception area (%s)\n" ..
198
- "...\n" ..
199
- "Keep monitoring your tactical frequency" ..
200
- " for information about the Scramble procedure"
201
- msgTriggeredOthers = string.format(formatString,
202
- playerName,
203
- type(playerClient) ~= 'nil' and playerCoord:ToStringMGRS() or ""
204
- )
205
- elseif (objQRA.customconfig.type == JTFF_QRA.Type.Alpha) then
206
- local playerClient
207
- local playerName
208
- local playerCoord
209
- if type(trigerringUnitName) == 'nil' then
210
- playerName = "GameMaster"
211
- playerClient = nil
212
- playerCoord = COORDINATE.GetBullseyeCoordinate(objQRA.customconfig.benefit_coalition)
213
- else
214
- playerClient = CLIENT:FindByName(trigerringUnitName)
215
- playerName = playerClient:GetPlayer()
216
- playerCoord = playerClient:GetCoordinate()
217
- end
218
- triggerPlayerName = playerName
219
- local formatString = "QRA %s has been triggered by %s !\n" ..
220
- "Type is : %s\n" ..
221
- "If you're on Alert," ..
222
- " you have 10 minutes to take-off and start intercepting the the bogey.\n" ..
223
- "You are cleared to start and wait your AIC for scramble information\n\n\n" ..
224
- "If you're not on alert, please monitor the ground frequency" ..
225
- " and let the scramble flight taxi in highest priority..."
226
- msgTriggeredGround = string.format(
227
- formatString,
228
- objQRA.customconfig.name,
229
- playerName,
230
- objQRA.customconfig.type
231
- )
232
- formatString = "<WARNING> : QRA Triggered by %s!\n" ..
233
- "Stay away from the interception area (%s)\n" ..
234
- "...\n" ..
235
- "Keep monitoring your tactical frequency" ..
236
- " for information about the Scramble procedure"
237
- msgTriggeredOthers = string.format(formatString,
238
- playerName,
239
- type(playerClient) ~= 'nil' and playerCoord:ToStringMGRS() or ""
240
- )
241
- else
242
- end
243
- objQRA.clientSet:ForEachClient(
244
- function(clientObject)
245
- if ClientIsOnGround(clientObject) then
246
- playQRASoundToClient(clientObject)
247
- timer.scheduleFunction(
248
- playQRASoundToClient,
249
- clientObject,
250
- timer.getTime() + 17
251
- )
252
- MESSAGE:New(msgTriggeredGround,60):ToClient(clientObject)
253
- end
254
- end
255
- )
256
- MESSAGE:New(msgTriggeredOthers,30):ToCoalition(objQRA.customconfig.benefit_coalition)
257
- QRAArray[QRAIndex].menu_finex[QRAArray[QRAIndex].customconfig.benefit_coalition] = MENU_COALITION_COMMAND:New(
258
- QRAArray[QRAIndex].customconfig.benefit_coalition,
259
- "FinEx - " .. QRAArray[QRAIndex].customconfig.name .. " !!",
260
- MenuCoalitionQRA[QRAArray[QRAIndex].customconfig.benefit_coalition],
261
- QRAFinex,
262
- QRAIndex
263
- )
264
- if (type(dcsbot) ~= 'nil') then
265
- local title = string.format('QRA triggered !')
266
- local description = string.format("[%s] triggered a QRA scenario : All QRA pilots, startup and scramble following the procedure",triggerPlayerName)
267
- local img = 'https://www.defense.gouv.fr/sites/default/files/styles/16_9_sm/public/air/22_09_2023_13.jpeg?itok=n_MPmvZc'
268
- local fields = {
269
- ['Trigger'] = triggerPlayerName,
270
- ['Type'] = QRAArray[QRAIndex].customconfig.type,
271
- ['Coalition'] = UTILS.GetCoalitionName(QRAArray[QRAIndex].customconfig.benefit_coalition),
272
- }
273
- local footer = 'Scramble scramble scramble...'
274
- dcsbot.sendEmbed(title, description, img, fields, footer)
275
- end
276
- end
277
-
278
- function QRAFinex(objQRAIndex)
279
- local objQRA = QRAArray[objQRAIndex]
280
- if objQRA.customconfig.type == JTFF_QRA.Type.TangoAuto then
281
- jtff_log.trace(string.format("objQRA.objSpawn is %s", net.lua2json(objQRA.objSpawn)),"QRA")
282
- local GroupPlane, Index = objQRA.objSpawn:GetFirstAliveGroup()
283
- while GroupPlane ~= nil do
284
- GroupPlane:ScheduleStop()
285
- GroupPlane:Destroy(true,0)
286
- GroupPlane, Index = objQRA.objSpawn:GetNextAliveGroup( Index )
287
- end
288
- collectgarbage()
289
- end
290
- QRAArray[objQRAIndex].menu_finex[QRAArray[objQRAIndex].customconfig.benefit_coalition]:Remove()
291
- QRAArray[objQRAIndex].menu_finex[QRAArray[objQRAIndex].customconfig.benefit_coalition] = nil
292
- end
293
-
294
-
295
-
296
- -- *****************************************************************************
297
- -- ** QRA **
298
- -- *********************************************************
299
- QRAArray = {}
300
- compteur = 0
301
- MenuCoalitionQRA = {}
302
- MenuCoalitionQRA[coalition.side.BLUE] = MENU_COALITION:New(coalition.side.BLUE, "QRA", MenuCoalitionBlue)
303
- MenuCoalitionQRA[coalition.side.RED] = MENU_COALITION:New(coalition.side.RED, "QRA", MenuCoalitionRed)
304
- for index, qraconfig in ipairs(QRAConfig) do
305
- if qraconfig.enable == true then
306
- compteur = compteur + 1
307
- jtff_log.info('creation QRA : '.. qraconfig.name..'...',"QRA")
308
- local objQRA = {
309
- customconfig = {},
310
- clientSet = nil,
311
- objSpawn = nil,
312
- objBogeyGroup = nil,
313
- menu = {},
314
- menu_finex = {},
315
- }
316
- if ( qraconfig.type == JTFF_QRA.Type.TangoAuto) then
317
- objQRA.objSpawn = SPAWN:New(qraconfig.templates[1])
318
- :InitSkill(qraconfig.skill)
319
- :InitRandomizeTemplate(qraconfig.templates or {})
320
- end
321
- objQRA.clientSet = SET_CLIENT:New()
322
- :FilterCoalitions(string.lower(UTILS.GetCoalitionName(qraconfig.benefit_coalition)))
323
- :FilterCategories("plane")
324
- :FilterActive(true)
325
- :FilterFunction(ClientIsOnGround)
326
- :FilterStart()
327
- objQRA.clientSet:HandleEvent(EVENTS.PlayerEnterAircraft)
328
- jtff_log.debug(string.format("Nbr Clients getting QRA Calls : %i", objQRA.clientSet:Count()),"QRA")
329
-
330
- function objQRA.clientSet:OnEventPlayerEnterAircraft(EventData)
331
- local clientObject = CLIENT:Find(EventData.IniUnit:GetDCSObject())
332
- if ClientIsOnGround(clientObject) then
333
- --self:Add(clientObject:GetPlayer(), clientObject)
334
- jtff_log.debug(string.format("Added %s to QRA receivers", clientObject:GetPlayer() or ""),"QRA")
335
- jtff_log.debug(string.format("Nbr Clients getting QRA Calls : %i", objQRA.clientSet:Count()),"QRA")
336
- end
337
- end
338
-
339
- if ( qraconfig.type ~= JTFF_QRA.Type.TangoAuto) then
340
- objQRA.menu[qraconfig.benefit_coalition] = MENU_COALITION_COMMAND:New(
341
- qraconfig.benefit_coalition,
342
- "Trigger " .. qraconfig.name,
343
- MenuCoalitionQRA[qraconfig.benefit_coalition],
344
- QRATrigger,
345
- {
346
- objQRA,
347
- nil,
348
- index,
349
- }
350
- )
351
- end
352
-
353
- objQRA.customconfig = qraconfig
354
-
355
- QRAArray[compteur] = objQRA
356
- end
357
- end
358
-
359
- if compteur == 0 then
360
- MenuCoalitionQRA[coalition.side.BLUE]:Remove()
361
- MenuCoalitionQRA[coalition.side.RED]:Remove()
362
- MenuCoalitionQRA = {}
1
+ -- region QRAConfigFunctions
2
+
3
+ -- @type QRAConfig
4
+ -- @field #boolean enable Enable the QRA scenario.
5
+ -- @field #string name Name of the QRA scenario.
6
+ -- @field #JTFF_QRA.Type type Type of the QRA scenario.
7
+ -- @field #coalition.side benefit_coalition Coalition to benefit from the QRA scenario.
8
+ -- @field #string[] templates Templates to use for the QRA scenario.
9
+ -- @field #string skill Skill to use for the QRA scenario.
10
+
11
+ --- Parse an QRA config Object.
12
+ -- @param #JsonObject config Config object to parse
13
+ -- @return #QRAConfig qraConfigJson Parsed QRA config object
14
+ function ParseQRAConfigJson(config)
15
+ local json = require('Scripts/json')
16
+ local parser_name = "QRA"
17
+ -- **************************************************************************
18
+ -- enable
19
+ -- **************************************************************************
20
+ local qraConfigJson = {}
21
+ if config.enable == true then
22
+ qraConfigJson = config
23
+ else
24
+ qraConfigJson = {
25
+ enable = false,
26
+ }
27
+ end
28
+ Jtff_log.debug(
29
+ string.format(
30
+ "parsed QRA config for %s, resulting config :\n%s",
31
+ config.type or "",
32
+ json:encode(
33
+ qraConfigJson,
34
+ { indent = true }
35
+ )
36
+ ),
37
+ parser_name
38
+ )
39
+ return qraConfigJson
40
+ end
41
+ -- endregion QRAConfigFunctions
42
+
43
+ -- region QRAFunctions
44
+
45
+ function playQRASoundToClient(client, time)
46
+ SoundQRA:ToClient(client)
47
+ return nil
48
+ end
49
+
50
+ function QRALaunchBogey(params)
51
+ local objQRA = params[1]
52
+ local trigerringUnitName = params[2]
53
+ local QRAIndex = params[3]
54
+ local playerClient = CLIENT:FindByName(trigerringUnitName)
55
+ local playerCoord = playerClient:GetCoordinate()
56
+ local bogeyGroup = nil
57
+ local bogeyRouteLengthNM = 200
58
+ local bogeyRangeMin = 100
59
+ local bogeyRangeMax = 300
60
+ local bogeyFLMin = 5
61
+ local bogeyFLMax = 250
62
+ local bogeyAzimuthMin = 0
63
+ local bogeyAzimuthMax = 359
64
+ local bogeyGroundSpeedKnots = 600
65
+ local bogeyAzimuth = math.floor(
66
+ math.random(
67
+ UTILS.FeetToMeters(bogeyAzimuthMin),
68
+ UTILS.FeetToMeters(bogeyAzimuthMax)
69
+ )
70
+ )
71
+ local bogeyFL = math.floor(
72
+ math.random(
73
+ UTILS.FeetToMeters(bogeyFLMin * 100),
74
+ UTILS.FeetToMeters(bogeyFLMax * 100)
75
+ )
76
+ )
77
+ local bogeyRangeMeters = math.floor(
78
+ math.random(
79
+ UTILS.NMToMeters(bogeyRangeMin),
80
+ UTILS.NMToMeters(bogeyRangeMax)
81
+ )
82
+ )
83
+ local bogeySpawnObj = QRAArray[QRAIndex].objSpawn
84
+ local bogeyCoord = COORDINATE:NewFromVec3(
85
+ {
86
+ x = playerCoord.x + math.floor(bogeyRangeMeters * math.cos(math.rad(bogeyAzimuth))),
87
+ y = math.max(
88
+ math.min(
89
+ bogeyFL,
90
+ UTILS.FeetToMeters(32000)
91
+ ),
92
+ UTILS.FeetToMeters(500)
93
+ ),
94
+ z = playerCoord.z + math.floor(bogeyRangeMeters * math.sin(math.rad(bogeyAzimuth))),
95
+ }
96
+ )
97
+ local bogeyDestination = playerCoord:GetRandomCoordinateInRadius(
98
+ UTILS.NMToMeters(10),
99
+ UTILS.NMToMeters(60)
100
+ )
101
+ local bogeyHeading = bogeyCoord:HeadingTo(bogeyDestination)
102
+ Jtff_log.info(
103
+ string.format(
104
+ "Spawning bogey based on %s with Heading of %i degrees",
105
+ bogeySpawnObj.SpawnTemplatePrefix,
106
+ bogeyHeading
107
+ ),
108
+ "QRA"
109
+ )
110
+ bogeyGroup = bogeySpawnObj:InitHeading(bogeyHeading):SpawnFromCoordinate(bogeyCoord)
111
+ bogeyGroup:OptionROE(ENUMS.ROE.WeaponHold)
112
+ bogeyGroup:OptionROT(ENUMS.ROT.NoReaction)
113
+ bogeyGroup:OptionRTBBingoFuel(true)
114
+ bogeyGroup:OptionRestrictBurner(false)
115
+ bogeyGroup:EnableEmission(false)
116
+ bogeyGroup:OptionAlarmStateGreen()
117
+ bogeyGroup:OptionECM_Never()
118
+ bogeyGroup:CommandEPLRS(true)
119
+ local bogeyDestinationCoord = bogeyGroup:GetCoordinate():Translate(
120
+ UTILS.NMToMeters(bogeyRouteLengthNM),
121
+ bogeyHeading,
122
+ true,
123
+ false
124
+ )
125
+ bogeyGroup:Route(
126
+ {
127
+ bogeyDestinationCoord:WaypointAirTurningPoint(
128
+ COORDINATE.WaypointAltType.BARO,
129
+ UTILS.KnotsToKmph(bogeyGroundSpeedKnots),
130
+ nil,
131
+ "End QRA"
132
+ ),
133
+ bogeyDestinationCoord:GetClosestAirbase(
134
+ --bogeyGroup:GetCategory(),
135
+ --bogeyGroup:GetCoalition()
136
+ ):GetCoordinate():WaypointAirLanding(
137
+ UTILS.KnotsToKmph(bogeyGroundSpeedKnots),
138
+ bogeyDestinationCoord:GetClosestAirbase(
139
+ --bogeyGroup:GetCategory(),
140
+ --bogeyGroup:GetCoalition()
141
+ )
142
+ )
143
+ }
144
+ )
145
+ return bogeyGroup
146
+ end
147
+
148
+ function QRATrigger(params)
149
+ local objQRA = params[1]
150
+ local trigerringUnitName = params[2]
151
+ local QRAIndex = params[3]
152
+ local msgTriggeredGround = ""
153
+ local msgTriggeredOthers = ""
154
+ local triggerPlayerName = ""
155
+ if (objQRA.customconfig.type == JTFF_QRA.Type.TangoAuto) then
156
+ local playerClient = CLIENT:FindByName(trigerringUnitName)
157
+ local playerName = playerClient:GetPlayer()
158
+ triggerPlayerName = playerName
159
+ local playerCoord = playerClient:GetCoordinate()
160
+ QRAArray[QRAIndex].objBogeyGroup = QRALaunchBogey(params)
161
+ local bullsCoord = COORDINATE.GetBullseyeCoordinate(objQRA.customconfig.benefit_coalition)
162
+ local bogeyCoord = QRAArray[QRAIndex].objBogeyGroup:GetCoordinate()
163
+ local bullsBearing = math.floor(bullsCoord:HeadingTo(bogeyCoord))
164
+ local bullsRange = math.floor(UTILS.MetersToNM(bullsCoord:Get2DDistance(bogeyCoord)))
165
+ local bogeyAngel = math.floor(UTILS.MetersToFeet(QRAArray[QRAIndex].objBogeyGroup:GetAltitude(false))/1000)
166
+ local bogeyApproxDestination = playerCoord:GetClosestAirbase():GetName()
167
+ Jtff_log.info(
168
+ string.format(
169
+ "Bogey Spawned based on %s",
170
+ QRAArray[QRAIndex].objSpawn.SpawnTemplatePrefix
171
+ ),
172
+ "QRA"
173
+ )
174
+ Jtff_log.info(
175
+ string.format("Bogey is Bulls %i for %i Angel %i, tracking to %s",
176
+ bullsBearing,
177
+ bullsRange,
178
+ bogeyAngel,
179
+ bogeyApproxDestination
180
+ ),
181
+ "QRA"
182
+ )
183
+ local formatString = "QRA %s has been triggered by %s!\n" ..
184
+ "Type is : %s\n" ..
185
+ "Bogey is Bulls %i for %i Angel %i, tracking %s\n" ..
186
+ "If you're on Alert," ..
187
+ " you have 10 minutes to take-off and intercept the bogey.\n" ..
188
+ "If you're not, please give %s priority on the taxiway.\n"
189
+ msgTriggeredGround = string.format(
190
+ formatString,
191
+ objQRA.customconfig.name,
192
+ playerName,
193
+ objQRA.customconfig.type,
194
+ bullsBearing,
195
+ bullsRange,
196
+ bogeyAngel,
197
+ bogeyApproxDestination,
198
+ playerName
199
+ )
200
+ formatString = "<WARNING> : QRA Triggered by %s!\n" ..
201
+ "A Bogey is approaching %s, " ..
202
+ "stay away from the interception area\n" ..
203
+ "...\n" ..
204
+ "Bogey last position : Bulls %i for %i Angel %i, tracking to %s"
205
+ msgTriggeredOthers = string.format(formatString,
206
+ playerName,
207
+ playerCoord:GetClosestAirbase():GetName(),
208
+ bullsBearing,
209
+ bullsRange,
210
+ bogeyAngel,
211
+ bogeyApproxDestination
212
+ )
213
+ elseif (objQRA.customconfig.type == JTFF_QRA.Type.TangoManual) then
214
+ local playerClient
215
+ local playerName
216
+ local playerCoord
217
+ if type(trigerringUnitName) == 'nil' then
218
+ playerName = "GameMaster"
219
+ playerClient = nil
220
+ playerCoord = COORDINATE.GetBullseyeCoordinate(objQRA.customconfig.benefit_coalition)
221
+ else
222
+ playerClient = CLIENT:FindByName(trigerringUnitName)
223
+ playerName = playerClient:GetPlayer()
224
+ playerCoord = playerClient:GetCoordinate()
225
+ end
226
+ triggerPlayerName = playerName
227
+ local formatString = "QRA %s has been triggered by %s !\n" ..
228
+ "Type is : %s\n" ..
229
+ "If you're on Alert," ..
230
+ " you have 10 minutes to take-off and start intercepting the the bogey.\n" ..
231
+ "You are cleared to start and wait your AIC for scramble information\n\n\n" ..
232
+ "If you're not on alert, please monitor the ground frequency" ..
233
+ " and let the scramble flight taxi in highest priority..."
234
+ msgTriggeredGround = string.format(
235
+ formatString,
236
+ objQRA.customconfig.name,
237
+ playerName,
238
+ objQRA.customconfig.type
239
+ )
240
+ formatString = "<WARNING> : QRA Training triggered by %s!\n" ..
241
+ "Stay away from the interception area (%s)\n" ..
242
+ "...\n" ..
243
+ "Keep monitoring your tactical frequency" ..
244
+ " for information about the Scramble procedure"
245
+ msgTriggeredOthers = string.format(formatString,
246
+ playerName,
247
+ type(playerClient) ~= 'nil' and playerCoord:ToStringMGRS() or ""
248
+ )
249
+ elseif (objQRA.customconfig.type == JTFF_QRA.Type.Alpha) then
250
+ local playerClient
251
+ local playerName
252
+ local playerCoord
253
+ if type(trigerringUnitName) == 'nil' then
254
+ playerName = "GameMaster"
255
+ playerClient = nil
256
+ playerCoord = COORDINATE.GetBullseyeCoordinate(objQRA.customconfig.benefit_coalition)
257
+ else
258
+ playerClient = CLIENT:FindByName(trigerringUnitName)
259
+ playerName = playerClient:GetPlayer()
260
+ playerCoord = playerClient:GetCoordinate()
261
+ end
262
+ triggerPlayerName = playerName
263
+ local formatString = "QRA %s has been triggered by %s !\n" ..
264
+ "Type is : %s\n" ..
265
+ "If you're on Alert," ..
266
+ " you have 10 minutes to take-off and start intercepting the the bogey.\n" ..
267
+ "You are cleared to start and wait your AIC for scramble information\n\n\n" ..
268
+ "If you're not on alert, please monitor the ground frequency" ..
269
+ " and let the scramble flight taxi in highest priority..."
270
+ msgTriggeredGround = string.format(
271
+ formatString,
272
+ objQRA.customconfig.name,
273
+ playerName,
274
+ objQRA.customconfig.type
275
+ )
276
+ formatString = "<WARNING> : QRA Triggered by %s!\n" ..
277
+ "Stay away from the interception area (%s)\n" ..
278
+ "...\n" ..
279
+ "Keep monitoring your tactical frequency" ..
280
+ " for information about the Scramble procedure"
281
+ msgTriggeredOthers = string.format(formatString,
282
+ playerName,
283
+ type(playerClient) ~= 'nil' and playerCoord:ToStringMGRS() or ""
284
+ )
285
+ else
286
+ end
287
+ objQRA.clientSet:ForEachClient(
288
+ function(clientObject)
289
+ if ClientIsOnGround(clientObject) then
290
+ playQRASoundToClient(clientObject)
291
+ timer.scheduleFunction(
292
+ playQRASoundToClient,
293
+ clientObject,
294
+ timer.getTime() + 17
295
+ )
296
+ MESSAGE:New(msgTriggeredGround,60):ToClient(clientObject)
297
+ end
298
+ end
299
+ )
300
+ MESSAGE:New(msgTriggeredOthers,30):ToCoalition(objQRA.customconfig.benefit_coalition)
301
+ QRAArray[QRAIndex].menu_finex[QRAArray[QRAIndex].customconfig.benefit_coalition] = MENU_COALITION_COMMAND:New(
302
+ QRAArray[QRAIndex].customconfig.benefit_coalition,
303
+ "FinEx - " .. QRAArray[QRAIndex].customconfig.name .. " !!",
304
+ MenuCoalitionQRA[QRAArray[QRAIndex].customconfig.benefit_coalition],
305
+ QRAFinex,
306
+ QRAIndex
307
+ )
308
+ if (type(Jtff_dcsbot) ~= 'nil') then
309
+ local title = string.format('QRA triggered !')
310
+ local description = string.format("[%s] triggered a QRA scenario : All QRA pilots, startup and scramble following the procedure",triggerPlayerName)
311
+ local img = 'https://www.defense.gouv.fr/sites/default/files/styles/16_9_sm/public/air/22_09_2023_13.jpeg?itok=n_MPmvZc'
312
+ local fields = {
313
+ ['Trigger'] = triggerPlayerName,
314
+ ['Type'] = QRAArray[QRAIndex].customconfig.type,
315
+ ['Coalition'] = UTILS.GetCoalitionName(QRAArray[QRAIndex].customconfig.benefit_coalition),
316
+ }
317
+ local footer = 'Scramble scramble scramble...'
318
+ Jtff_dcsbot.sendEmbed(title, description, img, fields, footer)
319
+ end
320
+ end
321
+
322
+ function QRAFinex(objQRAIndex)
323
+ local objQRA = QRAArray[objQRAIndex]
324
+ if objQRA.customconfig.type == JTFF_QRA.Type.TangoAuto then
325
+ Jtff_log.trace(string.format("objQRA.objSpawn is %s", net.lua2json(objQRA.objSpawn)),"QRA")
326
+ local GroupPlane, Index = objQRA.objSpawn:GetFirstAliveGroup()
327
+ while GroupPlane ~= nil do
328
+ GroupPlane:ScheduleStop()
329
+ GroupPlane:Destroy(true,0)
330
+ GroupPlane, Index = objQRA.objSpawn:GetNextAliveGroup( Index )
331
+ end
332
+ collectgarbage()
333
+ end
334
+ QRAArray[objQRAIndex].menu_finex[QRAArray[objQRAIndex].customconfig.benefit_coalition]:Remove()
335
+ QRAArray[objQRAIndex].menu_finex[QRAArray[objQRAIndex].customconfig.benefit_coalition] = nil
336
+ end
337
+
338
+ -- endregion QRAFunctions
339
+
340
+ -- *****************************************************************************
341
+ -- ** QRA **
342
+ -- *********************************************************
343
+ QRAArray = {}
344
+ local compteur = #QRAArray
345
+
346
+ MenuCoalitionQRA = {}
347
+ for _k, _coalition in pairs(coalition.side) do
348
+ MenuCoalitionQRA[UTILS.GetCoalitionName(_coalition)] = MENU_COALITION:New(_coalition, "QRA", MenuCoalition[UTILS.GetCoalitionName(_coalition)])
349
+ end
350
+
351
+ for index, currentQRAConfigObject in ipairs(QRAConfig) do
352
+ local qraconfig = ParseQRAConfigJson(currentQRAConfigObject)
353
+ if qraconfig.enable == true then
354
+ compteur = compteur + 1
355
+ Jtff_log.info('creation QRA : '.. qraconfig.name..'...',"QRA")
356
+ local objQRA = {
357
+ customconfig = {},
358
+ clientSet = nil,
359
+ objSpawn = nil,
360
+ objBogeyGroup = nil,
361
+ menu = {},
362
+ menu_finex = {},
363
+ }
364
+ if ( qraconfig.type == JTFF_QRA.Type.TangoAuto) then
365
+ objQRA.objSpawn = SPAWN:New(qraconfig.templates[1])
366
+ :InitSkill(qraconfig.skill)
367
+ :InitRandomizeTemplate(qraconfig.templates or {})
368
+ end
369
+ objQRA.clientSet = SET_CLIENT:New()
370
+ :FilterCoalitions(string.lower(UTILS.GetCoalitionName(qraconfig.benefit_coalition)))
371
+ :FilterCategories("plane")
372
+ :FilterActive(true)
373
+ :FilterFunction(ClientIsOnGround)
374
+ :FilterStart()
375
+ objQRA.clientSet:HandleEvent(EVENTS.PlayerEnterAircraft)
376
+ Jtff_log.debug(
377
+ string.format(
378
+ "Nbr Clients getting QRA Calls : %i",
379
+ objQRA.clientSet:Count()
380
+ ),
381
+ "QRA"
382
+ )
383
+
384
+ function objQRA.clientSet:OnEventPlayerEnterAircraft(EventData)
385
+ local clientObject = CLIENT:Find(EventData.IniUnit:GetDCSObject())
386
+ if ClientIsOnGround(clientObject) then
387
+ --self:Add(clientObject:GetPlayer(), clientObject)
388
+ Jtff_log.debug(string.format("Added %s to QRA receivers", clientObject:GetPlayer() or ""),"QRA")
389
+ Jtff_log.debug(string.format("Nbr Clients getting QRA Calls : %i", objQRA.clientSet:Count()),"QRA")
390
+ end
391
+ end
392
+
393
+ if ( qraconfig.type ~= JTFF_QRA.Type.TangoAuto) then
394
+ objQRA.menu[qraconfig.benefit_coalition] = MENU_COALITION_COMMAND:New(
395
+ qraconfig.benefit_coalition,
396
+ "Trigger " .. qraconfig.name,
397
+ MenuCoalitionQRA[UTILS.GetCoalitionName(qraconfig.benefit_coalition)],
398
+ QRATrigger,
399
+ {
400
+ objQRA,
401
+ nil,
402
+ index,
403
+ }
404
+ )
405
+ end
406
+
407
+ objQRA.customconfig = qraconfig
408
+
409
+ QRAArray[compteur] = objQRA
410
+ end
411
+ end
412
+
413
+ if #QRAArray == 0 then
414
+ for _k, _coalition in pairs(coalition.side) do
415
+ MenuCoalitionQRA[UTILS.GetCoalitionName(_coalition)]:Remove()
416
+ end
417
+ MenuCoalitionQRA = {}
363
418
  end