mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-17 20:56:08 +00:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0971f8ffa7 | |||
| 9739f94428 | |||
| 450f4eaec0 | |||
| b5186fa328 | |||
| 526dc8363d | |||
| 242d735d8c | |||
| 9fedd32e78 | |||
| a146003a6a | |||
| d17df74191 | |||
| d23403383f | |||
| 877b36f8a8 | |||
| 299820162b | |||
| 5d20a59d92 | |||
| c1ab3b5476 | |||
| 0076130483 | |||
| a5194b1999 | |||
| b53b1f083f | |||
| 994a36001f | |||
| 26b91e3f66 | |||
| f42aedd485 | |||
| a73818a615 | |||
| 7c22e9fe69 | |||
| c58e91b956 | |||
| a61059242c | |||
| cea9437e66 | |||
| 3f052ef1da | |||
| c137a4b06d | |||
| 6c46dafc59 | |||
| 1207417894 | |||
| 7c717c219c | |||
| a9fad53255 | |||
| 372cc021bd | |||
| 6820774266 | |||
| a0c189a349 | |||
| 1060ff16d8 | |||
| 1255f48645 | |||
| 7ef69208d4 | |||
| 5277cca4e1 |
+17
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"Lua.workspace.preloadFileSize": 1000,
|
||||||
|
"Lua.diagnostics.disable": [
|
||||||
|
"undefined-doc-name"
|
||||||
|
],
|
||||||
|
"Lua.diagnostics.globals": [
|
||||||
|
"BASE",
|
||||||
|
"lfs",
|
||||||
|
"__Moose",
|
||||||
|
"trigger",
|
||||||
|
"coord",
|
||||||
|
"missionCommands"
|
||||||
|
],
|
||||||
|
"Lua.completion.displayContext": 5,
|
||||||
|
"Lua.runtime.version": "Lua 5.1",
|
||||||
|
"Lua.completion.callSnippet": "Both"
|
||||||
|
}
|
||||||
@@ -882,7 +882,8 @@ do -- AI_A2A_DISPATCHER
|
|||||||
-- @type AI_A2A_DISPATCHER.Takeoff
|
-- @type AI_A2A_DISPATCHER.Takeoff
|
||||||
-- @extends Wrapper.Group#GROUP.Takeoff
|
-- @extends Wrapper.Group#GROUP.Takeoff
|
||||||
|
|
||||||
--- @field #AI_A2A_DISPATCHER.Takeoff Takeoff
|
---
|
||||||
|
-- @field #AI_A2A_DISPATCHER.Takeoff Takeoff
|
||||||
AI_A2A_DISPATCHER.Takeoff = GROUP.Takeoff
|
AI_A2A_DISPATCHER.Takeoff = GROUP.Takeoff
|
||||||
|
|
||||||
--- Defines Landing type/location.
|
--- Defines Landing type/location.
|
||||||
@@ -928,6 +929,8 @@ do -- AI_A2A_DISPATCHER
|
|||||||
self.DefenderTasks = {} -- The Defenders Tasks.
|
self.DefenderTasks = {} -- The Defenders Tasks.
|
||||||
self.DefenderDefault = {} -- The Defender Default Settings over all Squadrons.
|
self.DefenderDefault = {} -- The Defender Default Settings over all Squadrons.
|
||||||
|
|
||||||
|
self.SetSendPlayerMessages = false --#boolean Flash messages to player
|
||||||
|
|
||||||
-- TODO: Check detection through radar.
|
-- TODO: Check detection through radar.
|
||||||
self.Detection:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
|
self.Detection:FilterCategories( { Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
|
||||||
-- self.Detection:InitDetectRadar( true )
|
-- self.Detection:InitDetectRadar( true )
|
||||||
@@ -2319,6 +2322,13 @@ do -- AI_A2A_DISPATCHER
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set flashing player messages on or off
|
||||||
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
|
-- @param #boolean onoff Set messages on (true) or off (false)
|
||||||
|
function AI_A2A_DISPATCHER:SetSendMessages( onoff )
|
||||||
|
self.SetSendPlayerMessages = onoff
|
||||||
|
end
|
||||||
|
|
||||||
--- Sets flights to take-off in the air, as part of the defense system.
|
--- Sets flights to take-off in the air, as part of the defense system.
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param #string SquadronName The name of the squadron.
|
-- @param #string SquadronName The name of the squadron.
|
||||||
@@ -3188,7 +3198,9 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
|
|
||||||
if Squadron then
|
if Squadron then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " Wheels up.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " Wheels up.", DefenderGroup )
|
||||||
|
end
|
||||||
AI_A2A_Fsm:__Patrol( 2 ) -- Start Patrolling
|
AI_A2A_Fsm:__Patrol( 2 ) -- Start Patrolling
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3200,10 +3212,10 @@ do -- AI_A2A_DISPATCHER
|
|||||||
self:GetParent( self ).onafterPatrolRoute( self, DefenderGroup, From, Event, To )
|
self:GetParent( self ).onafterPatrolRoute( self, DefenderGroup, From, Event, To )
|
||||||
|
|
||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
if Squadron then
|
if Squadron and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", patrolling.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", patrolling.", DefenderGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
@@ -3219,8 +3231,8 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
if Squadron then
|
if Squadron and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " returning to base.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " returning to base.", DefenderGroup )
|
||||||
end
|
end
|
||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
end
|
end
|
||||||
@@ -3404,10 +3416,10 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local DefenderTarget = Dispatcher:GetDefenderTaskTarget( DefenderGroup )
|
local DefenderTarget = Dispatcher:GetDefenderTaskTarget( DefenderGroup )
|
||||||
|
|
||||||
if DefenderTarget then
|
if DefenderTarget then
|
||||||
if Squadron.Language == "EN" then
|
if Squadron.Language == "EN" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " wheels up.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " wheels up.", DefenderGroup )
|
||||||
elseif Squadron.Language == "RU" then
|
elseif Squadron.Language == "RU" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " колеса вверх.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " колёса вверх.", DefenderGroup )
|
||||||
end
|
end
|
||||||
-- Fsm:__Engage( 2, DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
-- Fsm:__Engage( 2, DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
||||||
Fsm:EngageRoute( DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
Fsm:EngageRoute( DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
||||||
@@ -3425,12 +3437,12 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
|
||||||
if Squadron.Language == "EN" then
|
if Squadron.Language == "EN" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", intercepting bogeys at " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", intercepting bogeys at " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
||||||
elseif Squadron.Language == "RU" then
|
elseif Squadron.Language == "RU" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", перехват самолетов в " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", перехватывая боги в " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
||||||
elseif Squadron.Language == "DE" then
|
elseif Squadron.Language == "DE" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", Eindringlinge abfangen bei" .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", Eindringlinge abfangen bei" .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:GetParent( Fsm ).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
self:GetParent( Fsm ).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
||||||
@@ -3447,10 +3459,10 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
|
||||||
if Squadron.Language == "EN" then
|
if Squadron.Language == "EN" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging bogeys at " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging bogeys at " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
||||||
elseif Squadron.Language == "RU" then
|
elseif Squadron.Language == "RU" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", захватывающие самолеты в " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", задействуя боги в " .. Coordinate:ToStringA2A( DefenderGroup, nil, Squadron.Language ), DefenderGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:GetParent( Fsm ).onafterEngage( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
self:GetParent( Fsm ).onafterEngage( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
||||||
@@ -3465,10 +3477,10 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
|
|
||||||
if Squadron then
|
if Squadron then
|
||||||
if Squadron.Language == "EN" then
|
if Squadron.Language == "EN" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " returning to base.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " returning to base.", DefenderGroup )
|
||||||
elseif Squadron.Language == "RU" then
|
elseif Squadron.Language == "RU" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", возвращаясь на базу.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", возвращение на базу.", DefenderGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
@@ -3496,11 +3508,11 @@ do -- AI_A2A_DISPATCHER
|
|||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
|
|
||||||
if Squadron.Language == "EN" then
|
if Squadron.Language == "EN" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " landing at base.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. " landing at base.", DefenderGroup )
|
||||||
elseif Squadron.Language == "RU" then
|
elseif Squadron.Language == "RU" and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", захватывающие самолеты в посадка на базу.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", посадка на базу.", DefenderGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
if Action and Action == "Destroy" then
|
if Action and Action == "Destroy" then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
||||||
@@ -3890,7 +3902,7 @@ do
|
|||||||
self:CAP( SquadronName )
|
self:CAP( SquadronName )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add resources to a Squadron
|
--- Add resources to a Squadron
|
||||||
-- @param #AI_A2A_DISPATCHER self
|
-- @param #AI_A2A_DISPATCHER self
|
||||||
-- @param #string Squadron The squadron name.
|
-- @param #string Squadron The squadron name.
|
||||||
-- @param #number Amount Number of resources to add.
|
-- @param #number Amount Number of resources to add.
|
||||||
|
|||||||
@@ -1000,6 +1000,8 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- self.Detection:InitDetectVisual( true )
|
-- self.Detection:InitDetectVisual( true )
|
||||||
-- self.Detection:SetRefreshTimeInterval( 30 )
|
-- self.Detection:SetRefreshTimeInterval( 30 )
|
||||||
|
|
||||||
|
self.SetSendPlayerMessages = false --flash messages to players
|
||||||
|
|
||||||
self:SetDefenseRadius()
|
self:SetDefenseRadius()
|
||||||
self:SetDefenseLimit( nil )
|
self:SetDefenseLimit( nil )
|
||||||
self:SetDefenseApproach( AI_A2G_DISPATCHER.DefenseApproach.Random )
|
self:SetDefenseApproach( AI_A2G_DISPATCHER.DefenseApproach.Random )
|
||||||
@@ -3718,7 +3720,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
|
|
||||||
if Squadron then
|
if Squadron then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", wheels up.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", wheels up.", DefenderGroup )
|
||||||
|
end
|
||||||
AI_A2G_Fsm:Patrol() -- Engage on the TargetSetUnit
|
AI_A2G_Fsm:Patrol() -- Engage on the TargetSetUnit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3730,7 +3734,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
if Squadron then
|
if Squadron and self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", patrolling.", DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", patrolling.", DefenderGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3749,8 +3753,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
if Squadron and AttackSetUnit:Count() > 0 then
|
if Squadron and AttackSetUnit:Count() > 0 then
|
||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
if self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", moving on to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", moving on to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3764,8 +3769,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
if FirstUnit then
|
if FirstUnit then
|
||||||
local Coordinate = FirstUnit:GetCoordinate()
|
local Coordinate = FirstUnit:GetCoordinate()
|
||||||
|
if self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3776,8 +3782,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", returning to base.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", returning to base.", DefenderGroup )
|
||||||
|
end
|
||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3789,7 +3796,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", lost control." )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", lost control." )
|
||||||
|
end
|
||||||
if DefenderGroup:IsAboveRunway() then
|
if DefenderGroup:IsAboveRunway() then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
||||||
DefenderGroup:Destroy()
|
DefenderGroup:Destroy()
|
||||||
@@ -3804,8 +3813,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", landing at base.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", landing at base.", DefenderGroup )
|
||||||
|
end
|
||||||
if Action and Action == "Destroy" then
|
if Action and Action == "Destroy" then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
||||||
DefenderGroup:Destroy()
|
DefenderGroup:Destroy()
|
||||||
@@ -3861,7 +3871,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
self:F( { DefenderTarget = DefenderTarget } )
|
self:F( { DefenderTarget = DefenderTarget } )
|
||||||
|
|
||||||
if DefenderTarget then
|
if DefenderTarget then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", wheels up.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", wheels up.", DefenderGroup )
|
||||||
|
end
|
||||||
AI_A2G_Fsm:EngageRoute( DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
AI_A2G_Fsm:EngageRoute( DefenderTarget.Set ) -- Engage on the TargetSetUnit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3876,8 +3888,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
if Squadron then
|
if Squadron then
|
||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
|
||||||
|
if self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", on route to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", on route to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
self:GetParent(self).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
self:GetParent(self).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
|
||||||
end
|
end
|
||||||
@@ -3892,8 +3905,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local FirstUnit = AttackSetUnit:GetFirst()
|
local FirstUnit = AttackSetUnit:GetFirst()
|
||||||
if FirstUnit then
|
if FirstUnit then
|
||||||
local Coordinate = FirstUnit:GetCoordinate()
|
local Coordinate = FirstUnit:GetCoordinate()
|
||||||
|
if self.SetSendPlayerMessages then
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", engaging ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), DefenderGroup )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3903,8 +3917,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", returning to base.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", returning to base.", DefenderGroup )
|
||||||
|
end
|
||||||
self:GetParent(self).onafterRTB( self, DefenderGroup, From, Event, To )
|
self:GetParent(self).onafterRTB( self, DefenderGroup, From, Event, To )
|
||||||
|
|
||||||
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
|
||||||
@@ -3918,8 +3933,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
--Dispatcher:MessageToPlayers( Squadron, "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " lost control." )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " lost control." )
|
||||||
|
end
|
||||||
if DefenderGroup:IsAboveRunway() then
|
if DefenderGroup:IsAboveRunway() then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
||||||
DefenderGroup:Destroy()
|
DefenderGroup:Destroy()
|
||||||
@@ -3934,8 +3950,9 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefenderName = DefenderGroup:GetCallsign()
|
local DefenderName = DefenderGroup:GetCallsign()
|
||||||
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
|
||||||
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
|
||||||
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", landing at base.", DefenderGroup )
|
if self.SetSendPlayerMessages then
|
||||||
|
Dispatcher:MessageToPlayers( Squadron, DefenderName .. ", landing at base.", DefenderGroup )
|
||||||
|
end
|
||||||
if Action and Action == "Destroy" then
|
if Action and Action == "Destroy" then
|
||||||
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
|
||||||
DefenderGroup:Destroy()
|
DefenderGroup:Destroy()
|
||||||
@@ -3975,7 +3992,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate )
|
local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate )
|
||||||
|
|
||||||
-- Now check if this coordinate is not in a danger zone, meaning, that the attack line is not crossing other coordinates.
|
-- Now check if this coordinate is not in a danger zone, meaning, that the attack line is not crossing other coordinates.
|
||||||
-- (y1 – y2)x + (x2 – x1)y + (x1y2 – x2y1) = 0
|
-- (y1 - y2)x + (x2 - x1)y + (x1y2 - x2y1) = 0
|
||||||
|
|
||||||
local c1 = DefenseCoordinate
|
local c1 = DefenseCoordinate
|
||||||
local c2 = AttackCoordinate
|
local c2 = AttackCoordinate
|
||||||
@@ -4036,7 +4053,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
for DefenderID, DefenderGroup in pairs( DefenderFriendlies or {} ) do
|
for DefenderID, DefenderGroup in pairs( DefenderFriendlies or {} ) do
|
||||||
|
|
||||||
-- Here we check if the defenders have a defense line to the attackers.
|
-- Here we check if the defenders have a defense line to the attackers.
|
||||||
-- If the attackers are behind enemy lines or too close to an other defense line; then don´t engage.
|
-- If the attackers are behind enemy lines or too close to an other defense line; then don't engage.
|
||||||
local DefenseCoordinate = DefenderGroup:GetCoordinate()
|
local DefenseCoordinate = DefenderGroup:GetCoordinate()
|
||||||
local HasDefenseLine = self:HasDefenseLine( DefenseCoordinate, DetectedItem )
|
local HasDefenseLine = self:HasDefenseLine( DefenseCoordinate, DetectedItem )
|
||||||
|
|
||||||
@@ -4341,7 +4358,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
|
|
||||||
-- Show tactical situation
|
-- Show tactical situation
|
||||||
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
|
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
|
||||||
Report:Add( string.format( " - %1s%s ( %04s ): ( #%02d - %-4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) )
|
Report:Add( string.format( " - %1s%s ( %04s ): ( #%02d - %-4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) )
|
||||||
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
||||||
local Defender = Defender -- Wrapper.Group#GROUP
|
local Defender = Defender -- Wrapper.Group#GROUP
|
||||||
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
||||||
@@ -4559,7 +4576,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
if self.TacticalDisplay then
|
if self.TacticalDisplay then
|
||||||
-- Show tactical situation
|
-- Show tactical situation
|
||||||
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
|
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
|
||||||
Report:Add( string.format( " - %1s%s ( %4s ): ( #%d - %4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) )
|
Report:Add( string.format( " - %1s%s ( %4s ): ( #%d - %4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) )
|
||||||
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
||||||
local Defender = Defender -- Wrapper.Group#GROUP
|
local Defender = Defender -- Wrapper.Group#GROUP
|
||||||
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
||||||
@@ -4729,7 +4746,15 @@ do
|
|||||||
self:Patrol( SquadronName, PatrolTaskType )
|
self:Patrol( SquadronName, PatrolTaskType )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add resources to a Squadron
|
--- Set flashing player messages on or off
|
||||||
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
|
-- @param #boolean onoff Set messages on (true) or off (false)
|
||||||
|
function AI_A2G_DISPATCHER:SetSendMessages( onoff )
|
||||||
|
self.SetSendPlayerMessages = onoff
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add resources to a Squadron
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
-- @param #string Squadron The squadron name.
|
-- @param #string Squadron The squadron name.
|
||||||
-- @param #number Amount Number of resources to add.
|
-- @param #number Amount Number of resources to add.
|
||||||
@@ -4752,6 +4777,3 @@ do
|
|||||||
end
|
end
|
||||||
self:T({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
|
self:T({Squadron = Squadron.Name,SquadronResourceCount = Squadron.ResourceCount})
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|||||||
@@ -428,9 +428,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
|||||||
--- Calculate the current route point.
|
--- Calculate the current route point.
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
|
|
||||||
if not CurrentVec2 then -- flight dead at this point
|
if not CurrentVec2 then return self end
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
|
|||||||
@@ -459,7 +459,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
|||||||
--- Calculate the current route point.
|
--- Calculate the current route point.
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
|
|
||||||
--TODO: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||||
|
|||||||
@@ -174,8 +174,8 @@ function AI_CARGO_DISPATCHER_HELICOPTER:New( HelicopterSet, CargoSet, PickupZone
|
|||||||
self:SetPickupSpeed( 350, 150 )
|
self:SetPickupSpeed( 350, 150 )
|
||||||
self:SetDeploySpeed( 350, 150 )
|
self:SetDeploySpeed( 350, 150 )
|
||||||
|
|
||||||
self:SetPickupRadius( 0, 0 )
|
self:SetPickupRadius( 40, 12 )
|
||||||
self:SetDeployRadius( 0, 0 )
|
self:SetDeployRadius( 40, 12 )
|
||||||
|
|
||||||
self:SetPickupHeight( 500, 200 )
|
self:SetPickupHeight( 500, 200 )
|
||||||
self:SetDeployHeight( 500, 200 )
|
self:SetDeployHeight( 500, 200 )
|
||||||
@@ -186,6 +186,9 @@ end
|
|||||||
|
|
||||||
function AI_CARGO_DISPATCHER_HELICOPTER:AICargo( Helicopter, CargoSet )
|
function AI_CARGO_DISPATCHER_HELICOPTER:AICargo( Helicopter, CargoSet )
|
||||||
|
|
||||||
return AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
|
local dispatcher = AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
|
||||||
|
dispatcher:SetLandingSpeedAndHeight(27, 6)
|
||||||
|
return dispatcher
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI.AI_Cargo_Dispatcher_Ship
|
-- @module AI.AI_Cargo_Dispatcher_Ship
|
||||||
-- @image AI_Cargo_Dispatching_For_Ship.JPG
|
-- @image AI_Cargo_Dispatcher.JPG
|
||||||
|
|
||||||
--- @type AI_CARGO_DISPATCHER_SHIP
|
--- @type AI_CARGO_DISPATCHER_SHIP
|
||||||
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
|
-- @extends AI.AI_Cargo_Dispatcher#AI_CARGO_DISPATCHER
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module AI.AI_Cargo_Ship
|
-- @module AI.AI_Cargo_Ship
|
||||||
-- @image AI_Cargo_Dispatching_For_Ship.JPG
|
-- @image AI_Cargo_Dispatcher.JPG
|
||||||
|
|
||||||
--- @type AI_CARGO_SHIP
|
--- @type AI_CARGO_SHIP
|
||||||
-- @extends AI.AI_Cargo#AI_CARGO
|
-- @extends AI.AI_Cargo#AI_CARGO
|
||||||
|
|||||||
@@ -1140,7 +1140,7 @@ end
|
|||||||
-- @param DCS#Vec3 CV2 Vec3
|
-- @param DCS#Vec3 CV2 Vec3
|
||||||
function AI_FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2)
|
function AI_FORMATION:FollowMe(FollowGroup, ClientUnit, CT1, CV1, CT2, CV2)
|
||||||
|
|
||||||
if FollowGroup:GetState( FollowGroup, "Mode" ) == self.__Enum.Mode.Formation then
|
if FollowGroup:GetState( FollowGroup, "Mode" ) == self.__Enum.Mode.Formation and not self:Is("Stopped") then
|
||||||
|
|
||||||
self:T({Mode=FollowGroup:GetState( FollowGroup, "Mode" )})
|
self:T({Mode=FollowGroup:GetState( FollowGroup, "Mode" )})
|
||||||
|
|
||||||
|
|||||||
@@ -725,7 +725,6 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local life = self.Controllable:GetLife() or 0
|
local life = self.Controllable:GetLife() or 0
|
||||||
if self.Controllable:IsAlive() and life > 1 then
|
if self.Controllable:IsAlive() and life > 1 then
|
||||||
-- Determine if the AIControllable is within the PatrolZone.
|
-- Determine if the AIControllable is within the PatrolZone.
|
||||||
@@ -745,7 +744,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
|||||||
self:T( "Not in the air, finding route path within PatrolZone" )
|
self:T( "Not in the air, finding route path within PatrolZone" )
|
||||||
local CurrentVec2 = self.Controllable:GetVec2()
|
local CurrentVec2 = self.Controllable:GetVec2()
|
||||||
if not CurrentVec2 then return end
|
if not CurrentVec2 then return end
|
||||||
--DONE: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
--Done: Create GetAltitude function for GROUP, and delete GetUnit(1).
|
||||||
local CurrentAltitude = self.Controllable:GetAltitude()
|
local CurrentAltitude = self.Controllable:GetAltitude()
|
||||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||||
|
|||||||
@@ -206,27 +206,29 @@
|
|||||||
-- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding.
|
-- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding.
|
||||||
-- Note that this option is optional, so can be omitted. The default value of the RR is 10 meters.
|
-- Note that this option is optional, so can be omitted. The default value of the RR is 10 meters.
|
||||||
--
|
--
|
||||||
-- ## 5.2) The \#CARGO tag to create CARGO_CRATE objects:
|
-- ## 5.2) The \#CARGO tag to create CARGO_CRATE or CARGO_SLINGLOAD objects:
|
||||||
--
|
--
|
||||||
-- You can also use the \#CARGO tag on **static** objects, including **static cargo** objects of the mission editor.
|
-- You can also use the \#CARGO tag on **static** objects, including **static cargo** objects of the mission editor.
|
||||||
--
|
--
|
||||||
-- For example, the following #CARGO naming in the **static name** of the object, will create a CARGO_CRATE object when the mission starts.
|
-- For example, the following #CARGO naming in the **static name** of the object, will create a CARGO_CRATE object when the mission starts.
|
||||||
--
|
--
|
||||||
-- `Static #CARGO(T=Workmaterials,RR=500,NR=25)`
|
-- `Static #CARGO(T=Workmaterials,C=CRATE,RR=500,NR=25)`
|
||||||
--
|
--
|
||||||
-- This will create a CARGO_CRATE object:
|
-- This will create a CARGO_CRATE object:
|
||||||
--
|
--
|
||||||
-- * with the group name `Static #CARGO`
|
-- * with the group name `Static #CARGO`
|
||||||
-- * is of type `Workmaterials`
|
-- * is of type `Workmaterials`
|
||||||
|
-- * is of category `CRATE` (as opposed to `SLING`)
|
||||||
-- * will report when a carrier is within 500 meters
|
-- * will report when a carrier is within 500 meters
|
||||||
-- * will board to carriers when the carrier is within 500 meters from the cargo object
|
-- * will board to carriers when the carrier is within 500 meters from the cargo object
|
||||||
-- * will disappear when the cargo is within 25 meters from the carrier during boarding
|
-- * will disappear when the cargo is within 25 meters from the carrier during boarding
|
||||||
--
|
--
|
||||||
-- So the overall syntax of the #CARGO naming tag and arguments are:
|
-- So the overall syntax of the #CARGO naming tag and arguments are:
|
||||||
--
|
--
|
||||||
-- `StaticName #CARGO(T=CargoTypeName,RR=Range,NR=Range)`
|
-- `StaticName #CARGO(T=CargoTypeName,C=Category,RR=Range,NR=Range)`
|
||||||
--
|
--
|
||||||
-- * **T=** Provide a text that contains the type name of the cargo object. This type name can be used to filter cargo within a SET_CARGO object.
|
-- * **T=** Provide a text that contains the type name of the cargo object. This type name can be used to filter cargo within a SET_CARGO object.
|
||||||
|
-- * **C=** Provide either `CRATE` or `SLING` to have this static created as a CARGO_CRATE or CARGO_SLINGLOAD respectivly.
|
||||||
-- * **RR=** Provide the minimal range in meters when the report to the carrier, and board to the carrier.
|
-- * **RR=** Provide the minimal range in meters when the report to the carrier, and board to the carrier.
|
||||||
-- Note that this option is optional, so can be omitted. The default value of the RR is 250 meters.
|
-- Note that this option is optional, so can be omitted. The default value of the RR is 250 meters.
|
||||||
-- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding.
|
-- * **NR=** Provide the maximum range in meters when the cargo units will be boarded within the carrier during boarding.
|
||||||
|
|||||||
@@ -0,0 +1,943 @@
|
|||||||
|
--- **Core** - A* Pathfinding.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Find path from A to B.
|
||||||
|
-- * Pre-defined as well as custom valid neighbour functions.
|
||||||
|
-- * Pre-defined as well as custom cost functions.
|
||||||
|
-- * Easy rectangular grid setup.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **funkyfranky**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Core.Astar
|
||||||
|
-- @image CORE_Astar.png
|
||||||
|
|
||||||
|
|
||||||
|
--- ASTAR class.
|
||||||
|
-- @type ASTAR
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #boolean Debug Debug mode. Messages to all about status.
|
||||||
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
|
-- @field #table nodes Table of nodes.
|
||||||
|
-- @field #number counter Node counter.
|
||||||
|
-- @field #number Nnodes Number of nodes.
|
||||||
|
-- @field #number nvalid Number of nvalid calls.
|
||||||
|
-- @field #number nvalidcache Number of cached valid evals.
|
||||||
|
-- @field #number ncost Number of cost evaluations.
|
||||||
|
-- @field #number ncostcache Number of cached cost evals.
|
||||||
|
-- @field #ASTAR.Node startNode Start node.
|
||||||
|
-- @field #ASTAR.Node endNode End node.
|
||||||
|
-- @field Core.Point#COORDINATE startCoord Start coordinate.
|
||||||
|
-- @field Core.Point#COORDINATE endCoord End coordinate.
|
||||||
|
-- @field #function ValidNeighbourFunc Function to check if a node is valid.
|
||||||
|
-- @field #table ValidNeighbourArg Optional arguments passed to the valid neighbour function.
|
||||||
|
-- @field #function CostFunc Function to calculate the heuristic "cost" to go from one node to another.
|
||||||
|
-- @field #table CostArg Optional arguments passed to the cost function.
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *When nothing goes right... Go left!*
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # The ASTAR Concept
|
||||||
|
--
|
||||||
|
-- Pathfinding algorithm.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Start and Goal
|
||||||
|
--
|
||||||
|
-- The first thing we need to define is obviously the place where we want to start and where we want to go eventually.
|
||||||
|
--
|
||||||
|
-- ## Start
|
||||||
|
--
|
||||||
|
-- The start
|
||||||
|
--
|
||||||
|
-- ## Goal
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Nodes
|
||||||
|
--
|
||||||
|
-- ## Rectangular Grid
|
||||||
|
--
|
||||||
|
-- A rectangular grid can be created using the @{#ASTAR.CreateGrid}(*ValidSurfaceTypes, BoxHY, SpaceX, deltaX, deltaY, MarkGrid*), where
|
||||||
|
--
|
||||||
|
-- * *ValidSurfaceTypes* is a table of valid surface types. By default all surface types are valid.
|
||||||
|
-- * *BoxXY* is the width of the grid perpendicular the the line between start and end node. Default is 40,000 meters (40 km).
|
||||||
|
-- * *SpaceX* is the additional space behind the start and end nodes. Default is 20,000 meters (20 km).
|
||||||
|
-- * *deltaX* is the grid spacing between nodes in the direction of start and end node. Default is 2,000 meters (2 km).
|
||||||
|
-- * *deltaY* is the grid spacing perpendicular to the direction of start and end node. Default is the same as *deltaX*.
|
||||||
|
-- * *MarkGrid* If set to *true*, this places marker on the F10 map on each grid node. Note that this can stall DCS if too many nodes are created.
|
||||||
|
--
|
||||||
|
-- ## Valid Surfaces
|
||||||
|
--
|
||||||
|
-- Certain unit types can only travel on certain surfaces types, for example
|
||||||
|
--
|
||||||
|
-- * Naval units can only travel on water (that also excludes shallow water in DCS currently),
|
||||||
|
-- * Ground units can only traval on land.
|
||||||
|
--
|
||||||
|
-- By restricting the surface type in the grid construction, we also reduce the number of nodes, which makes the algorithm more efficient.
|
||||||
|
--
|
||||||
|
-- ## Box Width (BoxHY)
|
||||||
|
--
|
||||||
|
-- The box width needs to be large enough to capture all paths you want to consider.
|
||||||
|
--
|
||||||
|
-- ## Space in X
|
||||||
|
--
|
||||||
|
-- The space in X value is important if the algorithm needs to to backwards from the start node or needs to extend even further than the end node.
|
||||||
|
--
|
||||||
|
-- ## Grid Spacing
|
||||||
|
--
|
||||||
|
-- The grid spacing is an important factor as it determines the number of nodes and hence the performance of the algorithm. It should be as large as possible.
|
||||||
|
-- However, if the value is too large, the algorithm might fail to get a valid path.
|
||||||
|
--
|
||||||
|
-- A good estimate of the grid spacing is to set it to be smaller (~ half the size) of the smallest gap you need to path.
|
||||||
|
--
|
||||||
|
-- # Valid Neighbours
|
||||||
|
--
|
||||||
|
-- The A* algorithm needs to know if a transition from one node to another is allowed or not. By default, hopping from one node to another is always possible.
|
||||||
|
--
|
||||||
|
-- ## Line of Sight
|
||||||
|
--
|
||||||
|
-- For naval
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Heuristic Cost
|
||||||
|
--
|
||||||
|
-- In order to determine the optimal path, the pathfinding algorithm needs to know, how costly it is to go from one node to another.
|
||||||
|
-- Often, this can simply be determined by the distance between two nodes. Therefore, the default cost function is set to be the 2D distance between two nodes.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Calculate the Path
|
||||||
|
--
|
||||||
|
-- Finally, we have to calculate the path. This is done by the @{ASTAR.GetPath}(*ExcludeStart, ExcludeEnd*) function. This function returns a table of nodes, which
|
||||||
|
-- describe the optimal path from the start node to the end node.
|
||||||
|
--
|
||||||
|
-- By default, the start and end node are include in the table that is returned.
|
||||||
|
--
|
||||||
|
-- Note that a valid path must not always exist. So you should check if the function returns *nil*.
|
||||||
|
--
|
||||||
|
-- Common reasons that a path cannot be found are:
|
||||||
|
--
|
||||||
|
-- * The grid is too small ==> increase grid size, e.g. *BoxHY* and/or *SpaceX* if you use a rectangular grid.
|
||||||
|
-- * The grid spacing is too large ==> decrease *deltaX* and/or *deltaY*
|
||||||
|
-- * There simply is no valid path ==> you are screwed :(
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- # Examples
|
||||||
|
--
|
||||||
|
-- ## Strait of Hormuz
|
||||||
|
--
|
||||||
|
-- Carrier Group finds its way through the Stait of Hormuz.
|
||||||
|
--
|
||||||
|
-- ##
|
||||||
|
--
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #ASTAR
|
||||||
|
ASTAR = {
|
||||||
|
ClassName = "ASTAR",
|
||||||
|
Debug = nil,
|
||||||
|
lid = nil,
|
||||||
|
nodes = {},
|
||||||
|
counter = 1,
|
||||||
|
Nnodes = 0,
|
||||||
|
ncost = 0,
|
||||||
|
ncostcache = 0,
|
||||||
|
nvalid = 0,
|
||||||
|
nvalidcache = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Node data.
|
||||||
|
-- @type ASTAR.Node
|
||||||
|
-- @field #number id Node id.
|
||||||
|
-- @field Core.Point#COORDINATE coordinate Coordinate of the node.
|
||||||
|
-- @field #number surfacetype Surface type.
|
||||||
|
-- @field #table valid Cached valid/invalid nodes.
|
||||||
|
-- @field #table cost Cached cost.
|
||||||
|
|
||||||
|
--- ASTAR infinity.
|
||||||
|
-- @field #number INF
|
||||||
|
ASTAR.INF=1/0
|
||||||
|
|
||||||
|
--- ASTAR class version.
|
||||||
|
-- @field #string version
|
||||||
|
ASTAR.version="0.4.0"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- TODO list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: Add more valid neighbour functions.
|
||||||
|
-- TODO: Write docs.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new ASTAR object.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:New()
|
||||||
|
|
||||||
|
-- Inherit everything from INTEL class.
|
||||||
|
local self=BASE:Inherit(self, BASE:New()) --#ASTAR
|
||||||
|
|
||||||
|
self.lid="ASTAR | "
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- User functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Set coordinate from where to start.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate Start coordinate.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetStartCoordinate(Coordinate)
|
||||||
|
|
||||||
|
self.startCoord=Coordinate
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set coordinate where you want to go.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate end coordinate.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetEndCoordinate(Coordinate)
|
||||||
|
|
||||||
|
self.endCoord=Coordinate
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a node from a given coordinate.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate The coordinate where to create the node.
|
||||||
|
-- @return #ASTAR.Node The node.
|
||||||
|
function ASTAR:GetNodeFromCoordinate(Coordinate)
|
||||||
|
|
||||||
|
local node={} --#ASTAR.Node
|
||||||
|
|
||||||
|
node.coordinate=Coordinate
|
||||||
|
node.surfacetype=Coordinate:GetSurfaceType()
|
||||||
|
node.id=self.counter
|
||||||
|
|
||||||
|
node.valid={}
|
||||||
|
node.cost={}
|
||||||
|
|
||||||
|
self.counter=self.counter+1
|
||||||
|
|
||||||
|
return node
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add a node to the table of grid nodes.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node Node The node to be added.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:AddNode(Node)
|
||||||
|
|
||||||
|
self.nodes[Node.id]=Node
|
||||||
|
self.Nnodes=self.Nnodes+1
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a node to the table of grid nodes specifying its coordinate.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate The coordinate where the node is created.
|
||||||
|
-- @return #ASTAR.Node The node.
|
||||||
|
function ASTAR:AddNodeFromCoordinate(Coordinate)
|
||||||
|
|
||||||
|
local node=self:GetNodeFromCoordinate(Coordinate)
|
||||||
|
|
||||||
|
self:AddNode(node)
|
||||||
|
|
||||||
|
return node
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if the coordinate of a node has is at a valid surface type.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node Node The node to be added.
|
||||||
|
-- @param #table SurfaceTypes Surface types, for example `{land.SurfaceType.WATER}`. By default all surface types are valid.
|
||||||
|
-- @return #boolean If true, surface type of node is valid.
|
||||||
|
function ASTAR:CheckValidSurfaceType(Node, SurfaceTypes)
|
||||||
|
|
||||||
|
if SurfaceTypes then
|
||||||
|
|
||||||
|
if type(SurfaceTypes)~="table" then
|
||||||
|
SurfaceTypes={SurfaceTypes}
|
||||||
|
end
|
||||||
|
|
||||||
|
for _,surface in pairs(SurfaceTypes) do
|
||||||
|
if surface==Node.surfacetype then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a function to determine if a neighbour of a node is valid.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #function NeighbourFunction Function that needs to return *true* for a neighbour to be valid.
|
||||||
|
-- @param ... Condition function arguments if any.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetValidNeighbourFunction(NeighbourFunction, ...)
|
||||||
|
|
||||||
|
self.ValidNeighbourFunc=NeighbourFunction
|
||||||
|
|
||||||
|
self.ValidNeighbourArg={}
|
||||||
|
if arg then
|
||||||
|
self.ValidNeighbourArg=arg
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set valid neighbours to require line of sight between two nodes.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #number CorridorWidth Width of LoS corridor in meters.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetValidNeighbourLoS(CorridorWidth)
|
||||||
|
|
||||||
|
self:SetValidNeighbourFunction(ASTAR.LoS, CorridorWidth)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set valid neighbours to be in a certain distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #number MaxDistance Max distance between nodes in meters. Default is 2000 m.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetValidNeighbourDistance(MaxDistance)
|
||||||
|
|
||||||
|
self:SetValidNeighbourFunction(ASTAR.DistMax, MaxDistance)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set valid neighbours to be in a certain distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #number MaxDistance Max distance between nodes in meters. Default is 2000 m.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetValidNeighbourRoad(MaxDistance)
|
||||||
|
|
||||||
|
self:SetValidNeighbourFunction(ASTAR.Road, MaxDistance)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the function which calculates the "cost" to go from one to another node.
|
||||||
|
-- The first to arguments of this function are always the two nodes under consideration. But you can add optional arguments.
|
||||||
|
-- Very often the distance between nodes is a good measure for the cost.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #function CostFunction Function that returns the "cost".
|
||||||
|
-- @param ... Condition function arguments if any.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetCostFunction(CostFunction, ...)
|
||||||
|
|
||||||
|
self.CostFunc=CostFunction
|
||||||
|
|
||||||
|
self.CostArg={}
|
||||||
|
if arg then
|
||||||
|
self.CostArg=arg
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set heuristic cost to go from one node to another to be their 2D distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetCostDist2D()
|
||||||
|
|
||||||
|
self:SetCostFunction(ASTAR.Dist2D)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set heuristic cost to go from one node to another to be their 3D distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetCostDist3D()
|
||||||
|
|
||||||
|
self:SetCostFunction(ASTAR.Dist3D)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set heuristic cost to go from one node to another to be their 3D distance.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:SetCostRoad()
|
||||||
|
|
||||||
|
self:SetCostFunction(ASTAR)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Grid functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a rectangular grid of nodes between star and end coordinate.
|
||||||
|
-- The coordinate system is oriented along the line between start and end point.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table ValidSurfaceTypes Valid surface types. By default is all surfaces are allowed.
|
||||||
|
-- @param #number BoxHY Box "height" in meters along the y-coordinate. Default 40000 meters (40 km).
|
||||||
|
-- @param #number SpaceX Additional space in meters before start and after end coordinate. Default 10000 meters (10 km).
|
||||||
|
-- @param #number deltaX Increment in the direction of start to end coordinate in meters. Default 2000 meters.
|
||||||
|
-- @param #number deltaY Increment perpendicular to the direction of start to end coordinate in meters. Default is same as deltaX.
|
||||||
|
-- @param #boolean MarkGrid If true, create F10 map markers at grid nodes.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:CreateGrid(ValidSurfaceTypes, BoxHY, SpaceX, deltaX, deltaY, MarkGrid)
|
||||||
|
|
||||||
|
-- Note that internally
|
||||||
|
-- x coordinate is z: x-->z Line from start to end
|
||||||
|
-- y coordinate is x: y-->x Perpendicular
|
||||||
|
|
||||||
|
-- Grid length and width.
|
||||||
|
local Dz=SpaceX or 10000
|
||||||
|
local Dx=BoxHY and BoxHY/2 or 20000
|
||||||
|
|
||||||
|
-- Increments.
|
||||||
|
local dz=deltaX or 2000
|
||||||
|
local dx=deltaY or dz
|
||||||
|
|
||||||
|
-- Heading from start to end coordinate.
|
||||||
|
local angle=self.startCoord:HeadingTo(self.endCoord)
|
||||||
|
|
||||||
|
--Distance between start and end.
|
||||||
|
local dist=self.startCoord:Get2DDistance(self.endCoord)+2*Dz
|
||||||
|
|
||||||
|
-- Origin of map. Needed to translate back to wanted position.
|
||||||
|
local co=COORDINATE:New(0, 0, 0)
|
||||||
|
local do1=co:Get2DDistance(self.startCoord)
|
||||||
|
local ho1=co:HeadingTo(self.startCoord)
|
||||||
|
|
||||||
|
-- Start of grid.
|
||||||
|
local xmin=-Dx
|
||||||
|
local zmin=-Dz
|
||||||
|
|
||||||
|
-- Number of grid points.
|
||||||
|
local nz=dist/dz+1
|
||||||
|
local nx=2*Dx/dx+1
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
local text=string.format("Building grid with nx=%d ny=%d => total=%d nodes", nx, nz, nx*nz)
|
||||||
|
self:T(self.lid..text)
|
||||||
|
|
||||||
|
-- Loop over x and z coordinate to create a 2D grid.
|
||||||
|
for i=1,nx do
|
||||||
|
|
||||||
|
-- x coordinate perpendicular to z.
|
||||||
|
local x=xmin+dx*(i-1)
|
||||||
|
|
||||||
|
for j=1,nz do
|
||||||
|
|
||||||
|
-- z coordinate connecting start and end.
|
||||||
|
local z=zmin+dz*(j-1)
|
||||||
|
|
||||||
|
-- Rotate 2D.
|
||||||
|
local vec3=UTILS.Rotate2D({x=x, y=0, z=z}, angle)
|
||||||
|
|
||||||
|
-- Coordinate of the node.
|
||||||
|
local c=COORDINATE:New(vec3.z, vec3.y, vec3.x):Translate(do1, ho1, true)
|
||||||
|
|
||||||
|
-- Create a node at this coordinate.
|
||||||
|
local node=self:GetNodeFromCoordinate(c)
|
||||||
|
|
||||||
|
-- Check if node has valid surface type.
|
||||||
|
if self:CheckValidSurfaceType(node, ValidSurfaceTypes) then
|
||||||
|
|
||||||
|
if MarkGrid then
|
||||||
|
c:MarkToAll(string.format("i=%d, j=%d surface=%d", i, j, node.surfacetype))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add node to grid.
|
||||||
|
self:AddNode(node)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
local text=string.format("Done building grid!")
|
||||||
|
self:T2(self.lid..text)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Valid neighbour functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Function to check if two nodes have line of sight (LoS).
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @param #number corridor (Optional) Width of corridor in meters.
|
||||||
|
-- @return #boolean If true, two nodes have LoS.
|
||||||
|
function ASTAR.LoS(nodeA, nodeB, corridor)
|
||||||
|
|
||||||
|
local offset=1
|
||||||
|
|
||||||
|
local dx=corridor and corridor/2 or nil
|
||||||
|
local dy=dx
|
||||||
|
|
||||||
|
local cA=nodeA.coordinate:GetVec3()
|
||||||
|
local cB=nodeB.coordinate:GetVec3()
|
||||||
|
cA.y=offset
|
||||||
|
cB.y=offset
|
||||||
|
|
||||||
|
local los=land.isVisible(cA, cB)
|
||||||
|
|
||||||
|
if los and corridor then
|
||||||
|
|
||||||
|
-- Heading from A to B.
|
||||||
|
local heading=nodeA.coordinate:HeadingTo(nodeB.coordinate)
|
||||||
|
|
||||||
|
local Ap=UTILS.VecTranslate(cA, dx, heading+90)
|
||||||
|
local Bp=UTILS.VecTranslate(cB, dx, heading+90)
|
||||||
|
|
||||||
|
los=land.isVisible(Ap, Bp)
|
||||||
|
|
||||||
|
if los then
|
||||||
|
|
||||||
|
local Am=UTILS.VecTranslate(cA, dx, heading-90)
|
||||||
|
local Bm=UTILS.VecTranslate(cB, dx, heading-90)
|
||||||
|
|
||||||
|
los=land.isVisible(Am, Bm)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return los
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to check if two nodes have a road connection.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @return #boolean If true, two nodes are connected via a road.
|
||||||
|
function ASTAR.Road(nodeA, nodeB)
|
||||||
|
|
||||||
|
local path=land.findPathOnRoads("roads", nodeA.coordinate.x, nodeA.coordinate.z, nodeB.coordinate.x, nodeB.coordinate.z)
|
||||||
|
|
||||||
|
if path then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to check if distance between two nodes is less than a threshold distance.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @param #number distmax Max distance in meters. Default is 2000 m.
|
||||||
|
-- @return #boolean If true, distance between the two nodes is below threshold.
|
||||||
|
function ASTAR.DistMax(nodeA, nodeB, distmax)
|
||||||
|
|
||||||
|
distmax=distmax or 2000
|
||||||
|
|
||||||
|
local dist=nodeA.coordinate:Get2DDistance(nodeB.coordinate)
|
||||||
|
|
||||||
|
return dist<=distmax
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Heuristic cost functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Heuristic cost is given by the 2D distance between the nodes.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @return #number Distance between the two nodes.
|
||||||
|
function ASTAR.Dist2D(nodeA, nodeB)
|
||||||
|
local dist=nodeA.coordinate:Get2DDistance(nodeB)
|
||||||
|
return dist
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Heuristic cost is given by the 3D distance between the nodes.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @return #number Distance between the two nodes.
|
||||||
|
function ASTAR.Dist3D(nodeA, nodeB)
|
||||||
|
local dist=nodeA.coordinate:Get3DDistance(nodeB.coordinate)
|
||||||
|
return dist
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Heuristic cost is given by the distance between the nodes on road.
|
||||||
|
-- @param #ASTAR.Node nodeA First node.
|
||||||
|
-- @param #ASTAR.Node nodeB Other node.
|
||||||
|
-- @return #number Distance between the two nodes.
|
||||||
|
function ASTAR.DistRoad(nodeA, nodeB)
|
||||||
|
|
||||||
|
-- Get the path.
|
||||||
|
local path=land.findPathOnRoads("roads", nodeA.coordinate.x, nodeA.coordinate.z, nodeB.coordinate.x, nodeB.coordinate.z)
|
||||||
|
|
||||||
|
if path then
|
||||||
|
|
||||||
|
local dist=0
|
||||||
|
|
||||||
|
for i=2,#path do
|
||||||
|
local b=path[i] --DCS#Vec2
|
||||||
|
local a=path[i-1] --DCS#Vec2
|
||||||
|
|
||||||
|
dist=dist+UTILS.VecDist2D(a,b)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return dist
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return math.huge
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Misc functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Find the closest node from a given coordinate.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param Core.Point#COORDINATE Coordinate.
|
||||||
|
-- @return #ASTAR.Node Cloest node to the coordinate.
|
||||||
|
-- @return #number Distance to closest node in meters.
|
||||||
|
function ASTAR:FindClosestNode(Coordinate)
|
||||||
|
|
||||||
|
local distMin=math.huge
|
||||||
|
local closeNode=nil
|
||||||
|
|
||||||
|
for _,_node in pairs(self.nodes) do
|
||||||
|
local node=_node --#ASTAR.Node
|
||||||
|
|
||||||
|
local dist=node.coordinate:Get2DDistance(Coordinate)
|
||||||
|
|
||||||
|
if dist<distMin then
|
||||||
|
distMin=dist
|
||||||
|
closeNode=node
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return closeNode, distMin
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Find the start node.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node Node The node to be added to the nodes table.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:FindStartNode()
|
||||||
|
|
||||||
|
local node, dist=self:FindClosestNode(self.startCoord)
|
||||||
|
|
||||||
|
self.startNode=node
|
||||||
|
|
||||||
|
if dist>1000 then
|
||||||
|
self:T(self.lid.."Adding start node to node grid!")
|
||||||
|
self:AddNode(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a node.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node Node The node to be added to the nodes table.
|
||||||
|
-- @return #ASTAR self
|
||||||
|
function ASTAR:FindEndNode()
|
||||||
|
|
||||||
|
local node, dist=self:FindClosestNode(self.endCoord)
|
||||||
|
|
||||||
|
self.endNode=node
|
||||||
|
|
||||||
|
if dist>1000 then
|
||||||
|
self:T(self.lid.."Adding end node to node grid!")
|
||||||
|
self:AddNode(node)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Main A* pathfinding function
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- A* pathfinding function. This seaches the path along nodes between start and end nodes/coordinates.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #boolean ExcludeStartNode If *true*, do not include start node in found path. Default is to include it.
|
||||||
|
-- @param #boolean ExcludeEndNode If *true*, do not include end node in found path. Default is to include it.
|
||||||
|
-- @return #table Table of nodes from start to finish.
|
||||||
|
function ASTAR:GetPath(ExcludeStartNode, ExcludeEndNode)
|
||||||
|
|
||||||
|
self:FindStartNode()
|
||||||
|
self:FindEndNode()
|
||||||
|
|
||||||
|
local nodes=self.nodes
|
||||||
|
local start=self.startNode
|
||||||
|
local goal=self.endNode
|
||||||
|
|
||||||
|
-- Sets.
|
||||||
|
local openset = {}
|
||||||
|
local closedset = {}
|
||||||
|
local came_from = {}
|
||||||
|
local g_score = {}
|
||||||
|
local f_score = {}
|
||||||
|
|
||||||
|
openset[start.id]=true
|
||||||
|
local Nopen=1
|
||||||
|
|
||||||
|
-- Initial scores.
|
||||||
|
g_score[start.id]=0
|
||||||
|
f_score[start.id]=g_score[start.id]+self:_HeuristicCost(start, goal)
|
||||||
|
|
||||||
|
-- Set start time.
|
||||||
|
local T0=timer.getAbsTime()
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
local text=string.format("Starting A* pathfinding with %d Nodes", self.Nnodes)
|
||||||
|
self:T(self.lid..text)
|
||||||
|
|
||||||
|
local Tstart=UTILS.GetOSTime()
|
||||||
|
|
||||||
|
-- Loop while we still have an open set.
|
||||||
|
while Nopen > 0 do
|
||||||
|
|
||||||
|
-- Get current node.
|
||||||
|
local current=self:_LowestFscore(openset, f_score)
|
||||||
|
|
||||||
|
-- Check if we are at the end node.
|
||||||
|
if current.id==goal.id then
|
||||||
|
|
||||||
|
local path=self:_UnwindPath({}, came_from, goal)
|
||||||
|
|
||||||
|
if not ExcludeEndNode then
|
||||||
|
table.insert(path, goal)
|
||||||
|
end
|
||||||
|
|
||||||
|
if ExcludeStartNode then
|
||||||
|
table.remove(path, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local Tstop=UTILS.GetOSTime()
|
||||||
|
|
||||||
|
local dT=nil
|
||||||
|
if Tstart and Tstop then
|
||||||
|
dT=Tstop-Tstart
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
local text=string.format("Found path with %d nodes (%d total)", #path, self.Nnodes)
|
||||||
|
if dT then
|
||||||
|
text=text..string.format(", OS Time %.6f sec", dT)
|
||||||
|
end
|
||||||
|
text=text..string.format(", Nvalid=%d [%d cached]", self.nvalid, self.nvalidcache)
|
||||||
|
text=text..string.format(", Ncost=%d [%d cached]", self.ncost, self.ncostcache)
|
||||||
|
self:T(self.lid..text)
|
||||||
|
|
||||||
|
return path
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Move Node from open to closed set.
|
||||||
|
openset[current.id]=nil
|
||||||
|
Nopen=Nopen-1
|
||||||
|
closedset[current.id]=true
|
||||||
|
|
||||||
|
-- Get neighbour nodes.
|
||||||
|
local neighbors=self:_NeighbourNodes(current, nodes)
|
||||||
|
|
||||||
|
-- Loop over neighbours.
|
||||||
|
for _,neighbor in pairs(neighbors) do
|
||||||
|
|
||||||
|
if self:_NotIn(closedset, neighbor.id) then
|
||||||
|
|
||||||
|
local tentative_g_score=g_score[current.id]+self:_DistNodes(current, neighbor)
|
||||||
|
|
||||||
|
if self:_NotIn(openset, neighbor.id) or tentative_g_score < g_score[neighbor.id] then
|
||||||
|
|
||||||
|
came_from[neighbor]=current
|
||||||
|
|
||||||
|
g_score[neighbor.id]=tentative_g_score
|
||||||
|
f_score[neighbor.id]=g_score[neighbor.id]+self:_HeuristicCost(neighbor, goal)
|
||||||
|
|
||||||
|
if self:_NotIn(openset, neighbor.id) then
|
||||||
|
-- Add to open set.
|
||||||
|
openset[neighbor.id]=true
|
||||||
|
Nopen=Nopen+1
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
local text=string.format("WARNING: Could NOT find valid path!")
|
||||||
|
self:E(self.lid..text)
|
||||||
|
MESSAGE:New(text, 60, "ASTAR"):ToAllIf(self.Debug)
|
||||||
|
|
||||||
|
return nil -- no valid path
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- A* pathfinding helper functions
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Heuristic "cost" function to go from node A to node B. Default is the distance between the nodes.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node nodeA Node A.
|
||||||
|
-- @param #ASTAR.Node nodeB Node B.
|
||||||
|
-- @return #number "Cost" to go from node A to node B.
|
||||||
|
function ASTAR:_HeuristicCost(nodeA, nodeB)
|
||||||
|
|
||||||
|
-- Counter.
|
||||||
|
self.ncost=self.ncost+1
|
||||||
|
|
||||||
|
-- Get chached cost if available.
|
||||||
|
local cost=nodeA.cost[nodeB.id]
|
||||||
|
if cost~=nil then
|
||||||
|
self.ncostcache=self.ncostcache+1
|
||||||
|
return cost
|
||||||
|
end
|
||||||
|
|
||||||
|
local cost=nil
|
||||||
|
if self.CostFunc then
|
||||||
|
cost=self.CostFunc(nodeA, nodeB, unpack(self.CostArg))
|
||||||
|
else
|
||||||
|
cost=self:_DistNodes(nodeA, nodeB)
|
||||||
|
end
|
||||||
|
|
||||||
|
nodeA.cost[nodeB.id]=cost
|
||||||
|
nodeB.cost[nodeA.id]=cost -- Symmetric problem.
|
||||||
|
|
||||||
|
return cost
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if going from a node to a neighbour is possible.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node node A node.
|
||||||
|
-- @param #ASTAR.Node neighbor Neighbour node.
|
||||||
|
-- @return #boolean If true, transition between nodes is possible.
|
||||||
|
function ASTAR:_IsValidNeighbour(node, neighbor)
|
||||||
|
|
||||||
|
-- Counter.
|
||||||
|
self.nvalid=self.nvalid+1
|
||||||
|
|
||||||
|
local valid=node.valid[neighbor.id]
|
||||||
|
if valid~=nil then
|
||||||
|
--env.info(string.format("Node %d has valid=%s neighbour %d", node.id, tostring(valid), neighbor.id))
|
||||||
|
self.nvalidcache=self.nvalidcache+1
|
||||||
|
return valid
|
||||||
|
end
|
||||||
|
|
||||||
|
local valid=nil
|
||||||
|
if self.ValidNeighbourFunc then
|
||||||
|
valid=self.ValidNeighbourFunc(node, neighbor, unpack(self.ValidNeighbourArg))
|
||||||
|
else
|
||||||
|
valid=true
|
||||||
|
end
|
||||||
|
|
||||||
|
node.valid[neighbor.id]=valid
|
||||||
|
neighbor.valid[node.id]=valid -- Symmetric problem.
|
||||||
|
|
||||||
|
return valid
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Calculate 2D distance between two nodes.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node nodeA Node A.
|
||||||
|
-- @param #ASTAR.Node nodeB Node B.
|
||||||
|
-- @return #number Distance between nodes in meters.
|
||||||
|
function ASTAR:_DistNodes(nodeA, nodeB)
|
||||||
|
return nodeA.coordinate:Get2DDistance(nodeB.coordinate)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function that calculates the lowest F score.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table set The set of nodes IDs.
|
||||||
|
-- @param #number f_score F score.
|
||||||
|
-- @return #ASTAR.Node Best node.
|
||||||
|
function ASTAR:_LowestFscore(set, f_score)
|
||||||
|
|
||||||
|
local lowest, bestNode = ASTAR.INF, nil
|
||||||
|
|
||||||
|
for nid,node in pairs(set) do
|
||||||
|
|
||||||
|
local score=f_score[nid]
|
||||||
|
|
||||||
|
if score<lowest then
|
||||||
|
lowest, bestNode = score, nid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self.nodes[bestNode]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to get valid neighbours of a node.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #ASTAR.Node theNode The node.
|
||||||
|
-- @param #table nodes Possible neighbours.
|
||||||
|
-- @param #table Valid neighbour nodes.
|
||||||
|
function ASTAR:_NeighbourNodes(theNode, nodes)
|
||||||
|
|
||||||
|
local neighbors = {}
|
||||||
|
|
||||||
|
for _,node in pairs(nodes) do
|
||||||
|
|
||||||
|
if theNode.id~=node.id then
|
||||||
|
|
||||||
|
local isvalid=self:_IsValidNeighbour(theNode, node)
|
||||||
|
|
||||||
|
if isvalid then
|
||||||
|
table.insert(neighbors, node)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return neighbors
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function to check if a node is not in a set.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table set Set of nodes.
|
||||||
|
-- @param #ASTAR.Node theNode The node to check.
|
||||||
|
-- @return #boolean If true, the node is not in the set.
|
||||||
|
function ASTAR:_NotIn(set, theNode)
|
||||||
|
return set[theNode]==nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Unwind path function.
|
||||||
|
-- @param #ASTAR self
|
||||||
|
-- @param #table flat_path Flat path.
|
||||||
|
-- @param #table map Map.
|
||||||
|
-- @param #ASTAR.Node current_node The current node.
|
||||||
|
-- @return #table Unwinded path.
|
||||||
|
function ASTAR:_UnwindPath( flat_path, map, current_node )
|
||||||
|
|
||||||
|
if map [current_node] then
|
||||||
|
table.insert (flat_path, 1, map[current_node])
|
||||||
|
return self:_UnwindPath(flat_path, map, map[current_node])
|
||||||
|
else
|
||||||
|
return flat_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -229,7 +229,8 @@ FORMATION = {
|
|||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @return #BASE
|
-- @return #BASE
|
||||||
function BASE:New()
|
function BASE:New()
|
||||||
local self = routines.utils.deepCopy( self ) -- Create a new self instance
|
--local self = routines.utils.deepCopy( self ) -- Create a new self instance
|
||||||
|
local self = UTILS.DeepCopy(self)
|
||||||
|
|
||||||
_ClassID = _ClassID + 1
|
_ClassID = _ClassID + 1
|
||||||
self.ClassID = _ClassID
|
self.ClassID = _ClassID
|
||||||
@@ -463,131 +464,152 @@ do -- Event Handling
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Event handling function prototypes
|
-- Event handling function prototypes - Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
|
|
||||||
--- Occurs whenever any unit in a mission fires a weapon. But not any machine gun or auto cannon based weapon, those are handled by EVENT.ShootingStart.
|
--- Occurs whenever any unit in a mission fires a weapon. But not any machine gun or autocannon based weapon, those are handled by EVENT.ShootingStart.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventShot
|
-- @function [parent=#BASE] OnEventShot
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs whenever an object is hit by a weapon.
|
--- Occurs whenever an object is hit by a weapon.
|
||||||
-- initiator : The unit object the fired the weapon.
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- weapon: Weapon object that hit the target.
|
-- initiator : The unit object the fired the weapon
|
||||||
|
-- weapon: Weapon object that hit the target
|
||||||
-- target: The Object that was hit.
|
-- target: The Object that was hit.
|
||||||
-- @function [parent=#BASE] OnEventHit
|
-- @function [parent=#BASE] OnEventHit
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an aircraft takes off from an airbase, farp, or ship.
|
--- Occurs when an aircraft takes off from an airbase, farp, or ship.
|
||||||
-- initiator : The unit that took off.
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- place: Object from where the AI took-off from. Can be an Airbase Object, FARP, or Ships.
|
-- initiator : The unit that tookoff
|
||||||
|
-- place: Object from where the AI took-off from. Can be an Airbase Object, FARP, or Ships
|
||||||
-- @function [parent=#BASE] OnEventTakeoff
|
-- @function [parent=#BASE] OnEventTakeoff
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an aircraft lands at an airbase, farp or ship
|
--- Occurs when an aircraft lands at an airbase, farp or ship
|
||||||
-- initiator : The unit that has landed.
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- place: Object that the unit landed on. Can be an Airbase Object, FARP, or Ships.
|
-- initiator : The unit that has landed
|
||||||
|
-- place: Object that the unit landed on. Can be an Airbase Object, FARP, or Ships
|
||||||
-- @function [parent=#BASE] OnEventLand
|
-- @function [parent=#BASE] OnEventLand
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any aircraft crashes into the ground and is completely destroyed.
|
--- Occurs when any aircraft crashes into the ground and is completely destroyed.
|
||||||
-- initiator : The unit that has crashed.
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that has crashed
|
||||||
-- @function [parent=#BASE] OnEventCrash
|
-- @function [parent=#BASE] OnEventCrash
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a pilot ejects from an aircraft
|
--- Occurs when a pilot ejects from an aircraft
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- initiator : The unit that has ejected
|
-- initiator : The unit that has ejected
|
||||||
-- @function [parent=#BASE] OnEventEjection
|
-- @function [parent=#BASE] OnEventEjection
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an aircraft connects with a tanker and begins taking on fuel.
|
--- Occurs when an aircraft connects with a tanker and begins taking on fuel.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- initiator : The unit that is receiving fuel.
|
-- initiator : The unit that is receiving fuel.
|
||||||
-- @function [parent=#BASE] OnEventRefueling
|
-- @function [parent=#BASE] OnEventRefueling
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an object is dead.
|
--- Occurs when an object is dead.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- initiator : The unit that is dead.
|
-- initiator : The unit that is dead.
|
||||||
-- @function [parent=#BASE] OnEventDead
|
-- @function [parent=#BASE] OnEventDead
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an object is completely destroyed.
|
--- Occurs when an Event for an object is triggered.
|
||||||
-- initiator : The unit that is was destroyed.
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that triggered the event.
|
||||||
-- @function [parent=#BASE] OnEvent
|
-- @function [parent=#BASE] OnEvent
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when the pilot of an aircraft is killed. Can occur either if the player is alive and crashes or if a weapon kills the pilot without completely destroying the plane.
|
--- Occurs when the pilot of an aircraft is killed. Can occur either if the player is alive and crashes or if a weapon kills the pilot without completely destroying the plane.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- initiator : The unit that the pilot has died in.
|
-- initiator : The unit that the pilot has died in.
|
||||||
-- @function [parent=#BASE] OnEventPilotDead
|
-- @function [parent=#BASE] OnEventPilotDead
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a ground unit captures either an airbase or a farp.
|
--- Occurs when a ground unit captures either an airbase or a farp.
|
||||||
-- initiator : The unit that captured the base.
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that captured the base
|
||||||
-- place: The airbase that was captured, can be a FARP or Airbase. When calling place:getCoalition() the faction will already be the new owning faction.
|
-- place: The airbase that was captured, can be a FARP or Airbase. When calling place:getCoalition() the faction will already be the new owning faction.
|
||||||
-- @function [parent=#BASE] OnEventBaseCaptured
|
-- @function [parent=#BASE] OnEventBaseCaptured
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a mission starts.
|
--- Occurs when a mission starts
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventMissionStart
|
-- @function [parent=#BASE] OnEventMissionStart
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a mission ends.
|
--- Occurs when a mission ends
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventMissionEnd
|
-- @function [parent=#BASE] OnEventMissionEnd
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when an aircraft is finished taking fuel.
|
--- Occurs when an aircraft is finished taking fuel.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- initiator : The unit that was receiving fuel.
|
-- initiator : The unit that was receiving fuel.
|
||||||
-- @function [parent=#BASE] OnEventRefuelingStop
|
-- @function [parent=#BASE] OnEventRefuelingStop
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any object is spawned into the mission.
|
--- Occurs when any object is spawned into the mission.
|
||||||
-- initiator : The unit that was spawned.
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that was spawned
|
||||||
-- @function [parent=#BASE] OnEventBirth
|
-- @function [parent=#BASE] OnEventBirth
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any system fails on a human controlled aircraft.
|
--- Occurs when any system fails on a human controlled aircraft.
|
||||||
-- initiator : The unit that had the failure.
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that had the failure
|
||||||
-- @function [parent=#BASE] OnEventHumanFailure
|
-- @function [parent=#BASE] OnEventHumanFailure
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any aircraft starts its engines.
|
--- Occurs when any aircraft starts its engines.
|
||||||
-- initiator : The unit that is starting its engines..
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that is starting its engines.
|
||||||
-- @function [parent=#BASE] OnEventEngineStartup
|
-- @function [parent=#BASE] OnEventEngineStartup
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any aircraft shuts down its engines.
|
--- Occurs when any aircraft shuts down its engines.
|
||||||
-- initiator : The unit that is stopping its engines..
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
|
-- initiator : The unit that is stopping its engines.
|
||||||
-- @function [parent=#BASE] OnEventEngineShutdown
|
-- @function [parent=#BASE] OnEventEngineShutdown
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any player assumes direct control of a unit.
|
--- Occurs when any player assumes direct control of a unit. Note - not Mulitplayer safe. Use PlayerEnterAircraft.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- initiator : The unit that is being taken control of.
|
-- initiator : The unit that is being taken control of.
|
||||||
-- @function [parent=#BASE] OnEventPlayerEnterUnit
|
-- @function [parent=#BASE] OnEventPlayerEnterUnit
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any player relieves control of a unit to the AI.
|
--- Occurs when any player relieves control of a unit to the AI.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- initiator : The unit that the player left.
|
-- initiator : The unit that the player left.
|
||||||
-- @function [parent=#BASE] OnEventPlayerLeaveUnit
|
-- @function [parent=#BASE] OnEventPlayerLeaveUnit
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any unit begins firing a weapon that has a high rate of fire. Most common with aircraft cannons (GAU-8), auto cannons, and machine guns.
|
--- Occurs when any unit begins firing a weapon that has a high rate of fire. Most common with aircraft cannons (GAU-8), autocannons, and machine guns.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- initiator : The unit that is doing the shooting.
|
-- initiator : The unit that is doing the shooting.
|
||||||
-- target: The unit that is being targeted.
|
-- target: The unit that is being targeted.
|
||||||
-- @function [parent=#BASE] OnEventShootingStart
|
-- @function [parent=#BASE] OnEventShootingStart
|
||||||
@@ -595,24 +617,28 @@ do -- Event Handling
|
|||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when any unit stops firing its weapon. Event will always correspond with a shooting start event.
|
--- Occurs when any unit stops firing its weapon. Event will always correspond with a shooting start event.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- initiator : The unit that was doing the shooting.
|
-- initiator : The unit that was doing the shooting.
|
||||||
-- @function [parent=#BASE] OnEventShootingEnd
|
-- @function [parent=#BASE] OnEventShootingEnd
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a new mark was added.
|
--- Occurs when a new mark was added.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- MarkID: ID of the mark.
|
-- MarkID: ID of the mark.
|
||||||
-- @function [parent=#BASE] OnEventMarkAdded
|
-- @function [parent=#BASE] OnEventMarkAdded
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a mark was removed.
|
--- Occurs when a mark was removed.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- MarkID: ID of the mark.
|
-- MarkID: ID of the mark.
|
||||||
-- @function [parent=#BASE] OnEventMarkRemoved
|
-- @function [parent=#BASE] OnEventMarkRemoved
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a mark text was changed.
|
--- Occurs when a mark text was changed.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- MarkID: ID of the mark.
|
-- MarkID: ID of the mark.
|
||||||
-- @function [parent=#BASE] OnEventMarkChange
|
-- @function [parent=#BASE] OnEventMarkChange
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
@@ -628,13 +654,15 @@ do -- Event Handling
|
|||||||
|
|
||||||
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
|
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
|
||||||
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
|
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventScore
|
-- @function [parent=#BASE] OnEventScore
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs on the death of a unit. Contains more and different information. Similar to unit_lost it will occur for aircraft before the aircraft crash event occurs.
|
--- Occurs on the death of a unit. Contains more and different information. Similar to unit_lost it will occur for aircraft before the aircraft crash event occurs.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
--
|
--
|
||||||
-- * initiator: The unit that killed the target.
|
-- * initiator: The unit that killed the target
|
||||||
-- * target: Target Object
|
-- * target: Target Object
|
||||||
-- * weapon: Weapon Object
|
-- * weapon: Weapon Object
|
||||||
--
|
--
|
||||||
@@ -644,11 +672,13 @@ do -- Event Handling
|
|||||||
|
|
||||||
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
|
--- Occurs when any modification to the "Score" as seen on the debrief menu would occur.
|
||||||
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
|
-- There is no information on what values the score was changed to. Event is likely similar to player_comment in this regard.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventScore
|
-- @function [parent=#BASE] OnEventScore
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when the game thinks an object is destroyed.
|
--- Occurs when the game thinks an object is destroyed.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
--
|
--
|
||||||
-- * initiator: The unit that is was destroyed.
|
-- * initiator: The unit that is was destroyed.
|
||||||
--
|
--
|
||||||
@@ -657,6 +687,7 @@ do -- Event Handling
|
|||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs shortly after the landing animation of an ejected pilot touching the ground and standing up. Event does not occur if the pilot lands in the water and sub combs to Davey Jones Locker.
|
--- Occurs shortly after the landing animation of an ejected pilot touching the ground and standing up. Event does not occur if the pilot lands in the water and sub combs to Davey Jones Locker.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
--
|
--
|
||||||
-- * initiator: Static object representing the ejected pilot. Place : Aircraft that the pilot ejected from.
|
-- * initiator: Static object representing the ejected pilot. Place : Aircraft that the pilot ejected from.
|
||||||
-- * place: may not return as a valid object if the aircraft has crashed into the ground and no longer exists.
|
-- * place: may not return as a valid object if the aircraft has crashed into the ground and no longer exists.
|
||||||
@@ -667,36 +698,43 @@ do -- Event Handling
|
|||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Paratrooper landing.
|
--- Paratrooper landing.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventParatrooperLanding
|
-- @function [parent=#BASE] OnEventParatrooperLanding
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Discard chair after ejection.
|
--- Discard chair after ejection.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventDiscardChairAfterEjection
|
-- @function [parent=#BASE] OnEventDiscardChairAfterEjection
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Weapon add. Fires when entering a mission per pylon with the name of the weapon (double pylons not counted, infinite wep reload not counted.
|
--- Weapon add. Fires when entering a mission per pylon with the name of the weapon (double pylons not counted, infinite wep reload not counted.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventParatrooperLanding
|
-- @function [parent=#BASE] OnEventParatrooperLanding
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Trigger zone.
|
--- Trigger zone.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventTriggerZone
|
-- @function [parent=#BASE] OnEventTriggerZone
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Landing quality mark.
|
--- Landing quality mark.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventLandingQualityMark
|
-- @function [parent=#BASE] OnEventLandingQualityMark
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- BDA.
|
--- BDA.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- @function [parent=#BASE] OnEventBDA
|
-- @function [parent=#BASE] OnEventBDA
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
-- @param Core.Event#EVENTDATA EventData The EventData structure.
|
||||||
|
|
||||||
--- Occurs when a player enters a slot and takes control of an aircraft.
|
--- Occurs when a player enters a slot and takes control of an aircraft.
|
||||||
|
-- Have a look at the class @{Core.EVENT#EVENT} as these are just the prototypes.
|
||||||
-- **NOTE**: This is a workaround of a long standing DCS bug with the PLAYER_ENTER_UNIT event.
|
-- **NOTE**: This is a workaround of a long standing DCS bug with the PLAYER_ENTER_UNIT event.
|
||||||
-- initiator : The unit that is being taken control of.
|
-- initiator : The unit that is being taken control of.
|
||||||
-- @function [parent=#BASE] OnEventPlayerEnterAircraft
|
-- @function [parent=#BASE] OnEventPlayerEnterAircraft
|
||||||
@@ -744,18 +782,35 @@ function BASE:CreateEventCrash( EventTime, Initiator, IniObjectCategory )
|
|||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Creation of a Crash Event.
|
||||||
|
-- @param #BASE self
|
||||||
|
-- @param DCS#Time EventTime The time stamp of the event.
|
||||||
|
-- @param DCS#Object Initiator The initiating object of the event.
|
||||||
|
function BASE:CreateEventUnitLost(EventTime, Initiator)
|
||||||
|
self:F( { EventTime, Initiator } )
|
||||||
|
|
||||||
|
local Event = {
|
||||||
|
id = world.event.S_EVENT_UNIT_LOST,
|
||||||
|
time = EventTime,
|
||||||
|
initiator = Initiator,
|
||||||
|
}
|
||||||
|
|
||||||
|
world.onEvent( Event )
|
||||||
|
end
|
||||||
|
|
||||||
--- Creation of a Dead Event.
|
--- Creation of a Dead Event.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param DCS#Time EventTime The time stamp of the event.
|
-- @param DCS#Time EventTime The time stamp of the event.
|
||||||
-- @param DCS#Object Initiator The initiating object of the event.
|
-- @param DCS#Object Initiator The initiating object of the event.
|
||||||
function BASE:CreateEventDead( EventTime, Initiator )
|
function BASE:CreateEventDead( EventTime, Initiator, IniObjectCategory )
|
||||||
self:F( { EventTime, Initiator } )
|
self:F( { EventTime, Initiator, IniObjectCategory } )
|
||||||
|
|
||||||
local Event = {
|
local Event = {
|
||||||
id = world.event.S_EVENT_DEAD,
|
id = world.event.S_EVENT_DEAD,
|
||||||
time = EventTime,
|
time = EventTime,
|
||||||
initiator = Initiator,
|
initiator = Initiator,
|
||||||
}
|
IniObjectCategory = IniObjectCategory,
|
||||||
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
@@ -792,22 +847,21 @@ function BASE:CreateEventTakeoff( EventTime, Initiator )
|
|||||||
world.onEvent( Event )
|
world.onEvent( Event )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Creation of a `S_EVENT_PLAYER_ENTER_AIRCRAFT` event.
|
--- Creation of a `S_EVENT_PLAYER_ENTER_AIRCRAFT` event.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param Wrapper.Unit#UNIT PlayerUnit The aircraft unit the player entered.
|
-- @param Wrapper.Unit#UNIT PlayerUnit The aircraft unit the player entered.
|
||||||
function BASE:CreateEventPlayerEnterAircraft( PlayerUnit )
|
function BASE:CreateEventPlayerEnterAircraft( PlayerUnit )
|
||||||
self:F( { PlayerUnit } )
|
self:F( { PlayerUnit } )
|
||||||
|
|
||||||
local Event = {
|
local Event = {
|
||||||
id = EVENTS.PlayerEnterAircraft,
|
id = EVENTS.PlayerEnterAircraft,
|
||||||
time = timer.getTime(),
|
time = timer.getTime(),
|
||||||
initiator = PlayerUnit:GetDCSObject(),
|
initiator = PlayerUnit:GetDCSObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
world.onEvent( Event )
|
world.onEvent(Event)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO: Complete DCS#Event structure.
|
|
||||||
--- The main event handling function... This function captures all events generated for the class.
|
--- The main event handling function... This function captures all events generated for the class.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param DCS#Event event
|
-- @param DCS#Event event
|
||||||
@@ -846,31 +900,37 @@ do -- Scheduling
|
|||||||
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
||||||
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
||||||
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
||||||
-- @return #number The ScheduleID of the planned schedule.
|
-- @return #string The Schedule ID of the planned schedule.
|
||||||
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
||||||
self:F2( { Start } )
|
|
||||||
self:T3( { ... } )
|
|
||||||
|
|
||||||
|
-- Object name.
|
||||||
local ObjectName = "-"
|
local ObjectName = "-"
|
||||||
ObjectName = self.ClassName .. self.ClassID
|
ObjectName = self.ClassName .. self.ClassID
|
||||||
|
|
||||||
self:F3( { "ScheduleOnce: ", ObjectName, Start } )
|
-- Debug info.
|
||||||
|
self:F3( { "ScheduleOnce: ", ObjectName, Start } )
|
||||||
|
|
||||||
if not self.Scheduler then
|
if not self.Scheduler then
|
||||||
self.Scheduler = SCHEDULER:New( self )
|
self.Scheduler = SCHEDULER:New( self )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- FF this was wrong!
|
||||||
|
--[[
|
||||||
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
||||||
self,
|
self,
|
||||||
SchedulerFunction,
|
SchedulerFunction,
|
||||||
{ ... },
|
{ ... },
|
||||||
Start,
|
Start,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil
|
nil
|
||||||
)
|
)
|
||||||
|
]]
|
||||||
|
|
||||||
self._.Schedules[#self._.Schedules + 1] = ScheduleID
|
-- NOTE: MasterObject (first parameter) needs to be nil or it will be the first argument passed to the SchedulerFunction!
|
||||||
|
local ScheduleID = self.Scheduler:Schedule(nil, SchedulerFunction, {...}, Start)
|
||||||
|
|
||||||
|
self._.Schedules[#self._.Schedules+1] = ScheduleID
|
||||||
|
|
||||||
return self._.Schedules[#self._.Schedules]
|
return self._.Schedules[#self._.Schedules]
|
||||||
end
|
end
|
||||||
@@ -883,7 +943,7 @@ do -- Scheduling
|
|||||||
-- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped.
|
-- @param #number Stop Specifies the amount of seconds when the scheduler will be stopped.
|
||||||
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
||||||
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
||||||
-- @return #number The ScheduleID of the planned schedule.
|
-- @return #string The Schedule ID of the planned schedule.
|
||||||
function BASE:ScheduleRepeat( Start, Repeat, RandomizeFactor, Stop, SchedulerFunction, ... )
|
function BASE:ScheduleRepeat( Start, Repeat, RandomizeFactor, Stop, SchedulerFunction, ... )
|
||||||
self:F2( { Start } )
|
self:F2( { Start } )
|
||||||
self:T3( { ... } )
|
self:T3( { ... } )
|
||||||
@@ -897,31 +957,32 @@ do -- Scheduling
|
|||||||
self.Scheduler = SCHEDULER:New( self )
|
self.Scheduler = SCHEDULER:New( self )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- NOTE: MasterObject (first parameter) should(!) be nil as it will be the first argument passed to the SchedulerFunction!
|
||||||
local ScheduleID = self.Scheduler:Schedule(
|
local ScheduleID = self.Scheduler:Schedule(
|
||||||
self,
|
nil,
|
||||||
SchedulerFunction,
|
SchedulerFunction,
|
||||||
{ ... },
|
{ ... },
|
||||||
Start,
|
Start,
|
||||||
Repeat,
|
Repeat,
|
||||||
RandomizeFactor,
|
RandomizeFactor,
|
||||||
Stop,
|
Stop,
|
||||||
4
|
4
|
||||||
)
|
)
|
||||||
|
|
||||||
self._.Schedules[#self._.Schedules + 1] = ScheduleID
|
self._.Schedules[#self._.Schedules+1] = ScheduleID
|
||||||
|
|
||||||
return self._.Schedules[#self._.Schedules]
|
return self._.Schedules[#self._.Schedules]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Stops the Schedule.
|
--- Stops the Schedule.
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
-- @param #string SchedulerID (Optional) Scheduler ID to be stopped. If nil, all pending schedules are stopped.
|
||||||
function BASE:ScheduleStop( SchedulerFunction )
|
function BASE:ScheduleStop( SchedulerID )
|
||||||
|
|
||||||
self:F3( { "ScheduleStop:" } )
|
self:F3( { "ScheduleStop:" } )
|
||||||
|
|
||||||
if self.Scheduler then
|
if self.Scheduler then
|
||||||
_SCHEDULEDISPATCHER:Stop( self.Scheduler, self._.Schedules[SchedulerFunction] )
|
--_SCHEDULEDISPATCHER:Stop( self.Scheduler, self._.Schedules[SchedulerFunction] )
|
||||||
|
_SCHEDULEDISPATCHER:Stop(self.Scheduler, SchedulerID)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1062,7 +1123,7 @@ end
|
|||||||
|
|
||||||
--- Set tracing for a class
|
--- Set tracing for a class
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param #string Class
|
-- @param #string Class Class name.
|
||||||
function BASE:TraceClass( Class )
|
function BASE:TraceClass( Class )
|
||||||
_TraceClass[Class] = true
|
_TraceClass[Class] = true
|
||||||
_TraceClassMethod[Class] = {}
|
_TraceClassMethod[Class] = {}
|
||||||
@@ -1071,8 +1132,8 @@ end
|
|||||||
|
|
||||||
--- Set tracing for a specific method of class
|
--- Set tracing for a specific method of class
|
||||||
-- @param #BASE self
|
-- @param #BASE self
|
||||||
-- @param #string Class
|
-- @param #string Class Class name.
|
||||||
-- @param #string Method
|
-- @param #string Method Method.
|
||||||
function BASE:TraceClassMethod( Class, Method )
|
function BASE:TraceClassMethod( Class, Method )
|
||||||
if not _TraceClassMethod[Class] then
|
if not _TraceClassMethod[Class] then
|
||||||
_TraceClassMethod[Class] = {}
|
_TraceClassMethod[Class] = {}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
--
|
--
|
||||||
-- After attaching a @{#BEACON} to your @{Wrapper.Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want.
|
-- After attaching a @{#BEACON} to your @{Wrapper.Positionable#POSITIONABLE}, you need to select the right function to activate the kind of beacon you want.
|
||||||
-- There are two types of BEACONs available : the (aircraft) TACAN Beacon and the general purpose Radio Beacon.
|
-- There are two types of BEACONs available : the (aircraft) TACAN Beacon and the general purpose Radio Beacon.
|
||||||
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very useful to simulate the battery time if your BEACON is
|
-- Note that in both case, you can set an optional parameter : the `BeaconDuration`. This can be very usefull to simulate the battery time if your BEACON is
|
||||||
-- attach to a cargo crate, for exemple.
|
-- attach to a cargo crate, for exemple.
|
||||||
--
|
--
|
||||||
-- ## Aircraft TACAN Beacon usage
|
-- ## Aircraft TACAN Beacon usage
|
||||||
@@ -265,13 +265,12 @@ function BEACON:ActivateLink4(Frequency, Morse, Duration)
|
|||||||
|
|
||||||
-- Stop sheduler
|
-- Stop sheduler
|
||||||
if Duration then -- Schedule the stop of the BEACON if asked by the MD
|
if Duration then -- Schedule the stop of the BEACON if asked by the MD
|
||||||
self.Positionable:DeactivateLink4(Duration)
|
self.Positionable:CommandDeactivateLink4(Duration)
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- DEPRECATED: Please use @{BEACON:ActivateTACAN}() instead.
|
--- DEPRECATED: Please use @{BEACON:ActivateTACAN}() instead.
|
||||||
-- Activates a TACAN BEACON on an Aircraft.
|
-- Activates a TACAN BEACON on an Aircraft.
|
||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
@@ -430,7 +429,7 @@ function BEACON:RadioBeacon(FileName, Frequency, Modulation, Power, BeaconDurati
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Stop the Radio Beacon
|
--- Stops the Radio Beacon
|
||||||
-- @param #BEACON self
|
-- @param #BEACON self
|
||||||
-- @return #BEACON self
|
-- @return #BEACON self
|
||||||
function BEACON:StopRadioBeacon()
|
function BEACON:StopRadioBeacon()
|
||||||
|
|||||||
@@ -0,0 +1,295 @@
|
|||||||
|
--- **Core** - Define any or all conditions to be evaluated.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Add arbitrary numbers of conditon functions
|
||||||
|
-- * Evaluate *any* or *all* conditions
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Example Missions:
|
||||||
|
--
|
||||||
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Operation).
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **funkyfranky**
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
-- @module Core.Condition
|
||||||
|
-- @image Core_Conditon.png
|
||||||
|
|
||||||
|
--- CONDITON class.
|
||||||
|
-- @type CONDITION
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
|
-- @field #boolean isAny General functions are evaluated as any condition.
|
||||||
|
-- @field #boolean negateResult Negeate result of evaluation.
|
||||||
|
-- @field #table functionsGen General condition functions.
|
||||||
|
-- @field #table functionsAny Any condition functions.
|
||||||
|
-- @field #table functionsAll All condition functions.
|
||||||
|
--
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
--- *Better three hours too soon than a minute too late.* - William Shakespeare
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # The CONDITION Concept
|
||||||
|
--
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #CONDITION
|
||||||
|
CONDITION = {
|
||||||
|
ClassName = "CONDITION",
|
||||||
|
lid = nil,
|
||||||
|
functionsGen = {},
|
||||||
|
functionsAny = {},
|
||||||
|
functionsAll = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Condition function.
|
||||||
|
-- @type CONDITION.Function
|
||||||
|
-- @field #function func Callback function to check for a condition. Should return a `#boolean`.
|
||||||
|
-- @field #table arg (Optional) Arguments passed to the condition callback function if any.
|
||||||
|
|
||||||
|
--- CONDITION class version.
|
||||||
|
-- @field #string version
|
||||||
|
CONDITION.version="0.1.0"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- TODO list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: Make FSM.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new CONDITION object.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #string Name (Optional) Name used in the logs.
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:New(Name)
|
||||||
|
|
||||||
|
-- Inherit BASE.
|
||||||
|
local self=BASE:Inherit(self, BASE:New()) --#CONDITION
|
||||||
|
|
||||||
|
self.name=Name or "Condition X"
|
||||||
|
|
||||||
|
self.lid=string.format("%s | ", self.name)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set that general condition functions return `true` if `any` function returns `true`. Default is that *all* functions must return `true`.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #boolean Any If `true`, *any* condition can be true. Else *all* conditions must result `true`.
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:SetAny(Any)
|
||||||
|
self.isAny=Any
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Negate result.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #boolean Negate If `true`, result is negated else not.
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:SetNegateResult(Negate)
|
||||||
|
self.negateResult=Negate
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #function Function The function to call.
|
||||||
|
-- @param ... (Optional) Parameters passed to the function (if any).
|
||||||
|
--
|
||||||
|
-- @usage
|
||||||
|
-- local function isAequalB(a, b)
|
||||||
|
-- return a==b
|
||||||
|
-- end
|
||||||
|
--
|
||||||
|
-- myCondition:AddFunction(isAequalB, a, b)
|
||||||
|
--
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:AddFunction(Function, ...)
|
||||||
|
|
||||||
|
-- Condition function.
|
||||||
|
local condition=self:_CreateCondition(Function, ...)
|
||||||
|
|
||||||
|
-- Add to table.
|
||||||
|
table.insert(self.functionsGen, condition)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #function Function The function to call.
|
||||||
|
-- @param ... (Optional) Parameters passed to the function (if any).
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:AddFunctionAny(Function, ...)
|
||||||
|
|
||||||
|
-- Condition function.
|
||||||
|
local condition=self:_CreateCondition(Function, ...)
|
||||||
|
|
||||||
|
-- Add to table.
|
||||||
|
table.insert(self.functionsAny, condition)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a function that is evaluated. It must return a `#boolean` value, *i.e.* either `true` or `false` (or `nil`).
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #function Function The function to call.
|
||||||
|
-- @param ... (Optional) Parameters passed to the function (if any).
|
||||||
|
-- @return #CONDITION self
|
||||||
|
function CONDITION:AddFunctionAll(Function, ...)
|
||||||
|
|
||||||
|
-- Condition function.
|
||||||
|
local condition=self:_CreateCondition(Function, ...)
|
||||||
|
|
||||||
|
-- Add to table.
|
||||||
|
table.insert(self.functionsAll, condition)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Evaluate conditon functions.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #boolean AnyTrue If `true`, evaluation return `true` if *any* condition function returns `true`. By default, *all* condition functions must return true.
|
||||||
|
-- @return #boolean Result of condition functions.
|
||||||
|
function CONDITION:Evaluate(AnyTrue)
|
||||||
|
|
||||||
|
-- Check if at least one function was given.
|
||||||
|
if #self.functionsAll + #self.functionsAny + #self.functionsAll == 0 then
|
||||||
|
if self.negateResult then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Any condition for gen.
|
||||||
|
local evalAny=self.isAny
|
||||||
|
if AnyTrue~=nil then
|
||||||
|
evalAny=AnyTrue
|
||||||
|
end
|
||||||
|
|
||||||
|
local isGen=nil
|
||||||
|
if evalAny then
|
||||||
|
isGen=self:_EvalConditionsAny(self.functionsGen)
|
||||||
|
else
|
||||||
|
isGen=self:_EvalConditionsAll(self.functionsGen)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Is any?
|
||||||
|
local isAny=self:_EvalConditionsAny(self.functionsAny)
|
||||||
|
|
||||||
|
-- Is all?
|
||||||
|
local isAll=self:_EvalConditionsAll(self.functionsAll)
|
||||||
|
|
||||||
|
-- Result.
|
||||||
|
local result=isGen and isAny and isAll
|
||||||
|
|
||||||
|
-- Negate result.
|
||||||
|
if self.negateResult then
|
||||||
|
result=not result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Debug message.
|
||||||
|
self:T(self.lid..string.format("Evaluate: isGen=%s, isAny=%s, isAll=%s (negate=%s) ==> result=%s", tostring(isGen), tostring(isAny), tostring(isAll), tostring(self.negateResult), tostring(result)))
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if all given condition are true.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #table functions Functions to evaluate.
|
||||||
|
-- @return #boolean If true, all conditions were true (or functions was empty/nil). Returns false if at least one condition returned false.
|
||||||
|
function CONDITION:_EvalConditionsAll(functions)
|
||||||
|
|
||||||
|
-- At least one condition?
|
||||||
|
local gotone=false
|
||||||
|
|
||||||
|
|
||||||
|
-- Any stop condition must be true.
|
||||||
|
for _,_condition in pairs(functions or {}) do
|
||||||
|
local condition=_condition --#CONDITION.Function
|
||||||
|
|
||||||
|
-- At least one condition was defined.
|
||||||
|
gotone=true
|
||||||
|
|
||||||
|
-- Call function.
|
||||||
|
local istrue=condition.func(unpack(condition.arg))
|
||||||
|
|
||||||
|
-- Any false will return false.
|
||||||
|
if not istrue then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- All conditions were true.
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Check if any of the given conditions is true.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #table functions Functions to evaluate.
|
||||||
|
-- @return #boolean If true, at least one condition is true (or functions was emtpy/nil).
|
||||||
|
function CONDITION:_EvalConditionsAny(functions)
|
||||||
|
|
||||||
|
-- At least one condition?
|
||||||
|
local gotone=false
|
||||||
|
|
||||||
|
-- Any stop condition must be true.
|
||||||
|
for _,_condition in pairs(functions or {}) do
|
||||||
|
local condition=_condition --#CONDITION.Function
|
||||||
|
|
||||||
|
-- At least one condition was defined.
|
||||||
|
gotone=true
|
||||||
|
|
||||||
|
-- Call function.
|
||||||
|
local istrue=condition.func(unpack(condition.arg))
|
||||||
|
|
||||||
|
-- Any true will return true.
|
||||||
|
if istrue then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- No condition was true.
|
||||||
|
if gotone then
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
-- No functions passed.
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create conditon function object.
|
||||||
|
-- @param #CONDITION self
|
||||||
|
-- @param #function Function The function to call.
|
||||||
|
-- @param ... (Optional) Parameters passed to the function (if any).
|
||||||
|
-- @return #CONDITION.Function Condition function.
|
||||||
|
function CONDITION:_CreateCondition(Function, ...)
|
||||||
|
|
||||||
|
local condition={} --#CONDITION.Function
|
||||||
|
|
||||||
|
condition.func=Function
|
||||||
|
condition.arg={}
|
||||||
|
if arg then
|
||||||
|
condition.arg=arg
|
||||||
|
end
|
||||||
|
|
||||||
|
return condition
|
||||||
|
end
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -405,7 +405,7 @@ do -- FSM
|
|||||||
Transition.To = To
|
Transition.To = To
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
self:T2( Transition )
|
--self:T3( Transition )
|
||||||
|
|
||||||
self._Transitions[Transition] = Transition
|
self._Transitions[Transition] = Transition
|
||||||
self:_eventmap( self.Events, Transition )
|
self:_eventmap( self.Events, Transition )
|
||||||
@@ -426,7 +426,7 @@ do -- FSM
|
|||||||
-- @param #table ReturnEvents A table indicating for which returned events of the SubFSM which Event must be triggered in the FSM.
|
-- @param #table ReturnEvents A table indicating for which returned events of the SubFSM which Event must be triggered in the FSM.
|
||||||
-- @return Core.Fsm#FSM_PROCESS The SubFSM.
|
-- @return Core.Fsm#FSM_PROCESS The SubFSM.
|
||||||
function FSM:AddProcess( From, Event, Process, ReturnEvents )
|
function FSM:AddProcess( From, Event, Process, ReturnEvents )
|
||||||
self:T( { From, Event } )
|
--self:T3( { From, Event } )
|
||||||
|
|
||||||
local Sub = {}
|
local Sub = {}
|
||||||
Sub.From = From
|
Sub.From = From
|
||||||
@@ -525,7 +525,7 @@ do -- FSM
|
|||||||
Process._Scores[State].ScoreText = ScoreText
|
Process._Scores[State].ScoreText = ScoreText
|
||||||
Process._Scores[State].Score = Score
|
Process._Scores[State].Score = Score
|
||||||
|
|
||||||
self:T( Process._Scores )
|
--self:T3( Process._Scores )
|
||||||
|
|
||||||
return Process
|
return Process
|
||||||
end
|
end
|
||||||
@@ -561,17 +561,17 @@ do -- FSM
|
|||||||
-- @param #table EventStructure Event structure.
|
-- @param #table EventStructure Event structure.
|
||||||
function FSM:_eventmap( Events, EventStructure )
|
function FSM:_eventmap( Events, EventStructure )
|
||||||
|
|
||||||
local Event = EventStructure.Event
|
local Event = EventStructure.Event
|
||||||
local __Event = "__" .. EventStructure.Event
|
local __Event = "__" .. EventStructure.Event
|
||||||
|
|
||||||
self[Event] = self[Event] or self:_create_transition( Event )
|
self[Event] = self[Event] or self:_create_transition(Event)
|
||||||
self[__Event] = self[__Event] or self:_delayed_transition( Event )
|
self[__Event] = self[__Event] or self:_delayed_transition(Event)
|
||||||
|
|
||||||
-- Debug message.
|
-- Debug message.
|
||||||
self:T2( "Added methods: " .. Event .. ", " .. __Event )
|
--self:T3( "Added methods: " .. Event .. ", " .. __Event )
|
||||||
|
|
||||||
Events[Event] = self.Events[Event] or { map = {} }
|
Events[Event] = self.Events[Event] or { map = {} }
|
||||||
self:_add_to_map( Events[Event].map, EventStructure )
|
self:_add_to_map( Events[Event].map, EventStructure )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -784,7 +784,7 @@ do -- FSM
|
|||||||
return function( self, DelaySeconds, ... )
|
return function( self, DelaySeconds, ... )
|
||||||
|
|
||||||
-- Debug.
|
-- Debug.
|
||||||
self:T2( "Delayed Event: " .. EventName )
|
self:T3( "Delayed Event: " .. EventName )
|
||||||
|
|
||||||
local CallID = 0
|
local CallID = 0
|
||||||
if DelaySeconds ~= nil then
|
if DelaySeconds ~= nil then
|
||||||
@@ -802,23 +802,23 @@ do -- FSM
|
|||||||
self._EventSchedules[EventName] = CallID
|
self._EventSchedules[EventName] = CallID
|
||||||
|
|
||||||
-- Debug output.
|
-- Debug output.
|
||||||
self:T2( string.format( "NEGATIVE Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring( CallID ) ) )
|
self:T2(string.format("NEGATIVE Event %s delayed by %.3f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
||||||
else
|
else
|
||||||
self:T2( string.format( "NEGATIVE Event %s delayed by %.1f sec CANCELLED as we already have such an event in the queue.", EventName, DelaySeconds ) )
|
self:T2(string.format("NEGATIVE Event %s delayed by %.3f sec CANCELLED as we already have such an event in the queue.", EventName, DelaySeconds))
|
||||||
-- reschedule
|
-- reschedule
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
||||||
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
|
||||||
|
|
||||||
self:T2( string.format( "Event %s delayed by %.1f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring( CallID ) ) )
|
self:T2(string.format("Event %s delayed by %.3f sec SCHEDULED with CallID=%s", EventName, DelaySeconds, tostring(CallID)))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." )
|
error( "FSM: An asynchronous event trigger requires a DelaySeconds parameter!!! This can be positive or negative! Sorry, but will not process this." )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Debug.
|
-- Debug.
|
||||||
self:T2( { CallID = CallID } )
|
--self:T3( { CallID = CallID } )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -841,7 +841,7 @@ do -- FSM
|
|||||||
function FSM:_gosub( ParentFrom, ParentEvent )
|
function FSM:_gosub( ParentFrom, ParentEvent )
|
||||||
local fsmtable = {}
|
local fsmtable = {}
|
||||||
if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then
|
if self.subs[ParentFrom] and self.subs[ParentFrom][ParentEvent] then
|
||||||
self:T( { ParentFrom, ParentEvent, self.subs[ParentFrom], self.subs[ParentFrom][ParentEvent] } )
|
--self:T3( { ParentFrom, ParentEvent, self.subs[ParentFrom], self.subs[ParentFrom][ParentEvent] } )
|
||||||
return self.subs[ParentFrom][ParentEvent]
|
return self.subs[ParentFrom][ParentEvent]
|
||||||
else
|
else
|
||||||
return {}
|
return {}
|
||||||
@@ -888,7 +888,7 @@ do -- FSM
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T3( { Map, Event } )
|
--self:T3( { Map, Event } )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get current state.
|
--- Get current state.
|
||||||
@@ -908,7 +908,7 @@ do -- FSM
|
|||||||
--- Check if FSM is in state.
|
--- Check if FSM is in state.
|
||||||
-- @param #FSM self
|
-- @param #FSM self
|
||||||
-- @param #string State State name.
|
-- @param #string State State name.
|
||||||
-- @param #boolean If true, FSM is in this state.
|
-- @return #boolean If true, FSM is in this state.
|
||||||
function FSM:Is( State )
|
function FSM:Is( State )
|
||||||
return self.current == State
|
return self.current == State
|
||||||
end
|
end
|
||||||
@@ -916,8 +916,8 @@ do -- FSM
|
|||||||
--- Check if FSM is in state.
|
--- Check if FSM is in state.
|
||||||
-- @param #FSM self
|
-- @param #FSM self
|
||||||
-- @param #string State State name.
|
-- @param #string State State name.
|
||||||
-- @param #boolean If true, FSM is in this state.
|
-- @return #boolean If true, FSM is in this state.
|
||||||
function FSM:is( state )
|
function FSM:is(state)
|
||||||
return self.current == state
|
return self.current == state
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1146,7 +1146,7 @@ do -- FSM_PROCESS
|
|||||||
-- @param #FSM_PROCESS self
|
-- @param #FSM_PROCESS self
|
||||||
-- @return #FSM_PROCESS
|
-- @return #FSM_PROCESS
|
||||||
function FSM_PROCESS:Copy( Controllable, Task )
|
function FSM_PROCESS:Copy( Controllable, Task )
|
||||||
self:T( { self:GetClassNameAndID() } )
|
--self:T3( { self:GetClassNameAndID() } )
|
||||||
|
|
||||||
local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS
|
local NewFsm = self:New( Controllable, Task ) -- Core.Fsm#FSM_PROCESS
|
||||||
|
|
||||||
@@ -1171,13 +1171,13 @@ do -- FSM_PROCESS
|
|||||||
|
|
||||||
-- Copy End States
|
-- Copy End States
|
||||||
for EndStateID, EndState in pairs( self:GetEndStates() ) do
|
for EndStateID, EndState in pairs( self:GetEndStates() ) do
|
||||||
self:T( EndState )
|
--self:T3( EndState )
|
||||||
NewFsm:AddEndState( EndState )
|
NewFsm:AddEndState( EndState )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Copy the score tables
|
-- Copy the score tables
|
||||||
for ScoreID, Score in pairs( self:GetScores() ) do
|
for ScoreID, Score in pairs( self:GetScores() ) do
|
||||||
self:T( Score )
|
--self:T3( Score )
|
||||||
NewFsm:AddScore( ScoreID, Score.ScoreText, Score.Score )
|
NewFsm:AddScore( ScoreID, Score.ScoreText, Score.Score )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1422,7 +1422,7 @@ do -- FSM_SET
|
|||||||
-- @param #FSM_SET self
|
-- @param #FSM_SET self
|
||||||
-- @return Core.Set#SET_BASE
|
-- @return Core.Set#SET_BASE
|
||||||
function FSM_SET:Get()
|
function FSM_SET:Get()
|
||||||
return self.Controllable
|
return self.Set
|
||||||
end
|
end
|
||||||
|
|
||||||
function FSM_SET:_call_handler( step, trigger, params, EventName )
|
function FSM_SET:_call_handler( step, trigger, params, EventName )
|
||||||
|
|||||||
@@ -0,0 +1,267 @@
|
|||||||
|
--- **Core** - MarkerOps_Base.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Create an easy way to tap into markers added to the F10 map by users.
|
||||||
|
-- * Recognize own tag and list of keywords.
|
||||||
|
-- * Matched keywords are handed down to functions.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **Applevangelist**
|
||||||
|
--
|
||||||
|
-- Date: 5 May 2021
|
||||||
|
-- Last Update: Sep 2022
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
---
|
||||||
|
-- @module Core.MarkerOps_Base
|
||||||
|
-- @image MOOSE_Core.JPG
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
-- MARKEROPS_BASE Class Definition.
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- MARKEROPS_BASE class.
|
||||||
|
-- @type MARKEROPS_BASE
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #string Tag Tag to identify commands.
|
||||||
|
-- @field #table Keywords Table of keywords to recognize.
|
||||||
|
-- @field #string version Version of #MARKEROPS_BASE.
|
||||||
|
-- @field #boolean Casesensitive Enforce case when identifying the Tag, i.e. tag ~= Tag
|
||||||
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
--- *Fiat lux.* -- Latin proverb.
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # The MARKEROPS_BASE Concept
|
||||||
|
--
|
||||||
|
-- This class enable scripting text-based actions from markers.
|
||||||
|
--
|
||||||
|
-- @field #MARKEROPS_BASE
|
||||||
|
MARKEROPS_BASE = {
|
||||||
|
ClassName = "MARKEROPS",
|
||||||
|
Tag = "mytag",
|
||||||
|
Keywords = {},
|
||||||
|
version = "0.1.0",
|
||||||
|
debug = false,
|
||||||
|
Casesensitive = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Function to instantiate a new #MARKEROPS_BASE object.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string Tagname Name to identify us from the event text.
|
||||||
|
-- @param #table Keywords Table of keywords recognized from the event text.
|
||||||
|
-- @param #boolean Casesensitive (Optional) Switch case sensitive identification of Tagname. Defaults to true.
|
||||||
|
-- @return #MARKEROPS_BASE self
|
||||||
|
function MARKEROPS_BASE:New(Tagname,Keywords,Casesensitive)
|
||||||
|
-- Inherit FSM
|
||||||
|
local self=BASE:Inherit(self, FSM:New()) -- #MARKEROPS_BASE
|
||||||
|
|
||||||
|
-- Set some string id for output to DCS.log file.
|
||||||
|
self.lid=string.format("MARKEROPS_BASE %s | ", tostring(self.version))
|
||||||
|
|
||||||
|
self.Tag = Tagname or "mytag"-- #string
|
||||||
|
self.Keywords = Keywords or {} -- #table - might want to use lua regex here, too
|
||||||
|
self.debug = false
|
||||||
|
self.Casesensitive = true
|
||||||
|
|
||||||
|
if Casesensitive and Casesensitive == false then
|
||||||
|
self.Casesensitive = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
--- FSM Transitions ---
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
-- Start State.
|
||||||
|
self:SetStartState("Stopped")
|
||||||
|
|
||||||
|
-- Add FSM transitions.
|
||||||
|
-- From State --> Event --> To State
|
||||||
|
self:AddTransition("Stopped", "Start", "Running") -- Start the FSM.
|
||||||
|
self:AddTransition("*", "MarkAdded", "*") -- Start the FSM.
|
||||||
|
self:AddTransition("*", "MarkChanged", "*") -- Start the FSM.
|
||||||
|
self:AddTransition("*", "MarkDeleted", "*") -- Start the FSM.
|
||||||
|
self:AddTransition("Running", "Stop", "Stopped") -- Stop the FSM.
|
||||||
|
|
||||||
|
self:HandleEvent(EVENTS.MarkAdded, self.OnEventMark)
|
||||||
|
self:HandleEvent(EVENTS.MarkChange, self.OnEventMark)
|
||||||
|
self:HandleEvent(EVENTS.MarkRemoved, self.OnEventMark)
|
||||||
|
|
||||||
|
-- start
|
||||||
|
self:I(self.lid..string.format("started for %s",self.Tag))
|
||||||
|
self:__Start(1)
|
||||||
|
return self
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
-- PSEUDO Functions
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
--- On after "MarkAdded" event. Triggered when a Marker is added to the F10 map.
|
||||||
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkAdded
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
-- @param #string Text The text on the marker
|
||||||
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
|
|
||||||
|
--- On after "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
|
||||||
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkChanged
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
-- @param #string Text The text on the marker
|
||||||
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
|
|
||||||
|
--- On after "MarkDeleted" event. Triggered when a Marker is deleted from the F10 map.
|
||||||
|
-- @function [parent=#MARKEROPS_BASE] OnAfterMarkDeleted
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
|
||||||
|
--- "Stop" trigger. Used to stop the function an unhandle events
|
||||||
|
-- @function [parent=#MARKEROPS_BASE] Stop
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (internal) Handle events.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param Core.Event#EVENTDATA Event
|
||||||
|
function MARKEROPS_BASE:OnEventMark(Event)
|
||||||
|
self:T({Event})
|
||||||
|
if Event == nil or Event.idx == nil then
|
||||||
|
self:E("Skipping onEvent. Event or Event.idx unknown.")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
--position
|
||||||
|
local vec3={y=Event.pos.y, x=Event.pos.x, z=Event.pos.z}
|
||||||
|
local coord=COORDINATE:NewFromVec3(vec3)
|
||||||
|
if self.debug then
|
||||||
|
local coordtext = coord:ToStringLLDDM()
|
||||||
|
local text = tostring(Event.text)
|
||||||
|
local m = MESSAGE:New(string.format("Mark added at %s with text: %s",coordtext,text),10,"Info",false):ToAll()
|
||||||
|
end
|
||||||
|
-- decision
|
||||||
|
if Event.id==world.event.S_EVENT_MARK_ADDED then
|
||||||
|
self:T({event="S_EVENT_MARK_ADDED", carrier=self.groupname, vec3=Event.pos})
|
||||||
|
-- Handle event
|
||||||
|
local Eventtext = tostring(Event.text)
|
||||||
|
if Eventtext~=nil then
|
||||||
|
if self:_MatchTag(Eventtext) then
|
||||||
|
local matchtable = self:_MatchKeywords(Eventtext)
|
||||||
|
self:MarkAdded(Eventtext,matchtable,coord)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif Event.id==world.event.S_EVENT_MARK_CHANGE then
|
||||||
|
self:T({event="S_EVENT_MARK_CHANGE", carrier=self.groupname, vec3=Event.pos})
|
||||||
|
-- Handle event.
|
||||||
|
local Eventtext = tostring(Event.text)
|
||||||
|
if Eventtext~=nil then
|
||||||
|
if self:_MatchTag(Eventtext) then
|
||||||
|
local matchtable = self:_MatchKeywords(Eventtext)
|
||||||
|
self:MarkChanged(Eventtext,matchtable,coord)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif Event.id==world.event.S_EVENT_MARK_REMOVED then
|
||||||
|
self:T({event="S_EVENT_MARK_REMOVED", carrier=self.groupname, vec3=Event.pos})
|
||||||
|
-- Hande event.
|
||||||
|
local Eventtext = tostring(Event.text)
|
||||||
|
if Eventtext~=nil then
|
||||||
|
if self:_MatchTag(Eventtext) then
|
||||||
|
self:MarkDeleted()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (internal) Match tag.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string Eventtext Text added to the marker.
|
||||||
|
-- @return #boolean
|
||||||
|
function MARKEROPS_BASE:_MatchTag(Eventtext)
|
||||||
|
local matches = false
|
||||||
|
if not self.Casesensitive then
|
||||||
|
local type = string.lower(self.Tag) -- #string
|
||||||
|
if string.find(string.lower(Eventtext),type) then
|
||||||
|
matches = true --event text contains tag
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local type = self.Tag -- #string
|
||||||
|
if string.find(Eventtext,type) then
|
||||||
|
matches = true --event text contains tag
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return matches
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (internal) Match keywords table.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string Eventtext Text added to the marker.
|
||||||
|
-- @return #table
|
||||||
|
function MARKEROPS_BASE:_MatchKeywords(Eventtext)
|
||||||
|
local matchtable = {}
|
||||||
|
local keytable = self.Keywords
|
||||||
|
for _index,_word in pairs (keytable) do
|
||||||
|
if string.find(string.lower(Eventtext),string.lower(_word))then
|
||||||
|
table.insert(matchtable,_word)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return matchtable
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On before "MarkAdded" event. Triggered when a Marker is added to the F10 map.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
-- @param #string Text The text on the marker
|
||||||
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
|
function MARKEROPS_BASE:onbeforeMarkAdded(From,Event,To,Text,Keywords,Coord)
|
||||||
|
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On before "MarkChanged" event. Triggered when a Marker is changed on the F10 map.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
-- @param #string Text The text on the marker
|
||||||
|
-- @param #table Keywords Table of matching keywords found in the Event text
|
||||||
|
-- @param Core.Point#COORDINATE Coord Coordinate of the marker.
|
||||||
|
function MARKEROPS_BASE:onbeforeMarkChanged(From,Event,To,Text,Keywords,Coord)
|
||||||
|
self:T({self.lid,From,Event,To,Text,Keywords,Coord:ToStringLLDDM()})
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On before "MarkDeleted" event. Triggered when a Marker is removed from the F10 map.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
function MARKEROPS_BASE:onbeforeMarkDeleted(From,Event,To)
|
||||||
|
self:T({self.lid,From,Event,To})
|
||||||
|
end
|
||||||
|
|
||||||
|
--- On enter "Stopped" event. Unsubscribe events.
|
||||||
|
-- @param #MARKEROPS_BASE self
|
||||||
|
-- @param #string From The From state
|
||||||
|
-- @param #string Event The Event called
|
||||||
|
-- @param #string To The To state
|
||||||
|
function MARKEROPS_BASE:onenterStopped(From,Event,To)
|
||||||
|
self:T({self.lid,From,Event,To})
|
||||||
|
-- unsubscribe from events
|
||||||
|
self:UnHandleEvent(EVENTS.MarkAdded)
|
||||||
|
self:UnHandleEvent(EVENTS.MarkChange)
|
||||||
|
self:UnHandleEvent(EVENTS.MarkRemoved)
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
-- MARKEROPS_BASE Class Definition End.
|
||||||
|
--------------------------------------------------------------------------
|
||||||
@@ -239,6 +239,7 @@ do -- MENU_BASE
|
|||||||
function MENU_BASE:GetMenu( MenuText )
|
function MENU_BASE:GetMenu( MenuText )
|
||||||
return self.Menus[MenuText]
|
return self.Menus[MenuText]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sets a menu stamp for later prevention of menu removal.
|
--- Sets a menu stamp for later prevention of menu removal.
|
||||||
-- @param #MENU_BASE self
|
-- @param #MENU_BASE self
|
||||||
-- @param MenuStamp
|
-- @param MenuStamp
|
||||||
@@ -376,6 +377,7 @@ do -- MENU_MISSION
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Refreshes a radio item for a mission
|
--- Refreshes a radio item for a mission
|
||||||
-- @param #MENU_MISSION self
|
-- @param #MENU_MISSION self
|
||||||
-- @return #MENU_MISSION
|
-- @return #MENU_MISSION
|
||||||
@@ -813,6 +815,7 @@ do
|
|||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Refreshes a new radio item for a group and submenus
|
--- Refreshes a new radio item for a group and submenus
|
||||||
-- @param #MENU_GROUP self
|
-- @param #MENU_GROUP self
|
||||||
-- @return #MENU_GROUP
|
-- @return #MENU_GROUP
|
||||||
@@ -829,6 +832,29 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Refreshes a new radio item for a group and submenus, ordering by (numerical) MenuTag
|
||||||
|
-- @param #MENU_GROUP self
|
||||||
|
-- @return #MENU_GROUP
|
||||||
|
function MENU_GROUP:RefreshAndOrderByTag()
|
||||||
|
|
||||||
|
do
|
||||||
|
missionCommands.removeItemForGroup( self.GroupID, self.MenuPath )
|
||||||
|
missionCommands.addSubMenuForGroup( self.GroupID, self.MenuText, self.MenuParentPath )
|
||||||
|
|
||||||
|
local MenuTable = {}
|
||||||
|
for MenuText, Menu in pairs( self.Menus or {} ) do
|
||||||
|
local tag = Menu.MenuTag or math.random(1,10000)
|
||||||
|
MenuTable[#MenuTable+1] = {Tag=tag, Enty=Menu}
|
||||||
|
end
|
||||||
|
table.sort(MenuTable, function (k1, k2) return k1.tag < k2.tag end )
|
||||||
|
for _, Menu in pairs( MenuTable ) do
|
||||||
|
Menu.Entry:Refresh()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Removes the sub menus recursively of this MENU_GROUP.
|
--- Removes the sub menus recursively of this MENU_GROUP.
|
||||||
-- @param #MENU_GROUP self
|
-- @param #MENU_GROUP self
|
||||||
-- @param MenuStamp
|
-- @param MenuStamp
|
||||||
@@ -1180,4 +1206,3 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
-- * Send messages to a specific group.
|
-- * Send messages to a specific group.
|
||||||
-- * Send messages to a specific unit or client.
|
-- * Send messages to a specific unit or client.
|
||||||
--
|
--
|
||||||
--
|
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- @module Core.Message
|
-- @module Core.Message
|
||||||
@@ -205,14 +204,14 @@ function MESSAGE:ToClient( Client, Settings )
|
|||||||
local Unit = Client:GetClient()
|
local Unit = Client:GetClient()
|
||||||
|
|
||||||
if self.MessageDuration ~= 0 then
|
if self.MessageDuration ~= 0 then
|
||||||
local ClientGroupID = Client:GetClientGroupID()
|
local ClientGroupID = Client:GetClientGroupID()
|
||||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||||
--trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
--trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||||
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration , self.ClearScreen)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sends a MESSAGE to a Group.
|
--- Sends a MESSAGE to a Group.
|
||||||
@@ -263,6 +262,30 @@ function MESSAGE:ToUnit( Unit, Settings )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sends a MESSAGE to a Unit.
|
||||||
|
-- @param #MESSAGE self
|
||||||
|
-- @param Wrapper.Unit#UNIT Unit to which the message is displayed.
|
||||||
|
-- @return #MESSAGE Message object.
|
||||||
|
function MESSAGE:ToUnit( Unit, Settings )
|
||||||
|
self:F( Unit.IdentifiableName )
|
||||||
|
|
||||||
|
if Unit then
|
||||||
|
|
||||||
|
if self.MessageType then
|
||||||
|
local Settings = Settings or ( Unit and _DATABASE:GetPlayerSettings( Unit:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||||
|
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||||
|
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.MessageDuration ~= 0 then
|
||||||
|
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||||
|
trigger.action.outTextForUnit( Unit:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration, self.ClearScreen )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Sends a MESSAGE to the Blue coalition.
|
--- Sends a MESSAGE to the Blue coalition.
|
||||||
-- @param #MESSAGE self
|
-- @param #MESSAGE self
|
||||||
-- @return #MESSAGE
|
-- @return #MESSAGE
|
||||||
|
|||||||
@@ -825,7 +825,11 @@ do -- COORDINATE
|
|||||||
-- @param #COORDINATE TargetCoordinate The target COORDINATE.
|
-- @param #COORDINATE TargetCoordinate The target COORDINATE.
|
||||||
-- @return DCS#Vec3 DirectionVec3 The direction vector in Vec3 format.
|
-- @return DCS#Vec3 DirectionVec3 The direction vector in Vec3 format.
|
||||||
function COORDINATE:GetDirectionVec3( TargetCoordinate )
|
function COORDINATE:GetDirectionVec3( TargetCoordinate )
|
||||||
return { x = TargetCoordinate.x - self.x, y = TargetCoordinate.y - self.y, z = TargetCoordinate.z - self.z }
|
if TargetCoordinate then
|
||||||
|
return { x = TargetCoordinate.x - self.x, y = TargetCoordinate.y - self.y, z = TargetCoordinate.z - self.z }
|
||||||
|
else
|
||||||
|
return { x=0,y=0,z=0}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -875,6 +879,11 @@ do -- COORDINATE
|
|||||||
-- Get the vector from A to B
|
-- Get the vector from A to B
|
||||||
local vec=UTILS.VecSubstract(ToCoordinate, self)
|
local vec=UTILS.VecSubstract(ToCoordinate, self)
|
||||||
|
|
||||||
|
if f>1 then
|
||||||
|
local norm=UTILS.VecNorm(vec)
|
||||||
|
f=Fraction/norm
|
||||||
|
end
|
||||||
|
|
||||||
-- Scale the vector.
|
-- Scale the vector.
|
||||||
vec.x=f*vec.x
|
vec.x=f*vec.x
|
||||||
vec.y=f*vec.y
|
vec.y=f*vec.y
|
||||||
@@ -883,7 +892,9 @@ do -- COORDINATE
|
|||||||
-- Move the vector to start at the end of A.
|
-- Move the vector to start at the end of A.
|
||||||
vec=UTILS.VecAdd(self, vec)
|
vec=UTILS.VecAdd(self, vec)
|
||||||
|
|
||||||
|
-- Create a new coordiante object.
|
||||||
local coord=COORDINATE:New(vec.x,vec.y,vec.z)
|
local coord=COORDINATE:New(vec.x,vec.y,vec.z)
|
||||||
|
|
||||||
return coord
|
return coord
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2267,7 +2278,7 @@ do -- COORDINATE
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Creates a free form shape on the F10 map. The first point is the current COORDINATE. The remaining points need to be specified.
|
--- Creates a free form shape on the F10 map. The first point is the current COORDINATE. The remaining points need to be specified.
|
||||||
-- **NOTE**: A free form polygon must have **at least three points** in total and currently only **up to 10 points** in total are supported.
|
-- **NOTE**: A free form polygon must have **at least three points** in total and currently only **up to 15 points** in total are supported.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #table Coordinates Table of coordinates of the remaining points of the shape.
|
-- @param #table Coordinates Table of coordinates of the remaining points of the shape.
|
||||||
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
|
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
|
||||||
@@ -2320,8 +2331,28 @@ do -- COORDINATE
|
|||||||
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], Color, FillColor, LineType, ReadOnly, Text or "")
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
elseif #vecs==10 then
|
elseif #vecs==10 then
|
||||||
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], Color, FillColor, LineType, ReadOnly, Text or "")
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10], Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
|
elseif #vecs==11 then
|
||||||
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10],
|
||||||
|
vecs[11],
|
||||||
|
Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
|
elseif #vecs==12 then
|
||||||
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10],
|
||||||
|
vecs[11], vecs[12],
|
||||||
|
Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
|
elseif #vecs==13 then
|
||||||
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10],
|
||||||
|
vecs[11], vecs[12], vecs[13],
|
||||||
|
Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
|
elseif #vecs==14 then
|
||||||
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10],
|
||||||
|
vecs[11], vecs[12], vecs[13], vecs[14],
|
||||||
|
Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
|
elseif #vecs==15 then
|
||||||
|
trigger.action.markupToAll(7, Coalition, MarkID, vecs[1], vecs[2], vecs[3], vecs[4], vecs[5], vecs[6], vecs[7], vecs[8], vecs[9], vecs[10],
|
||||||
|
vecs[11], vecs[12], vecs[13], vecs[14], vecs[15],
|
||||||
|
Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
else
|
else
|
||||||
self:E("ERROR: Currently a free form polygon can only have 10 points in total!")
|
self:E("ERROR: Currently a free form polygon can only have 15 points in total!")
|
||||||
-- Unfortunately, unpack(vecs) does not work! So no idea how to generalize this :(
|
-- Unfortunately, unpack(vecs) does not work! So no idea how to generalize this :(
|
||||||
trigger.action.markupToAll(7, Coalition, MarkID, unpack(vecs), Color, FillColor, LineType, ReadOnly, Text or "")
|
trigger.action.markupToAll(7, Coalition, MarkID, unpack(vecs), Color, FillColor, LineType, ReadOnly, Text or "")
|
||||||
end
|
end
|
||||||
@@ -2751,7 +2782,7 @@ do -- COORDINATE
|
|||||||
return "BR, " .. self:GetBRText( AngleRadians, Distance, Settings )
|
return "BR, " .. self:GetBRText( AngleRadians, Distance, Settings )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return a BRAA string from a COORDINATE to the COORDINATE.
|
--- Return a BRA string from a COORDINATE to the COORDINATE.
|
||||||
-- @param #COORDINATE self
|
-- @param #COORDINATE self
|
||||||
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
-- @param #COORDINATE FromCoordinate The coordinate to measure the distance and the bearing from.
|
||||||
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
-- @param Core.Settings#SETTINGS Settings (optional) The settings. Can be nil, and in this case the default settings are used. If you want to specify your own settings, use the _SETTINGS object.
|
||||||
|
|||||||
@@ -109,9 +109,11 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
|||||||
self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } )
|
self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } )
|
||||||
|
|
||||||
if Scheduler.MasterObject then
|
if Scheduler.MasterObject then
|
||||||
|
--env.info("FF Object Scheduler")
|
||||||
self.ObjectSchedulers[CallID] = Scheduler
|
self.ObjectSchedulers[CallID] = Scheduler
|
||||||
self:F3( { CallID = CallID, ObjectScheduler = tostring( self.ObjectSchedulers[CallID] ), MasterObject = tostring( Scheduler.MasterObject ) } )
|
self:F3( { CallID = CallID, ObjectScheduler = tostring( self.ObjectSchedulers[CallID] ), MasterObject = tostring( Scheduler.MasterObject ) } )
|
||||||
else
|
else
|
||||||
|
--env.info("FF Persistent Scheduler")
|
||||||
self.PersistentSchedulers[CallID] = Scheduler
|
self.PersistentSchedulers[CallID] = Scheduler
|
||||||
self:F3( { CallID = CallID, PersistentScheduler = self.PersistentSchedulers[CallID] } )
|
self:F3( { CallID = CallID, PersistentScheduler = self.PersistentSchedulers[CallID] } )
|
||||||
end
|
end
|
||||||
@@ -121,8 +123,8 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
|||||||
self.Schedule[Scheduler][CallID] = {} -- #SCHEDULEDISPATCHER.ScheduleData
|
self.Schedule[Scheduler][CallID] = {} -- #SCHEDULEDISPATCHER.ScheduleData
|
||||||
self.Schedule[Scheduler][CallID].Function = ScheduleFunction
|
self.Schedule[Scheduler][CallID].Function = ScheduleFunction
|
||||||
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
|
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
|
||||||
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + (Start or 0)
|
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + ( Start or 0 )
|
||||||
self.Schedule[Scheduler][CallID].Start = Start + 0.1
|
self.Schedule[Scheduler][CallID].Start = Start + 0.001
|
||||||
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
|
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
|
||||||
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
|
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
|
||||||
self.Schedule[Scheduler][CallID].Stop = Stop
|
self.Schedule[Scheduler][CallID].Stop = Stop
|
||||||
@@ -217,6 +219,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
|||||||
if ShowTrace then
|
if ShowTrace then
|
||||||
SchedulerObject:T( Prefix .. Name .. ":" .. Line .. " (" .. Source .. ")" )
|
SchedulerObject:T( Prefix .. Name .. ":" .. Line .. " (" .. Source .. ")" )
|
||||||
end
|
end
|
||||||
|
-- The master object is passed as first parameter. A few :Schedule() calls in MOOSE expect this currently. But in principle it should be removed.
|
||||||
return ScheduleFunction( SchedulerObject, unpack( ScheduleArguments ) )
|
return ScheduleFunction( SchedulerObject, unpack( ScheduleArguments ) )
|
||||||
end
|
end
|
||||||
Status, Result = xpcall( Timer, ErrorHandler )
|
Status, Result = xpcall( Timer, ErrorHandler )
|
||||||
@@ -314,7 +317,7 @@ end
|
|||||||
--- Stop dispatcher.
|
--- Stop dispatcher.
|
||||||
-- @param #SCHEDULEDISPATCHER self
|
-- @param #SCHEDULEDISPATCHER self
|
||||||
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
|
-- @param Core.Scheduler#SCHEDULER Scheduler Scheduler object.
|
||||||
-- @param #table CallID Call ID.
|
-- @param #string CallID (Optional) Scheduler Call ID. If nil, all pending schedules are stopped recursively.
|
||||||
function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
function SCHEDULEDISPATCHER:Stop( Scheduler, CallID )
|
||||||
self:F2( { Stop = CallID, Scheduler = Scheduler } )
|
self:F2( { Stop = CallID, Scheduler = Scheduler } )
|
||||||
|
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ end
|
|||||||
-- @param #number Stop Time interval in seconds after which the scheduler will be stopped.
|
-- @param #number Stop Time interval in seconds after which the scheduler will be stopped.
|
||||||
-- @param #number TraceLevel Trace level [0,3]. Default 3.
|
-- @param #number TraceLevel Trace level [0,3]. Default 3.
|
||||||
-- @param Core.Fsm#FSM Fsm Finite state model.
|
-- @param Core.Fsm#FSM Fsm Finite state model.
|
||||||
-- @return #table The ScheduleID of the planned schedule.
|
-- @return #string The Schedule ID of the planned schedule.
|
||||||
function SCHEDULER:Schedule( MasterObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, TraceLevel, Fsm )
|
function SCHEDULER:Schedule( MasterObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, TraceLevel, Fsm )
|
||||||
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
|
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
|
||||||
self:T3( { SchedulerArguments } )
|
self:T3( { SchedulerArguments } )
|
||||||
@@ -271,7 +271,7 @@ end
|
|||||||
|
|
||||||
--- (Re-)Starts the schedules or a specific schedule if a valid ScheduleID is provided.
|
--- (Re-)Starts the schedules or a specific schedule if a valid ScheduleID is provided.
|
||||||
-- @param #SCHEDULER self
|
-- @param #SCHEDULER self
|
||||||
-- @param #string ScheduleID (Optional) The ScheduleID of the planned (repeating) schedule.
|
-- @param #string ScheduleID (Optional) The Schedule ID of the planned (repeating) schedule.
|
||||||
function SCHEDULER:Start( ScheduleID )
|
function SCHEDULER:Start( ScheduleID )
|
||||||
self:F3( { ScheduleID } )
|
self:F3( { ScheduleID } )
|
||||||
self:T( string.format( "Starting scheduler ID=%s", tostring( ScheduleID ) ) )
|
self:T( string.format( "Starting scheduler ID=%s", tostring( ScheduleID ) ) )
|
||||||
|
|||||||
@@ -201,9 +201,7 @@ do -- SET_BASE
|
|||||||
self:F2( { ObjectName = ObjectName } )
|
self:F2( { ObjectName = ObjectName } )
|
||||||
|
|
||||||
local TriggerEvent = true
|
local TriggerEvent = true
|
||||||
if NoTriggerEvent then
|
if NoTriggerEvent then TriggerEvent = false end
|
||||||
TriggerEvent = false
|
|
||||||
end
|
|
||||||
|
|
||||||
local Object = self.Set[ObjectName]
|
local Object = self.Set[ObjectName]
|
||||||
|
|
||||||
@@ -265,11 +263,11 @@ do -- SET_BASE
|
|||||||
-- @return Core.Base#BASE The added BASE Object.
|
-- @return Core.Base#BASE The added BASE Object.
|
||||||
function SET_BASE:SortByName()
|
function SET_BASE:SortByName()
|
||||||
|
|
||||||
local function sort( a, b )
|
local function sort(a, b)
|
||||||
return a < b
|
return a<b
|
||||||
end
|
end
|
||||||
|
|
||||||
table.sort( self.Index )
|
table.sort(self.Index)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -277,15 +275,16 @@ do -- SET_BASE
|
|||||||
-- @param #SET_BASE self
|
-- @param #SET_BASE self
|
||||||
-- @param Core.Set#SET_BASE SetToAdd Set to add.
|
-- @param Core.Set#SET_BASE SetToAdd Set to add.
|
||||||
-- @return #SET_BASE self
|
-- @return #SET_BASE self
|
||||||
function SET_BASE:AddSet( SetToAdd )
|
function SET_BASE:AddSet(SetToAdd)
|
||||||
|
|
||||||
for _, ObjectB in pairs( SetToAdd.Set ) do
|
for _,ObjectB in pairs(SetToAdd.Set) do
|
||||||
self:AddObject( ObjectB )
|
self:AddObject(ObjectB)
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Get the *union* of two sets.
|
--- Get the *union* of two sets.
|
||||||
-- @param #SET_BASE self
|
-- @param #SET_BASE self
|
||||||
-- @param Core.Set#SET_BASE SetB Set *B*.
|
-- @param Core.Set#SET_BASE SetB Set *B*.
|
||||||
@@ -309,15 +308,16 @@ do -- SET_BASE
|
|||||||
-- @param #SET_BASE self
|
-- @param #SET_BASE self
|
||||||
-- @param Core.Set#SET_BASE SetB Set other set, called *B*.
|
-- @param Core.Set#SET_BASE SetB Set other set, called *B*.
|
||||||
-- @return Core.Set#SET_BASE A set of objects that is included in set *A* **and** in set *B*.
|
-- @return Core.Set#SET_BASE A set of objects that is included in set *A* **and** in set *B*.
|
||||||
function SET_BASE:GetSetIntersection( SetB )
|
|
||||||
|
|
||||||
local intersection = SET_BASE:New()
|
function SET_BASE:GetSetIntersection(SetB)
|
||||||
|
|
||||||
local union = self:GetSetUnion( SetB )
|
local intersection=SET_BASE:New()
|
||||||
|
|
||||||
for _, Object in pairs( union.Set ) do
|
local union=self:GetSetUnion(SetB)
|
||||||
if self:IsIncludeObject( Object ) and SetB:IsIncludeObject( Object ) then
|
|
||||||
intersection:AddObject( Object )
|
for _,Object in pairs(union.Set) do
|
||||||
|
if self:IsIncludeObject(Object) and SetB:IsIncludeObject(Object) then
|
||||||
|
intersection:AddObject(Object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -330,11 +330,11 @@ do -- SET_BASE
|
|||||||
-- @return Core.Set#SET_BASE The set of objects that are in set *B* but **not** in this set *A*.
|
-- @return Core.Set#SET_BASE The set of objects that are in set *B* but **not** in this set *A*.
|
||||||
function SET_BASE:GetSetComplement( SetB )
|
function SET_BASE:GetSetComplement( SetB )
|
||||||
|
|
||||||
local complement = self:GetSetUnion( SetB )
|
local complement = self:GetSetUnion(SetB)
|
||||||
local intersection = self:GetSetIntersection( SetB )
|
local intersection = self:GetSetIntersection(SetB)
|
||||||
|
|
||||||
for _, Object in pairs( intersection.Set ) do
|
for _,Object in pairs(intersection.Set) do
|
||||||
complement:Remove( Object.ObjectName, true )
|
complement:Remove(Object.ObjectName,true)
|
||||||
end
|
end
|
||||||
|
|
||||||
return complement
|
return complement
|
||||||
@@ -765,6 +765,7 @@ do -- SET_BASE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
----- Iterate the SET_BASE and call an iterator function for each **alive** unit, providing the Unit and optional parameters.
|
----- Iterate the SET_BASE and call an iterator function for each **alive** unit, providing the Unit and optional parameters.
|
||||||
---- @param #SET_BASE self
|
---- @param #SET_BASE self
|
||||||
---- @param #function IteratorFunction The function that will be called when there is an alive unit in the SET_BASE. The function needs to accept a UNIT parameter.
|
---- @param #function IteratorFunction The function that will be called when there is an alive unit in the SET_BASE. The function needs to accept a UNIT parameter.
|
||||||
@@ -1060,8 +1061,9 @@ do -- SET_GROUP
|
|||||||
-- Note that for each unit in the group that is set, a default cargo bay limit is initialized.
|
-- Note that for each unit in the group that is set, a default cargo bay limit is initialized.
|
||||||
-- @param Core.Set#SET_GROUP self
|
-- @param Core.Set#SET_GROUP self
|
||||||
-- @param Wrapper.Group#GROUP group The group which should be added to the set.
|
-- @param Wrapper.Group#GROUP group The group which should be added to the set.
|
||||||
|
-- @param #boolean DontSetCargoBayLimit If true, do not attempt to auto-add the cargo bay limit per unit in this group.
|
||||||
-- @return Core.Set#SET_GROUP self
|
-- @return Core.Set#SET_GROUP self
|
||||||
function SET_GROUP:AddGroup( group )
|
function SET_GROUP:AddGroup( group, DontSetCargoBayLimit )
|
||||||
|
|
||||||
self:Add( group:GetName(), group )
|
self:Add( group:GetName(), group )
|
||||||
|
|
||||||
@@ -1170,6 +1172,30 @@ do -- SET_GROUP
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Builds a set of groups in zones.
|
||||||
|
-- @param #SET_GROUP self
|
||||||
|
-- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE
|
||||||
|
-- @return #SET_GROUP self
|
||||||
|
function SET_GROUP:FilterZones( Zones )
|
||||||
|
if not self.Filter.Zones then
|
||||||
|
self.Filter.Zones = {}
|
||||||
|
end
|
||||||
|
local zones = {}
|
||||||
|
if Zones.ClassName and Zones.ClassName == "SET_ZONE" then
|
||||||
|
zones = Zones.Set
|
||||||
|
elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then
|
||||||
|
self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!")
|
||||||
|
return self
|
||||||
|
else
|
||||||
|
zones = Zones
|
||||||
|
end
|
||||||
|
for _,Zone in pairs( zones ) do
|
||||||
|
local zonename = Zone:GetName()
|
||||||
|
self.Filter.Zones[zonename] = Zone
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Builds a set of groups of coalitions.
|
--- Builds a set of groups of coalitions.
|
||||||
-- Possible current coalitions are red, blue and neutral.
|
-- Possible current coalitions are red, blue and neutral.
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
@@ -1428,17 +1454,18 @@ do -- SET_GROUP
|
|||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param #number Delay Delay in seconds.
|
-- @param #number Delay Delay in seconds.
|
||||||
-- @return #SET_GROUP self
|
-- @return #SET_GROUP self
|
||||||
function SET_GROUP:Activate( Delay )
|
function SET_GROUP:Activate(Delay)
|
||||||
local Set = self:GetSet()
|
local Set = self:GetSet()
|
||||||
for GroupID, GroupData in pairs( Set ) do -- For each GROUP in SET_GROUP
|
for GroupID, GroupData in pairs(Set) do -- For each GROUP in SET_GROUP
|
||||||
local group = GroupData -- Wrapper.Group#GROUP
|
local group=GroupData --Wrapper.Group#GROUP
|
||||||
if group and group:IsAlive() == false then
|
if group and group:IsAlive()==false then
|
||||||
group:Activate( Delay )
|
group:Activate(Delay)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function.
|
--- Iterate the SET_GROUP and call an iterator function for each **alive** GROUP presence completely in a @{Zone}, providing the GROUP and optional parameters to the called function.
|
||||||
-- @param #SET_GROUP self
|
-- @param #SET_GROUP self
|
||||||
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
-- @param Core.Zone#ZONE ZoneObject The Zone to be tested for.
|
||||||
@@ -1826,7 +1853,7 @@ do -- SET_GROUP
|
|||||||
local MGroupZone = false
|
local MGroupZone = false
|
||||||
for ZoneName, Zone in pairs( self.Filter.Zones ) do
|
for ZoneName, Zone in pairs( self.Filter.Zones ) do
|
||||||
self:T3( "Zone:", ZoneName )
|
self:T3( "Zone:", ZoneName )
|
||||||
if MGroup:IsInZone( Zone ) then
|
if MGroup:IsInZone(Zone) then
|
||||||
MGroupZone = true
|
MGroupZone = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2169,13 +2196,13 @@ do -- SET_UNIT
|
|||||||
local zones = {}
|
local zones = {}
|
||||||
if Zones.ClassName and Zones.ClassName == "SET_ZONE" then
|
if Zones.ClassName and Zones.ClassName == "SET_ZONE" then
|
||||||
zones = Zones.Set
|
zones = Zones.Set
|
||||||
elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName) then
|
elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then
|
||||||
self:E( "***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!" )
|
self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!")
|
||||||
return self
|
return self
|
||||||
else
|
else
|
||||||
zones = Zones
|
zones = Zones
|
||||||
end
|
end
|
||||||
for _, Zone in pairs( zones ) do
|
for _,Zone in pairs( zones ) do
|
||||||
local zonename = Zone:GetName()
|
local zonename = Zone:GetName()
|
||||||
self.Filter.Zones[zonename] = Zone
|
self.Filter.Zones[zonename] = Zone
|
||||||
end
|
end
|
||||||
@@ -2353,6 +2380,7 @@ do -- SET_UNIT
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters.
|
--- Iterate the SET_UNIT and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters.
|
||||||
-- @param #SET_UNIT self
|
-- @param #SET_UNIT self
|
||||||
-- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter.
|
-- @param #function IteratorFunction The function that will be called when there is an alive UNIT in the SET_UNIT. The function needs to accept a UNIT parameter.
|
||||||
@@ -2406,6 +2434,7 @@ do -- SET_UNIT
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Iterate the SET_UNIT **sorted *per Threat Level** and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters.
|
--- Iterate the SET_UNIT **sorted *per Threat Level** and call an iterator function for each **alive** UNIT, providing the UNIT and optional parameters.
|
||||||
--
|
--
|
||||||
-- @param #SET_UNIT self
|
-- @param #SET_UNIT self
|
||||||
@@ -2795,6 +2824,8 @@ do -- SET_UNIT
|
|||||||
return FriendlyUnitCount
|
return FriendlyUnitCount
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----- Iterate the SET_UNIT and call an iterator function for each **alive** player, providing the Unit of the player and optional parameters.
|
----- Iterate the SET_UNIT and call an iterator function for each **alive** player, providing the Unit of the player and optional parameters.
|
||||||
---- @param #SET_UNIT self
|
---- @param #SET_UNIT self
|
||||||
---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter.
|
---- @param #function IteratorFunction The function that will be called when there is an alive player in the SET_UNIT. The function needs to accept a UNIT parameter.
|
||||||
@@ -2924,11 +2955,11 @@ do -- SET_UNIT
|
|||||||
local MGroupZone = false
|
local MGroupZone = false
|
||||||
for ZoneName, Zone in pairs( self.Filter.Zones ) do
|
for ZoneName, Zone in pairs( self.Filter.Zones ) do
|
||||||
self:T3( "Zone:", ZoneName )
|
self:T3( "Zone:", ZoneName )
|
||||||
if MUnit:IsInZone( Zone ) then
|
if MUnit:IsInZone(Zone) then
|
||||||
MGroupZone = true
|
MGroupZone = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
MUnitInclude = MUnitInclude and MGroupZone
|
MUnitInclude = MUnitInclude and MGroupZone
|
||||||
end
|
end
|
||||||
|
|
||||||
self:T2( MUnitInclude )
|
self:T2( MUnitInclude )
|
||||||
@@ -3152,7 +3183,8 @@ do -- SET_STATIC
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Builds a set of statics in zones.
|
|
||||||
|
--- Builds a set of statics in zones.
|
||||||
-- @param #SET_STATIC self
|
-- @param #SET_STATIC self
|
||||||
-- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE
|
-- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE
|
||||||
-- @return #SET_STATIC self
|
-- @return #SET_STATIC self
|
||||||
@@ -3163,13 +3195,13 @@ do -- SET_STATIC
|
|||||||
local zones = {}
|
local zones = {}
|
||||||
if Zones.ClassName and Zones.ClassName == "SET_ZONE" then
|
if Zones.ClassName and Zones.ClassName == "SET_ZONE" then
|
||||||
zones = Zones.Set
|
zones = Zones.Set
|
||||||
elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName) then
|
elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then
|
||||||
self:E( "***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!" )
|
self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!")
|
||||||
return self
|
return self
|
||||||
else
|
else
|
||||||
zones = Zones
|
zones = Zones
|
||||||
end
|
end
|
||||||
for _, Zone in pairs( zones ) do
|
for _,Zone in pairs( zones ) do
|
||||||
local zonename = Zone:GetName()
|
local zonename = Zone:GetName()
|
||||||
self.Filter.Zones[zonename] = Zone
|
self.Filter.Zones[zonename] = Zone
|
||||||
end
|
end
|
||||||
@@ -3374,6 +3406,7 @@ do -- SET_STATIC
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Iterate the SET_STATIC and call an iterator function for each **alive** STATIC, providing the STATIC and optional parameters.
|
--- Iterate the SET_STATIC and call an iterator function for each **alive** STATIC, providing the STATIC and optional parameters.
|
||||||
-- @param #SET_STATIC self
|
-- @param #SET_STATIC self
|
||||||
-- @param #function IteratorFunction The function that will be called when there is an alive STATIC in the SET_STATIC. The function needs to accept a STATIC parameter.
|
-- @param #function IteratorFunction The function that will be called when there is an alive STATIC in the SET_STATIC. The function needs to accept a STATIC parameter.
|
||||||
@@ -3656,7 +3689,7 @@ do -- SET_STATIC
|
|||||||
local MStaticZone = false
|
local MStaticZone = false
|
||||||
for ZoneName, Zone in pairs( self.Filter.Zones ) do
|
for ZoneName, Zone in pairs( self.Filter.Zones ) do
|
||||||
self:T3( "Zone:", ZoneName )
|
self:T3( "Zone:", ZoneName )
|
||||||
if MStatic and MStatic:IsInZone( Zone ) then
|
if MStatic and MStatic:IsInZone(Zone) then
|
||||||
MStaticZone = true
|
MStaticZone = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3943,7 +3976,7 @@ do -- SET_CLIENT
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Builds a set of clients in zones.
|
--- Builds a set of clients in zones.
|
||||||
-- @param #SET_CLIENT self
|
-- @param #SET_CLIENT self
|
||||||
-- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE
|
-- @param #table Zones Table of Core.Zone#ZONE Zone objects, or a Core.Set#SET_ZONE
|
||||||
-- @return #SET_TABLE self
|
-- @return #SET_TABLE self
|
||||||
@@ -3954,13 +3987,13 @@ do -- SET_CLIENT
|
|||||||
local zones = {}
|
local zones = {}
|
||||||
if Zones.ClassName and Zones.ClassName == "SET_ZONE" then
|
if Zones.ClassName and Zones.ClassName == "SET_ZONE" then
|
||||||
zones = Zones.Set
|
zones = Zones.Set
|
||||||
elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName) then
|
elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then
|
||||||
self:E( "***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!" )
|
self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!")
|
||||||
return self
|
return self
|
||||||
else
|
else
|
||||||
zones = Zones
|
zones = Zones
|
||||||
end
|
end
|
||||||
for _, Zone in pairs( zones ) do
|
for _,Zone in pairs( zones ) do
|
||||||
local zonename = Zone:GetName()
|
local zonename = Zone:GetName()
|
||||||
self.Filter.Zones[zonename] = Zone
|
self.Filter.Zones[zonename] = Zone
|
||||||
end
|
end
|
||||||
@@ -4080,6 +4113,26 @@ do -- SET_CLIENT
|
|||||||
return CountU
|
return CountU
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Gets the alive set.
|
||||||
|
-- @param #SET_CLIENT self
|
||||||
|
-- @return #table Table of SET objects
|
||||||
|
function SET_CLIENT:GetAliveSet()
|
||||||
|
|
||||||
|
local AliveSet = SET_CLIENT:New()
|
||||||
|
|
||||||
|
-- Clean the Set before returning with only the alive Groups.
|
||||||
|
for GroupName, GroupObject in pairs(self.Set) do
|
||||||
|
local GroupObject=GroupObject --Wrapper.Client#CLIENT
|
||||||
|
|
||||||
|
if GroupObject and GroupObject:IsAlive() then
|
||||||
|
AliveSet:Add(GroupName, GroupObject)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return AliveSet.Set or {}
|
||||||
|
end
|
||||||
|
|
||||||
---
|
---
|
||||||
-- @param #SET_CLIENT self
|
-- @param #SET_CLIENT self
|
||||||
-- @param Wrapper.Client#CLIENT MClient
|
-- @param Wrapper.Client#CLIENT MClient
|
||||||
@@ -4169,7 +4222,7 @@ do -- SET_CLIENT
|
|||||||
for ZoneName, Zone in pairs( self.Filter.Zones ) do
|
for ZoneName, Zone in pairs( self.Filter.Zones ) do
|
||||||
self:T3( "Zone:", ZoneName )
|
self:T3( "Zone:", ZoneName )
|
||||||
local unit = MClient:GetClientGroupUnit()
|
local unit = MClient:GetClientGroupUnit()
|
||||||
if unit and unit:IsInZone( Zone ) then
|
if unit and unit:IsInZone(Zone) then
|
||||||
MClientZone = true
|
MClientZone = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -4333,19 +4386,20 @@ do -- SET_PLAYER
|
|||||||
local zones = {}
|
local zones = {}
|
||||||
if Zones.ClassName and Zones.ClassName == "SET_ZONE" then
|
if Zones.ClassName and Zones.ClassName == "SET_ZONE" then
|
||||||
zones = Zones.Set
|
zones = Zones.Set
|
||||||
elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName) then
|
elseif type( Zones ) ~= "table" or (type( Zones ) == "table" and Zones.ClassName ) then
|
||||||
self:E( "***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!" )
|
self:E("***** FilterZones needs either a table of ZONE Objects or a SET_ZONE as parameter!")
|
||||||
return self
|
return self
|
||||||
else
|
else
|
||||||
zones = Zones
|
zones = Zones
|
||||||
end
|
end
|
||||||
for _, Zone in pairs( zones ) do
|
for _,Zone in pairs( zones ) do
|
||||||
local zonename = Zone:GetName()
|
local zonename = Zone:GetName()
|
||||||
self.Filter.Zones[zonename] = Zone
|
self.Filter.Zones[zonename] = Zone
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of clients out of categories joined by players.
|
--- Builds a set of clients out of categories joined by players.
|
||||||
-- Possible current categories are plane, helicopter, ground, ship.
|
-- Possible current categories are plane, helicopter, ground, ship.
|
||||||
-- @param #SET_PLAYER self
|
-- @param #SET_PLAYER self
|
||||||
@@ -4594,7 +4648,7 @@ do -- SET_PLAYER
|
|||||||
for ZoneName, Zone in pairs( self.Filter.Zones ) do
|
for ZoneName, Zone in pairs( self.Filter.Zones ) do
|
||||||
self:T3( "Zone:", ZoneName )
|
self:T3( "Zone:", ZoneName )
|
||||||
local unit = MClient:GetClientGroupUnit()
|
local unit = MClient:GetClientGroupUnit()
|
||||||
if unit and unit:IsInZone( Zone ) then
|
if unit and unit:IsInZone(Zone) then
|
||||||
MClientZone = true
|
MClientZone = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -5614,7 +5668,28 @@ do -- SET_ZONE
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
---
|
--- Draw all zones in the set on the F10 map.
|
||||||
|
-- @param #SET_ZONE self
|
||||||
|
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
|
||||||
|
-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red.
|
||||||
|
-- @param #number Alpha Transparency [0,1]. Default 1.
|
||||||
|
-- @param #table FillColor RGB color table {r, g, b}, e.g. {1,0,0} for red. Default is same as `Color` value.
|
||||||
|
-- @param #number FillAlpha Transparency [0,1]. Default 0.15.
|
||||||
|
-- @param #number LineType Line type: 0=No line, 1=Solid, 2=Dashed, 3=Dotted, 4=Dot dash, 5=Long dash, 6=Two dash. Default 1=Solid.
|
||||||
|
-- @param #boolean ReadOnly (Optional) Mark is readonly and cannot be removed by users. Default false.
|
||||||
|
-- @return #SET_ZONE self
|
||||||
|
function SET_ZONE:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly)
|
||||||
|
|
||||||
|
for _,_zone in pairs(self.Set) do
|
||||||
|
local zone=_zone --Core.Zone#ZONE
|
||||||
|
zone:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Private function.
|
||||||
-- @param #SET_ZONE self
|
-- @param #SET_ZONE self
|
||||||
-- @param Core.Zone#ZONE_BASE MZone
|
-- @param Core.Zone#ZONE_BASE MZone
|
||||||
-- @return #SET_ZONE self
|
-- @return #SET_ZONE self
|
||||||
@@ -6014,6 +6089,8 @@ do -- SET_ZONE_GOAL
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
do -- SET_OPSGROUP
|
do -- SET_OPSGROUP
|
||||||
|
|
||||||
--- @type SET_OPSGROUP
|
--- @type SET_OPSGROUP
|
||||||
@@ -6119,13 +6196,14 @@ do -- SET_OPSGROUP
|
|||||||
}, -- FilterMeta
|
}, -- FilterMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
--- Creates a new SET_OPSGROUP object, building a set of groups belonging to a coalitions, categories, countries, types or with defined prefix names.
|
--- Creates a new SET_OPSGROUP object, building a set of groups belonging to a coalitions, categories, countries, types or with defined prefix names.
|
||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @return #SET_OPSGROUP
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:New()
|
function SET_OPSGROUP:New()
|
||||||
|
|
||||||
-- Inherit SET_BASE.
|
-- Inherit SET_BASE.
|
||||||
local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.GROUPS ) ) -- #SET_OPSGROUP
|
local self = BASE:Inherit(self, SET_BASE:New(_DATABASE.GROUPS)) -- #SET_OPSGROUP
|
||||||
|
|
||||||
-- Include non activated
|
-- Include non activated
|
||||||
self:FilterActive( false )
|
self:FilterActive( false )
|
||||||
@@ -6141,11 +6219,11 @@ do -- SET_OPSGROUP
|
|||||||
local AliveSet = SET_OPSGROUP:New()
|
local AliveSet = SET_OPSGROUP:New()
|
||||||
|
|
||||||
-- Clean the Set before returning with only the alive Groups.
|
-- Clean the Set before returning with only the alive Groups.
|
||||||
for GroupName, GroupObject in pairs( self.Set ) do
|
for GroupName, GroupObject in pairs(self.Set) do
|
||||||
local GroupObject = GroupObject -- Wrapper.Group#GROUP
|
local GroupObject=GroupObject --Wrapper.Group#GROUP
|
||||||
|
|
||||||
if GroupObject and GroupObject:IsAlive() then
|
if GroupObject and GroupObject:IsAlive() then
|
||||||
AliveSet:Add( GroupName, GroupObject )
|
AliveSet:Add(GroupName, GroupObject)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -6157,52 +6235,60 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #string ObjectName The name of the object.
|
-- @param #string ObjectName The name of the object.
|
||||||
-- @param Core.Base#BASE Object The object itself.
|
-- @param Core.Base#BASE Object The object itself.
|
||||||
-- @return Core.Base#BASE The added BASE Object.
|
-- @return Core.Base#BASE The added BASE Object.
|
||||||
function SET_OPSGROUP:Add( ObjectName, Object )
|
function SET_OPSGROUP:Add(ObjectName, Object)
|
||||||
self:T( { ObjectName = ObjectName, Object = Object } )
|
self:T( { ObjectName = ObjectName, Object = Object } )
|
||||||
|
|
||||||
-- Ensure that the existing element is removed from the Set before a new one is inserted to the Set
|
-- Ensure that the existing element is removed from the Set before a new one is inserted to the Set
|
||||||
if self.Set[ObjectName] then
|
if self.Set[ObjectName] then
|
||||||
self:Remove( ObjectName, true )
|
self:Remove(ObjectName, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
local object = nil -- Ops.OpsGroup#OPSGROUP
|
local object=nil --Ops.OpsGroup#OPSGROUP
|
||||||
if Object:IsInstanceOf( "GROUP" ) then
|
if Object:IsInstanceOf("GROUP") then
|
||||||
|
|
||||||
---
|
---
|
||||||
-- GROUP Object
|
-- GROUP Object
|
||||||
---
|
---
|
||||||
|
|
||||||
-- Fist, look up in the DATABASE if an OPSGROUP already exists.
|
-- Fist, look up in the DATABASE if an OPSGROUP already exists.
|
||||||
object = _DATABASE:FindOpsGroup( ObjectName )
|
object=_DATABASE:FindOpsGroup(ObjectName)
|
||||||
|
|
||||||
if not object then
|
if not object then
|
||||||
|
|
||||||
if Object:IsShip() then
|
if Object:IsShip() then
|
||||||
object = NAVYGROUP:New( Object )
|
object=NAVYGROUP:New(Object)
|
||||||
elseif Object:IsGround() then
|
elseif Object:IsGround() then
|
||||||
object = ARMYGROUP:New( Object )
|
object=ARMYGROUP:New(Object)
|
||||||
elseif Object:IsAir() then
|
elseif Object:IsAir() then
|
||||||
object = FLIGHTGROUP:New( Object )
|
object=FLIGHTGROUP:New(Object)
|
||||||
else
|
else
|
||||||
env.error( "ERROR: Unknown category of group object!" )
|
env.error("ERROR: Unknown category of group object!")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif Object:IsInstanceOf( "OPSGROUP" ) then
|
elseif Object:IsInstanceOf("OPSGROUP") then
|
||||||
-- We already have an OPSGROUP.
|
-- We already have an OPSGROUP.
|
||||||
object = Object
|
object=Object
|
||||||
else
|
else
|
||||||
env.error( "ERROR: Object must be a GROUP or OPSGROUP!" )
|
env.error("ERROR: Object must be a GROUP or OPSGROUP!")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add object to set.
|
-- Add object to set.
|
||||||
self.Set[ObjectName] = object
|
self.Set[ObjectName]=object
|
||||||
|
|
||||||
-- Add Object name to Index.
|
-- Add Object name to Index.
|
||||||
table.insert( self.Index, ObjectName )
|
table.insert(self.Index, ObjectName)
|
||||||
|
|
||||||
-- Trigger Added event.
|
-- Trigger Added event.
|
||||||
self:Added( ObjectName, object )
|
self:Added(ObjectName, object)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Adds a @{Core.Base#BASE} object in the @{Core.Set#SET_BASE}, using the Object Name as the index.
|
||||||
|
-- @param #SET_BASE self
|
||||||
|
-- @param Ops.OpsGroup#OPSGROUP Object Ops group
|
||||||
|
-- @return Core.Base#BASE The added BASE Object.
|
||||||
|
function SET_OPSGROUP:AddObject(Object)
|
||||||
|
self:Add(Object.groupname, Object)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add a GROUP or OPSGROUP object to the set.
|
--- Add a GROUP or OPSGROUP object to the set.
|
||||||
@@ -6210,11 +6296,11 @@ do -- SET_OPSGROUP
|
|||||||
-- @param Core.Set#SET_OPSGROUP self
|
-- @param Core.Set#SET_OPSGROUP self
|
||||||
-- @param Wrapper.Group#GROUP group The GROUP which should be added to the set. Can also be given as an #OPSGROUP object.
|
-- @param Wrapper.Group#GROUP group The GROUP which should be added to the set. Can also be given as an #OPSGROUP object.
|
||||||
-- @return Core.Set#SET_OPSGROUP self
|
-- @return Core.Set#SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:AddGroup( group )
|
function SET_OPSGROUP:AddGroup(group)
|
||||||
|
|
||||||
local groupname = group:GetName()
|
local groupname=group:GetName()
|
||||||
|
|
||||||
self:Add( groupname, group )
|
self:Add(groupname, group )
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -6225,10 +6311,10 @@ do -- SET_OPSGROUP
|
|||||||
-- @return Core.Set#SET_OPSGROUP self
|
-- @return Core.Set#SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:AddGroupsByName( AddGroupNames )
|
function SET_OPSGROUP:AddGroupsByName( AddGroupNames )
|
||||||
|
|
||||||
local AddGroupNamesArray = (type( AddGroupNames ) == "table") and AddGroupNames or { AddGroupNames }
|
local AddGroupNamesArray = ( type( AddGroupNames ) == "table" ) and AddGroupNames or { AddGroupNames }
|
||||||
|
|
||||||
for AddGroupID, AddGroupName in pairs( AddGroupNamesArray ) do
|
for AddGroupID, AddGroupName in pairs( AddGroupNamesArray ) do
|
||||||
self:Add( AddGroupName, GROUP:FindByName( AddGroupName ) )
|
self:Add(AddGroupName, GROUP:FindByName(AddGroupName))
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -6240,7 +6326,7 @@ do -- SET_OPSGROUP
|
|||||||
-- @return Core.Set#SET_OPSGROUP self
|
-- @return Core.Set#SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:RemoveGroupsByName( RemoveGroupNames )
|
function SET_OPSGROUP:RemoveGroupsByName( RemoveGroupNames )
|
||||||
|
|
||||||
local RemoveGroupNamesArray = (type( RemoveGroupNames ) == "table") and RemoveGroupNames or { RemoveGroupNames }
|
local RemoveGroupNamesArray = ( type( RemoveGroupNames ) == "table" ) and RemoveGroupNames or { RemoveGroupNames }
|
||||||
|
|
||||||
for RemoveGroupID, RemoveGroupName in pairs( RemoveGroupNamesArray ) do
|
for RemoveGroupID, RemoveGroupName in pairs( RemoveGroupNamesArray ) do
|
||||||
self:Remove( RemoveGroupName )
|
self:Remove( RemoveGroupName )
|
||||||
@@ -6253,7 +6339,7 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param #string GroupName Name of the group.
|
-- @param #string GroupName Name of the group.
|
||||||
-- @return Ops.OpsGroup#OPSGROUP The found OPSGROUP (FLIGHTGROUP, ARMYGROUP or NAVYGROUP) or `#nil` if the group is not in the set.
|
-- @return Ops.OpsGroup#OPSGROUP The found OPSGROUP (FLIGHTGROUP, ARMYGROUP or NAVYGROUP) or `#nil` if the group is not in the set.
|
||||||
function SET_OPSGROUP:FindGroup( GroupName )
|
function SET_OPSGROUP:FindGroup(GroupName)
|
||||||
local GroupFound = self.Set[GroupName]
|
local GroupFound = self.Set[GroupName]
|
||||||
return GroupFound
|
return GroupFound
|
||||||
end
|
end
|
||||||
@@ -6262,8 +6348,8 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param #string GroupName Name of the group.
|
-- @param #string GroupName Name of the group.
|
||||||
-- @return Ops.FlightGroup#FLIGHTGROUP The found FLIGHTGROUP or `#nil` if the group is not in the set.
|
-- @return Ops.FlightGroup#FLIGHTGROUP The found FLIGHTGROUP or `#nil` if the group is not in the set.
|
||||||
function SET_OPSGROUP:FindFlightGroup( GroupName )
|
function SET_OPSGROUP:FindFlightGroup(GroupName)
|
||||||
local GroupFound = self:FindGroup( GroupName )
|
local GroupFound = self:FindGroup(GroupName)
|
||||||
return GroupFound
|
return GroupFound
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -6271,17 +6357,18 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param #string GroupName Name of the group.
|
-- @param #string GroupName Name of the group.
|
||||||
-- @return Ops.ArmyGroup#ARMYGROUP The found ARMYGROUP or `#nil` if the group is not in the set.
|
-- @return Ops.ArmyGroup#ARMYGROUP The found ARMYGROUP or `#nil` if the group is not in the set.
|
||||||
function SET_OPSGROUP:FindArmyGroup( GroupName )
|
function SET_OPSGROUP:FindArmyGroup(GroupName)
|
||||||
local GroupFound = self:FindGroup( GroupName )
|
local GroupFound = self:FindGroup(GroupName)
|
||||||
return GroupFound
|
return GroupFound
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Finds a NAVYGROUP based on the group name.
|
--- Finds a NAVYGROUP based on the group name.
|
||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param #string GroupName Name of the group.
|
-- @param #string GroupName Name of the group.
|
||||||
-- @return Ops.NavyGroup#NAVYGROUP The found NAVYGROUP or `#nil` if the group is not in the set.
|
-- @return Ops.NavyGroup#NAVYGROUP The found NAVYGROUP or `#nil` if the group is not in the set.
|
||||||
function SET_OPSGROUP:FindNavyGroup( GroupName )
|
function SET_OPSGROUP:FindNavyGroup(GroupName)
|
||||||
local GroupFound = self:FindGroup( GroupName )
|
local GroupFound = self:FindGroup(GroupName)
|
||||||
return GroupFound
|
return GroupFound
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -6290,16 +6377,16 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" or combinations as a table, for example `{"red", "neutral"}`.
|
-- @param #string Coalitions Can take the following values: "red", "blue", "neutral" or combinations as a table, for example `{"red", "neutral"}`.
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:FilterCoalitions( Coalitions )
|
function SET_OPSGROUP:FilterCoalitions(Coalitions)
|
||||||
|
|
||||||
-- Create an empty set.
|
-- Create an empty set.
|
||||||
if not self.Filter.Coalitions then
|
if not self.Filter.Coalitions then
|
||||||
self.Filter.Coalitions = {}
|
self.Filter.Coalitions={}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Ensure we got a table.
|
-- Ensure we got a table.
|
||||||
if type( Coalitions ) ~= "table" then
|
if type(Coalitions)~="table" then
|
||||||
Coalitions = { Coalitions }
|
Coalitions = {Coalitions}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set filter.
|
-- Set filter.
|
||||||
@@ -6310,6 +6397,7 @@ do -- SET_OPSGROUP
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of groups out of categories.
|
--- Builds a set of groups out of categories.
|
||||||
--
|
--
|
||||||
-- Possible current categories are:
|
-- Possible current categories are:
|
||||||
@@ -6325,11 +6413,11 @@ do -- SET_OPSGROUP
|
|||||||
function SET_OPSGROUP:FilterCategories( Categories )
|
function SET_OPSGROUP:FilterCategories( Categories )
|
||||||
|
|
||||||
if not self.Filter.Categories then
|
if not self.Filter.Categories then
|
||||||
self.Filter.Categories = {}
|
self.Filter.Categories={}
|
||||||
end
|
end
|
||||||
|
|
||||||
if type( Categories ) ~= "table" then
|
if type(Categories)~="table" then
|
||||||
Categories = { Categories }
|
Categories={Categories}
|
||||||
end
|
end
|
||||||
|
|
||||||
for CategoryID, Category in pairs( Categories ) do
|
for CategoryID, Category in pairs( Categories ) do
|
||||||
@@ -6343,7 +6431,7 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:FilterCategoryGround()
|
function SET_OPSGROUP:FilterCategoryGround()
|
||||||
self:FilterCategories( "ground" )
|
self:FilterCategories("ground")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -6351,15 +6439,15 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:FilterCategoryAirplane()
|
function SET_OPSGROUP:FilterCategoryAirplane()
|
||||||
self:FilterCategories( "plane" )
|
self:FilterCategories("plane")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Builds a set of groups out of aircraft category (planes and helicopters).
|
--- Builds a set of groups out of aicraft category (planes and helicopters).
|
||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:FilterCategoryAircraft()
|
function SET_OPSGROUP:FilterCategoryAircraft()
|
||||||
self:FilterCategories( { "plane", "helicopter" } )
|
self:FilterCategories({"plane", "helicopter"})
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -6375,7 +6463,7 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:FilterCategoryShip()
|
function SET_OPSGROUP:FilterCategoryShip()
|
||||||
self:FilterCategories( "ship" )
|
self:FilterCategories("ship")
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -6383,7 +6471,7 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param #string Countries Can take those country strings known within DCS world.
|
-- @param #string Countries Can take those country strings known within DCS world.
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:FilterCountries( Countries )
|
function SET_OPSGROUP:FilterCountries(Countries)
|
||||||
|
|
||||||
-- Create empty table if necessary.
|
-- Create empty table if necessary.
|
||||||
if not self.Filter.Countries then
|
if not self.Filter.Countries then
|
||||||
@@ -6391,8 +6479,8 @@ do -- SET_OPSGROUP
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Ensure input is a table.
|
-- Ensure input is a table.
|
||||||
if type( Countries ) ~= "table" then
|
if type(Countries)~="table" then
|
||||||
Countries = { Countries }
|
Countries={Countries}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set filter.
|
-- Set filter.
|
||||||
@@ -6403,26 +6491,27 @@ do -- SET_OPSGROUP
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Builds a set of groups that contain the given string in their group name.
|
--- Builds a set of groups that contain the given string in their group name.
|
||||||
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all groups that **contain** the string.
|
-- **Attention!** Bad naming convention as this **does not** filter only **prefixes** but all groups that **contain** the string.
|
||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param #string Prefixes The string pattern(s) that needs to be contained in the group name. Can also be passed as a `#table` of strings.
|
-- @param #string Prefixes The string pattern(s) that needs to be contained in the group name. Can also be passed as a `#table` of strings.
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:FilterPrefixes( Prefixes )
|
function SET_OPSGROUP:FilterPrefixes(Prefixes)
|
||||||
|
|
||||||
-- Create emtpy table if necessary.
|
-- Create emtpy table if necessary.
|
||||||
if not self.Filter.GroupPrefixes then
|
if not self.Filter.GroupPrefixes then
|
||||||
self.Filter.GroupPrefixes = {}
|
self.Filter.GroupPrefixes={}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Ensure we have a table.
|
-- Ensure we have a table.
|
||||||
if type( Prefixes ) ~= "table" then
|
if type(Prefixes)~="table" then
|
||||||
Prefixes = { Prefixes }
|
Prefixes={Prefixes}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set group prefixes.
|
-- Set group prefixes.
|
||||||
for PrefixID, Prefix in pairs( Prefixes ) do
|
for PrefixID, Prefix in pairs(Prefixes) do
|
||||||
self.Filter.GroupPrefixes[Prefix] = Prefix
|
self.Filter.GroupPrefixes[Prefix]=Prefix
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@@ -6431,7 +6520,7 @@ do -- SET_OPSGROUP
|
|||||||
--- Builds a set of groups that are only active.
|
--- Builds a set of groups that are only active.
|
||||||
-- Only the groups that are active will be included within the set.
|
-- Only the groups that are active will be included within the set.
|
||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param #boolean Active (Optional) Include only active groups to the set.
|
-- @param #boolean Active (optional) Include only active groups to the set.
|
||||||
-- Include inactive groups if you provide false.
|
-- Include inactive groups if you provide false.
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
-- @usage
|
-- @usage
|
||||||
@@ -6449,11 +6538,12 @@ do -- SET_OPSGROUP
|
|||||||
-- GroupSet = SET_OPSGROUP:New():FilterActive( false ):FilterCoalition( "blue" ):FilterOnce()
|
-- GroupSet = SET_OPSGROUP:New():FilterActive( false ):FilterCoalition( "blue" ):FilterOnce()
|
||||||
--
|
--
|
||||||
function SET_OPSGROUP:FilterActive( Active )
|
function SET_OPSGROUP:FilterActive( Active )
|
||||||
Active = Active or not (Active == false)
|
Active = Active or not ( Active == false )
|
||||||
self.Filter.Active = Active
|
self.Filter.Active = Active
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Starts the filtering.
|
--- Starts the filtering.
|
||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
@@ -6474,12 +6564,12 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param #number Delay Delay in seconds.
|
-- @param #number Delay Delay in seconds.
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:Activate( Delay )
|
function SET_OPSGROUP:Activate(Delay)
|
||||||
local Set = self:GetSet()
|
local Set = self:GetSet()
|
||||||
for GroupID, GroupData in pairs( Set ) do
|
for GroupID, GroupData in pairs(Set) do
|
||||||
local group = GroupData -- Ops.OpsGroup#OPSGROUP
|
local group=GroupData --Ops.OpsGroup#OPSGROUP
|
||||||
if group and group:IsAlive() == false then
|
if group and group:IsAlive()==false then
|
||||||
group:Activate( Delay )
|
group:Activate(Delay)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
@@ -6510,7 +6600,7 @@ do -- SET_OPSGROUP
|
|||||||
-- @return #table The GROUP
|
-- @return #table The GROUP
|
||||||
function SET_OPSGROUP:AddInDatabase( Event )
|
function SET_OPSGROUP:AddInDatabase( Event )
|
||||||
|
|
||||||
if Event.IniObjectCategory == 1 then
|
if Event.IniObjectCategory==1 then
|
||||||
|
|
||||||
if not self.Database[Event.IniDCSGroupName] then
|
if not self.Database[Event.IniDCSGroupName] then
|
||||||
self.Database[Event.IniDCSGroupName] = GROUP:Register( Event.IniDCSGroupName )
|
self.Database[Event.IniDCSGroupName] = GROUP:Register( Event.IniDCSGroupName )
|
||||||
@@ -6527,7 +6617,7 @@ do -- SET_OPSGROUP
|
|||||||
-- @param Core.Event#EVENTDATA Event Event data table.
|
-- @param Core.Event#EVENTDATA Event Event data table.
|
||||||
-- @return #string The name of the GROUP
|
-- @return #string The name of the GROUP
|
||||||
-- @return #table The GROUP
|
-- @return #table The GROUP
|
||||||
function SET_OPSGROUP:FindInDatabase( Event )
|
function SET_OPSGROUP:FindInDatabase(Event)
|
||||||
return Event.IniDCSGroupName, self.Database[Event.IniDCSGroupName]
|
return Event.IniDCSGroupName, self.Database[Event.IniDCSGroupName]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -6538,7 +6628,7 @@ do -- SET_OPSGROUP
|
|||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:ForEachGroup( IteratorFunction, ... )
|
function SET_OPSGROUP:ForEachGroup( IteratorFunction, ... )
|
||||||
|
|
||||||
self:ForEach( IteratorFunction, arg, self:GetSet() )
|
self:ForEach(IteratorFunction, arg, self:GetSet())
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -6547,17 +6637,17 @@ do -- SET_OPSGROUP
|
|||||||
-- @param #SET_OPSGROUP self
|
-- @param #SET_OPSGROUP self
|
||||||
-- @param Wrapper.Group#GROUP MGroup The group that is checked for inclusion.
|
-- @param Wrapper.Group#GROUP MGroup The group that is checked for inclusion.
|
||||||
-- @return #SET_OPSGROUP self
|
-- @return #SET_OPSGROUP self
|
||||||
function SET_OPSGROUP:IsIncludeObject( MGroup )
|
function SET_OPSGROUP:IsIncludeObject(MGroup)
|
||||||
|
|
||||||
-- Assume it is and check later if not.
|
-- Assume it is and check later if not.
|
||||||
local MGroupInclude = true
|
local MGroupInclude=true
|
||||||
|
|
||||||
-- Filter active.
|
-- Filter active.
|
||||||
if self.Filter.Active ~= nil then
|
if self.Filter.Active~=nil then
|
||||||
|
|
||||||
local MGroupActive = false
|
local MGroupActive = false
|
||||||
|
|
||||||
if self.Filter.Active == false or (self.Filter.Active == true and MGroup:IsActive() == true) then
|
if self.Filter.Active==false or (self.Filter.Active==true and MGroup:IsActive()==true) then
|
||||||
MGroupActive = true
|
MGroupActive = true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -6570,7 +6660,7 @@ do -- SET_OPSGROUP
|
|||||||
local MGroupCoalition = false
|
local MGroupCoalition = false
|
||||||
|
|
||||||
for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do
|
for CoalitionID, CoalitionName in pairs( self.Filter.Coalitions ) do
|
||||||
if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName] == MGroup:GetCoalition() then
|
if self.FilterMeta.Coalitions[CoalitionName] and self.FilterMeta.Coalitions[CoalitionName]==MGroup:GetCoalition() then
|
||||||
MGroupCoalition = true
|
MGroupCoalition = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -6584,7 +6674,7 @@ do -- SET_OPSGROUP
|
|||||||
local MGroupCategory = false
|
local MGroupCategory = false
|
||||||
|
|
||||||
for CategoryID, CategoryName in pairs( self.Filter.Categories ) do
|
for CategoryID, CategoryName in pairs( self.Filter.Categories ) do
|
||||||
if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName] == MGroup:GetCategory() then
|
if self.FilterMeta.Categories[CategoryName] and self.FilterMeta.Categories[CategoryName]==MGroup:GetCategory() then
|
||||||
MGroupCategory = true
|
MGroupCategory = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -6609,7 +6699,7 @@ do -- SET_OPSGROUP
|
|||||||
local MGroupPrefix = false
|
local MGroupPrefix = false
|
||||||
|
|
||||||
for GroupPrefixId, GroupPrefix in pairs( self.Filter.GroupPrefixes ) do
|
for GroupPrefixId, GroupPrefix in pairs( self.Filter.GroupPrefixes ) do
|
||||||
if string.find( MGroup:GetName(), GroupPrefix:gsub( "-", "%%-" ), 1 ) then -- Not sure why "-" is replaced by "%-" ?!
|
if string.find( MGroup:GetName(), GroupPrefix:gsub ("-", "%%-"), 1 ) then --Not sure why "-" is replaced by "%-" ?!
|
||||||
MGroupPrefix = true
|
MGroupPrefix = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ do -- SETTINGS
|
|||||||
self:SetMessageTime( MESSAGE.Type.Overview, 60 )
|
self:SetMessageTime( MESSAGE.Type.Overview, 60 )
|
||||||
self:SetMessageTime( MESSAGE.Type.Update, 15 )
|
self:SetMessageTime( MESSAGE.Type.Update, 15 )
|
||||||
self:SetEraModern()
|
self:SetEraModern()
|
||||||
|
self:SetLocale("en")
|
||||||
return self
|
return self
|
||||||
else
|
else
|
||||||
local Settings = _DATABASE:GetPlayerSettings( PlayerName )
|
local Settings = _DATABASE:GetPlayerSettings( PlayerName )
|
||||||
@@ -283,6 +284,20 @@ do -- SETTINGS
|
|||||||
self.Metric = true
|
self.Metric = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Sets the SETTINGS default text locale.
|
||||||
|
-- @param #SETTINGS self
|
||||||
|
-- @param #string Locale
|
||||||
|
function SETTINGS:SetLocale(Locale)
|
||||||
|
self.Locale = Locale or "en"
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Gets the SETTINGS text locale.
|
||||||
|
-- @param #SETTINGS self
|
||||||
|
-- @return #string
|
||||||
|
function SETTINGS:GetLocale()
|
||||||
|
return self.Locale or _SETTINGS:GetLocale()
|
||||||
|
end
|
||||||
|
|
||||||
--- Gets if the SETTINGS is metric.
|
--- Gets if the SETTINGS is metric.
|
||||||
-- @param #SETTINGS self
|
-- @param #SETTINGS self
|
||||||
-- @return #boolean true if metric.
|
-- @return #boolean true if metric.
|
||||||
@@ -300,7 +315,7 @@ do -- SETTINGS
|
|||||||
-- @param #SETTINGS self
|
-- @param #SETTINGS self
|
||||||
-- @return #boolean true if imperial.
|
-- @return #boolean true if imperial.
|
||||||
function SETTINGS:IsImperial()
|
function SETTINGS:IsImperial()
|
||||||
return (self.Metric ~= nil and self.Metric == false) or (self.Metric == nil and _SETTINGS:IsMetric())
|
return (self.Metric ~= nil and self.Metric == false) or (self.Metric == nil and _SETTINGS:IsImperial())
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sets the SETTINGS LL accuracy.
|
--- Sets the SETTINGS LL accuracy.
|
||||||
|
|||||||
@@ -1418,7 +1418,7 @@ function SPAWN:SpawnWithIndex( SpawnIndex, NoBirth )
|
|||||||
end
|
end
|
||||||
-- TODO: Need to fix this by putting an "R" in the name of the group when the group repeats.
|
-- TODO: Need to fix this by putting an "R" in the name of the group when the group repeats.
|
||||||
-- if self.Repeat then
|
-- if self.Repeat then
|
||||||
-- _DATABASE:SetStatusGroup( SpawnTemplate.name, "ReSpawn" )
|
-- _DATABASE:SetStatusGroup( SpawnTemplate.name, "ReSpawn" )
|
||||||
-- end
|
-- end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2403,8 +2403,7 @@ end
|
|||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param DCS#Vec3 Vec3 The Vec3 coordinates where to spawn the group.
|
-- @param DCS#Vec3 Vec3 The Vec3 coordinates where to spawn the group.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
||||||
self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } )
|
self:F( { self.SpawnTemplatePrefix, Vec3, SpawnIndex } )
|
||||||
|
|
||||||
@@ -2472,8 +2471,7 @@ end
|
|||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param Core.Point#Coordinate Coordinate The Coordinate coordinates where to spawn the group.
|
-- @param Core.Point#Coordinate Coordinate The Coordinate coordinates where to spawn the group.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
function SPAWN:SpawnFromCoordinate( Coordinate, SpawnIndex )
|
function SPAWN:SpawnFromCoordinate( Coordinate, SpawnIndex )
|
||||||
self:F( { self.SpawnTemplatePrefix, SpawnIndex } )
|
self:F( { self.SpawnTemplatePrefix, SpawnIndex } )
|
||||||
|
|
||||||
@@ -2487,8 +2485,7 @@ end
|
|||||||
-- @param #SPAWN self
|
-- @param #SPAWN self
|
||||||
-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 coordinates where to spawn the group.
|
-- @param Core.Point#POINT_VEC3 PointVec3 The PointVec3 coordinates where to spawn the group.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- local SpawnPointVec3 = ZONE:New( ZoneName ):GetPointVec3( 2000 ) -- Get the center of the ZONE object at 2000 meters from the ground.
|
-- local SpawnPointVec3 = ZONE:New( ZoneName ):GetPointVec3( 2000 ) -- Get the center of the ZONE object at 2000 meters from the ground.
|
||||||
@@ -2511,8 +2508,7 @@ end
|
|||||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- local SpawnVec2 = ZONE:New( ZoneName ):GetVec2()
|
-- local SpawnVec2 = ZONE:New( ZoneName ):GetVec2()
|
||||||
@@ -2544,8 +2540,7 @@ end
|
|||||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- local SpawnPointVec2 = ZONE:New( ZoneName ):GetPointVec2()
|
-- local SpawnPointVec2 = ZONE:New( ZoneName ):GetPointVec2()
|
||||||
@@ -2599,8 +2594,7 @@ end
|
|||||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil Nothing was spawned.
|
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- local SpawnStatic = STATIC:FindByName( StaticName )
|
-- local SpawnStatic = STATIC:FindByName( StaticName )
|
||||||
@@ -2631,8 +2625,7 @@ end
|
|||||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||||
-- @return Wrapper.Group#GROUP that was spawned.
|
-- @return Wrapper.Group#GROUP that was spawned or #nil if nothing was spawned.
|
||||||
-- @return #nil when nothing was spawned.
|
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
-- local SpawnZone = ZONE:New( ZoneName )
|
-- local SpawnZone = ZONE:New( ZoneName )
|
||||||
@@ -2978,9 +2971,9 @@ end
|
|||||||
function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
|
function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) -- R2.2
|
||||||
self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } )
|
self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } )
|
||||||
|
|
||||||
-- if not self.SpawnTemplate then
|
-- if not self.SpawnTemplate then
|
||||||
-- self.SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix )
|
-- self.SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix )
|
||||||
-- end
|
-- end
|
||||||
|
|
||||||
local SpawnTemplate
|
local SpawnTemplate
|
||||||
if self.TweakedTemplate ~= nil and self.TweakedTemplate == true then
|
if self.TweakedTemplate ~= nil and self.TweakedTemplate == true then
|
||||||
@@ -3376,8 +3369,12 @@ function SPAWN:_SpawnCleanUpScheduler()
|
|||||||
local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup()
|
local SpawnGroup, SpawnCursor = self:GetFirstAliveGroup()
|
||||||
self:T( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
|
self:T( { "CleanUp Scheduler:", SpawnGroup, SpawnCursor } )
|
||||||
|
|
||||||
|
local IsHelo = false
|
||||||
|
|
||||||
while SpawnGroup do
|
while SpawnGroup do
|
||||||
|
|
||||||
|
IsHelo = SpawnGroup:IsHelicopter()
|
||||||
|
|
||||||
local SpawnUnits = SpawnGroup:GetUnits()
|
local SpawnUnits = SpawnGroup:GetUnits()
|
||||||
|
|
||||||
for UnitID, UnitData in pairs( SpawnUnits ) do
|
for UnitID, UnitData in pairs( SpawnUnits ) do
|
||||||
@@ -3390,8 +3387,8 @@ function SPAWN:_SpawnCleanUpScheduler()
|
|||||||
self:T( { SpawnUnitName, Stamp } )
|
self:T( { SpawnUnitName, Stamp } )
|
||||||
|
|
||||||
if Stamp.Vec2 then
|
if Stamp.Vec2 then
|
||||||
if SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1 then
|
if (SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1) or IsHelo then
|
||||||
local NewVec2 = SpawnUnit:GetVec2()
|
local NewVec2 = SpawnUnit:GetVec2() or {x=0, y=0}
|
||||||
if (Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y) or (SpawnUnit:GetLife() <= 1) then
|
if (Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y) or (SpawnUnit:GetLife() <= 1) then
|
||||||
-- If the plane is not moving or dead , and is on the ground, assign it with a timestamp...
|
-- If the plane is not moving or dead , and is on the ground, assign it with a timestamp...
|
||||||
if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then
|
if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then
|
||||||
@@ -3409,8 +3406,8 @@ function SPAWN:_SpawnCleanUpScheduler()
|
|||||||
Stamp.Time = nil
|
Stamp.Time = nil
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if SpawnUnit:InAir() == false then
|
if SpawnUnit:InAir() == false or (IsHelo and SpawnUnit:GetLife() <= 1) then
|
||||||
Stamp.Vec2 = SpawnUnit:GetVec2()
|
Stamp.Vec2 = SpawnUnit:GetVec2() or {x=0, y=0}
|
||||||
if (SpawnUnit:GetVelocityKMH() < 1) then
|
if (SpawnUnit:GetVelocityKMH() < 1) then
|
||||||
Stamp.Time = timer.getTime()
|
Stamp.Time = timer.getTime()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,202 @@
|
|||||||
|
--- **Core** - TEXTANDSOUND (MOOSE gettext) system
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Main Features:
|
||||||
|
--
|
||||||
|
-- * A GetText for Moose
|
||||||
|
-- * Build a set of localized text entries, alongside their sounds and subtitles
|
||||||
|
-- * Aimed at class developers to offer localizable language support
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ## Example Missions:
|
||||||
|
--
|
||||||
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/).
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **applevangelist**
|
||||||
|
-- ## Date: April 2022
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- @module Core.TextAndSound
|
||||||
|
-- @image MOOSE.JPG
|
||||||
|
|
||||||
|
--- Text and Sound class.
|
||||||
|
-- @type TEXTANDSOUND
|
||||||
|
-- @field #string ClassName Name of this class.
|
||||||
|
-- @field #string version Versioning.
|
||||||
|
-- @field #string lid LID for log entries.
|
||||||
|
-- @field #string locale Default locale of this object.
|
||||||
|
-- @field #table entries Table of entries.
|
||||||
|
-- @field #string textclass Name of the class the texts belong to.
|
||||||
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
---
|
||||||
|
--
|
||||||
|
-- @field #TEXTANDSOUND
|
||||||
|
TEXTANDSOUND = {
|
||||||
|
ClassName = "TEXTANDSOUND",
|
||||||
|
version = "0.0.1",
|
||||||
|
lid = "",
|
||||||
|
locale = "en",
|
||||||
|
entries = {},
|
||||||
|
textclass = "",
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Text and Sound entry.
|
||||||
|
-- @type TEXTANDSOUND.Entry
|
||||||
|
-- @field #string Classname Name of the class this entry is for.
|
||||||
|
-- @field #string Locale Locale of this entry, defaults to "en".
|
||||||
|
-- @field #table Data The list of entries.
|
||||||
|
|
||||||
|
--- Text and Sound data
|
||||||
|
-- @type TEXTANDSOUND.Data
|
||||||
|
-- @field #string ID ID of this entry for retrieval.
|
||||||
|
-- @field #string Text Text of this entry.
|
||||||
|
-- @field #string Soundfile (optional) Soundfile File name of the corresponding sound file.
|
||||||
|
-- @field #number Soundlength (optional) Length of the sound file in seconds.
|
||||||
|
-- @field #string Subtitle (optional) Subtitle for the sound file.
|
||||||
|
|
||||||
|
--- Instantiate a new object
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @param #string ClassName Name of the class this instance is providing texts for.
|
||||||
|
-- @param #string Defaultlocale (Optional) Default locale of this instance, defaults to "en".
|
||||||
|
-- @return #TEXTANDSOUND self
|
||||||
|
function TEXTANDSOUND:New(ClassName,Defaultlocale)
|
||||||
|
-- Inherit everything from BASE class.
|
||||||
|
local self=BASE:Inherit(self, BASE:New())
|
||||||
|
-- Set some string id for output to DCS.log file.
|
||||||
|
self.lid=string.format("%s (%s) | ", self.ClassName, self.version)
|
||||||
|
self.locale = Defaultlocale or (_SETTINGS:GetLocale() or "en")
|
||||||
|
self.textclass = ClassName or "none"
|
||||||
|
self.entries = {}
|
||||||
|
local initentry = {} -- #TEXTANDSOUND.Entry
|
||||||
|
initentry.Classname = ClassName
|
||||||
|
initentry.Data = {}
|
||||||
|
initentry.Locale = self.locale
|
||||||
|
self.entries[self.locale] = initentry
|
||||||
|
self:I(self.lid .. "Instantiated.")
|
||||||
|
self:T({self.entries[self.locale]})
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add an entry
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @param #string Locale Locale to set for this entry, e.g. "de".
|
||||||
|
-- @param #string ID Unique(!) ID of this entry under this locale (i.e. use the same ID to get localized text for the entry in another language).
|
||||||
|
-- @param #string Text Text for this entry.
|
||||||
|
-- @param #string Soundfile (Optional) Sound file name for this entry.
|
||||||
|
-- @param #number Soundlength (Optional) Length of the sound file in seconds.
|
||||||
|
-- @param #string Subtitle (Optional) Subtitle to be used alongside the sound file.
|
||||||
|
-- @return #TEXTANDSOUND self
|
||||||
|
function TEXTANDSOUND:AddEntry(Locale,ID,Text,Soundfile,Soundlength,Subtitle)
|
||||||
|
self:T(self.lid .. "AddEntry")
|
||||||
|
local locale = Locale or self.locale
|
||||||
|
local dataentry = {} -- #TEXTANDSOUND.Data
|
||||||
|
dataentry.ID = ID or "1"
|
||||||
|
dataentry.Text = Text or "none"
|
||||||
|
dataentry.Soundfile = Soundfile
|
||||||
|
dataentry.Soundlength = Soundlength or 0
|
||||||
|
dataentry.Subtitle = Subtitle
|
||||||
|
if not self.entries[locale] then
|
||||||
|
local initentry = {} -- #TEXTANDSOUND.Entry
|
||||||
|
initentry.Classname = self.textclass -- class name entry
|
||||||
|
initentry.Data = {} -- data array
|
||||||
|
initentry.Locale = locale -- default locale
|
||||||
|
self.entries[locale] = initentry
|
||||||
|
end
|
||||||
|
self.entries[locale].Data[ID] = dataentry
|
||||||
|
self:T({self.entries[locale].Data})
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get an entry
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @param #string ID The unique ID of the data to be retrieved.
|
||||||
|
-- @param #string Locale (Optional) The locale of the text to be retrieved - defauls to default locale set with `New()`.
|
||||||
|
-- @return #string Text Text or nil if not found and no fallback.
|
||||||
|
-- @return #string Soundfile Filename or nil if not found and no fallback.
|
||||||
|
-- @return #string Soundlength Length of the sound or 0 if not found and no fallback.
|
||||||
|
-- @return #string Subtitle Text for subtitle or nil if not found and no fallback.
|
||||||
|
function TEXTANDSOUND:GetEntry(ID,Locale)
|
||||||
|
self:T(self.lid .. "GetEntry")
|
||||||
|
local locale = Locale or self.locale
|
||||||
|
if not self.entries[locale] then
|
||||||
|
-- fall back to default "en"
|
||||||
|
locale = self.locale
|
||||||
|
end
|
||||||
|
local Text,Soundfile,Soundlength,Subtitle = nil, nil, 0, nil
|
||||||
|
if self.entries[locale] then
|
||||||
|
if self.entries[locale].Data then
|
||||||
|
local data = self.entries[locale].Data[ID] -- #TEXTANDSOUND.Data
|
||||||
|
if data then
|
||||||
|
Text = data.Text
|
||||||
|
Soundfile = data.Soundfile
|
||||||
|
Soundlength = data.Soundlength
|
||||||
|
Subtitle = data.Subtitle
|
||||||
|
elseif self.entries[self.locale].Data[ID] then
|
||||||
|
-- no matching entry, try default
|
||||||
|
local data = self.entries[self.locale].Data[ID]
|
||||||
|
Text = data.Text
|
||||||
|
Soundfile = data.Soundfile
|
||||||
|
Soundlength = data.Soundlength
|
||||||
|
Subtitle = data.Subtitle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return nil, nil, 0, nil
|
||||||
|
end
|
||||||
|
return Text,Soundfile,Soundlength,Subtitle
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the default locale of this object
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @return #string locale
|
||||||
|
function TEXTANDSOUND:GetDefaultLocale()
|
||||||
|
self:T(self.lid .. "GetDefaultLocale")
|
||||||
|
return self.locale
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set default locale of this object
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @param #string locale
|
||||||
|
-- @return #TEXTANDSOUND self
|
||||||
|
function TEXTANDSOUND:SetDefaultLocale(locale)
|
||||||
|
self:T(self.lid .. "SetDefaultLocale")
|
||||||
|
self.locale = locale or "en"
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a locale exists
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @return #boolean outcome
|
||||||
|
function TEXTANDSOUND:HasLocale(Locale)
|
||||||
|
self:T(self.lid .. "HasLocale")
|
||||||
|
return self.entries[Locale] and true or false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Flush all entries to the log
|
||||||
|
-- @param #TEXTANDSOUND self
|
||||||
|
-- @return #TEXTANDSOUND self
|
||||||
|
function TEXTANDSOUND:FlushToLog()
|
||||||
|
self:I(self.lid .. "Flushing entries:")
|
||||||
|
local text = string.format("Textclass: %s | Default Locale: %s",self.textclass, self.locale)
|
||||||
|
for _,_entry in pairs(self.entries) do
|
||||||
|
local entry = _entry -- #TEXTANDSOUND.Entry
|
||||||
|
local text = string.format("Textclassname: %s | Locale: %s",entry.Classname, entry.Locale)
|
||||||
|
self:I(text)
|
||||||
|
for _ID,_data in pairs(entry.Data) do
|
||||||
|
local data = _data -- #TEXTANDSOUND.Data
|
||||||
|
local text = string.format("ID: %s\nText: %s\nSoundfile: %s With length: %d\nSubtitle: %s",tostring(_ID), data.Text or "none",data.Soundfile or "none",data.Soundlength or 0,data.Subtitle or "none")
|
||||||
|
self:I(text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- End TextAndSound
|
||||||
|
----------------------------------------------------------------
|
||||||
@@ -34,8 +34,6 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- 
|
|
||||||
--
|
|
||||||
-- # The TIMER Concept
|
-- # The TIMER Concept
|
||||||
--
|
--
|
||||||
-- The TIMER class is the little sister of the @{Core.Scheduler#SCHEDULER} class. It does the same thing but is a bit easier to use and has less overhead. It should be sufficient in many cases.
|
-- The TIMER class is the little sister of the @{Core.Scheduler#SCHEDULER} class. It does the same thing but is a bit easier to use and has less overhead. It should be sufficient in many cases.
|
||||||
@@ -107,19 +105,17 @@ TIMER = {
|
|||||||
--- Timer ID.
|
--- Timer ID.
|
||||||
_TIMERID=0
|
_TIMERID=0
|
||||||
|
|
||||||
--- Timer data base.
|
|
||||||
--_TIMERDB={}
|
|
||||||
|
|
||||||
--- TIMER class version.
|
--- TIMER class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
TIMER.version="0.1.1"
|
TIMER.version="0.1.2"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- TODO: A lot.
|
-- TODO: Randomization.
|
||||||
-- TODO: Write docs.
|
-- TODO: Pause/unpause.
|
||||||
|
-- DONE: Write docs.
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- Constructor
|
-- Constructor
|
||||||
@@ -156,9 +152,6 @@ function TIMER:New(Function, ...)
|
|||||||
-- Log id.
|
-- Log id.
|
||||||
self.lid=string.format("TIMER UID=%d | ", self.uid)
|
self.lid=string.format("TIMER UID=%d | ", self.uid)
|
||||||
|
|
||||||
-- Add to DB.
|
|
||||||
--_TIMERDB[self.uid]=self
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -174,7 +167,7 @@ function TIMER:Start(Tstart, dT, Duration)
|
|||||||
local Tnow=timer.getTime()
|
local Tnow=timer.getTime()
|
||||||
|
|
||||||
-- Start time in sec.
|
-- Start time in sec.
|
||||||
self.Tstart=Tstart and Tnow+Tstart or Tnow+0.001 -- one millisecond delay if Tstart=nil
|
self.Tstart=Tstart and Tnow+math.max(Tstart, 0.001) or Tnow+0.001 -- one millisecond delay if Tstart=nil
|
||||||
|
|
||||||
-- Set time interval.
|
-- Set time interval.
|
||||||
self.dT=dT
|
self.dT=dT
|
||||||
@@ -220,9 +213,6 @@ function TIMER:Stop(Delay)
|
|||||||
-- Not running any more.
|
-- Not running any more.
|
||||||
self.isrunning=false
|
self.isrunning=false
|
||||||
|
|
||||||
-- Remove DB entry.
|
|
||||||
--_TIMERDB[self.uid]=nil
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -239,6 +229,15 @@ function TIMER:SetMaxFunctionCalls(Nmax)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set time interval. Can also be set when the timer is already running and is applied after the next function call.
|
||||||
|
-- @param #TIMER self
|
||||||
|
-- @param #number dT Time interval in seconds.
|
||||||
|
-- @return #TIMER self
|
||||||
|
function TIMER:SetTimeInterval(dT)
|
||||||
|
self.dT=dT
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Check if the timer has been started and was not stopped.
|
--- Check if the timer has been started and was not stopped.
|
||||||
-- @param #TIMER self
|
-- @param #TIMER self
|
||||||
-- @return #boolean If `true`, the timer is running.
|
-- @return #boolean If `true`, the timer is running.
|
||||||
|
|||||||
@@ -59,7 +59,11 @@
|
|||||||
-- @field #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability.
|
-- @field #number ZoneProbability A value between 0 and 1. 0 = 0% and 1 = 100% probability.
|
||||||
-- @field #number DrawID Unique ID of the drawn zone on the F10 map.
|
-- @field #number DrawID Unique ID of the drawn zone on the F10 map.
|
||||||
-- @field #table Color Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value.
|
-- @field #table Color Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value.
|
||||||
|
-- @field #table FillColor Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value.
|
||||||
|
-- @field #number drawCoalition Draw coalition.
|
||||||
-- @field #number ZoneID ID of zone. Only zones defined in the ME have an ID!
|
-- @field #number ZoneID ID of zone. Only zones defined in the ME have an ID!
|
||||||
|
-- @field #table Table of any trigger zone properties from the ME. The key is the Name of the property, and the value is the property's Value.
|
||||||
|
-- @field #number Surface Type of surface. Only determined at the center of the zone!
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
|
||||||
@@ -103,6 +107,11 @@
|
|||||||
-- * @{#ZONE_BASE.SmokeZone}(): Smokes the zone boundaries in a color.
|
-- * @{#ZONE_BASE.SmokeZone}(): Smokes the zone boundaries in a color.
|
||||||
-- * @{#ZONE_BASE.FlareZone}(): Flares the zone boundaries in a color.
|
-- * @{#ZONE_BASE.FlareZone}(): Flares the zone boundaries in a color.
|
||||||
--
|
--
|
||||||
|
-- ## A zone might have additional Properties created in the DCS Mission Editor, which can be accessed:
|
||||||
|
--
|
||||||
|
-- *@{#ZONE_BASE.GetProperty}(): Returns the Value of the zone with the given PropertyName, or nil if no matching property exists.
|
||||||
|
-- *@{#ZONE_BASE.GetAllProperties}(): Returns the zone Properties table.
|
||||||
|
--
|
||||||
-- @field #ZONE_BASE
|
-- @field #ZONE_BASE
|
||||||
ZONE_BASE = {
|
ZONE_BASE = {
|
||||||
ClassName = "ZONE_BASE",
|
ClassName = "ZONE_BASE",
|
||||||
@@ -111,6 +120,8 @@ ZONE_BASE = {
|
|||||||
DrawID=nil,
|
DrawID=nil,
|
||||||
Color={},
|
Color={},
|
||||||
ZoneID=nil,
|
ZoneID=nil,
|
||||||
|
Properties={},
|
||||||
|
Sureface=nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -336,18 +347,41 @@ end
|
|||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @return #nil The bounding square.
|
-- @return #nil The bounding square.
|
||||||
function ZONE_BASE:GetBoundingSquare()
|
function ZONE_BASE:GetBoundingSquare()
|
||||||
--return { x1 = 0, y1 = 0, x2 = 0, y2 = 0 }
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get surface type of the zone.
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @return DCS#SurfaceType Type of surface.
|
||||||
|
function ZONE_BASE:GetSurfaceType()
|
||||||
|
local coord=self:GetCoordinate()
|
||||||
|
local surface=coord:GetSurfaceType()
|
||||||
|
return surface
|
||||||
|
end
|
||||||
|
|
||||||
--- Bound the zone boundaries with a tires.
|
--- Bound the zone boundaries with a tires.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
function ZONE_BASE:BoundZone()
|
function ZONE_BASE:BoundZone()
|
||||||
self:F2()
|
self:F2()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Set draw coalition of zone.
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @param #number Coalition Coalition. Default -1.
|
||||||
|
-- @return #ZONE_BASE self
|
||||||
|
function ZONE_BASE:SetDrawCoalition(Coalition)
|
||||||
|
self.drawCoalition=Coalition or -1
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get draw coalition of zone.
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @return #number Draw coaliton.
|
||||||
|
function ZONE_BASE:GetDrawCoalition()
|
||||||
|
return self.drawCoalition or -1
|
||||||
|
end
|
||||||
|
|
||||||
--- Set color of zone.
|
--- Set color of zone.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @param #table RGBcolor RGB color table. Default `{1, 0, 0}`.
|
-- @param #table RGBcolor RGB color table. Default `{1, 0, 0}`.
|
||||||
@@ -371,7 +405,7 @@ end
|
|||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @return #table Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value.
|
-- @return #table Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value.
|
||||||
function ZONE_BASE:GetColor()
|
function ZONE_BASE:GetColor()
|
||||||
return self.Color
|
return self.Color or {1, 0, 0, 0.15}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get RGB color of zone.
|
--- Get RGB color of zone.
|
||||||
@@ -379,9 +413,10 @@ end
|
|||||||
-- @return #table Table with three entries, e.g. {1, 0, 0}, which is the RGB color code.
|
-- @return #table Table with three entries, e.g. {1, 0, 0}, which is the RGB color code.
|
||||||
function ZONE_BASE:GetColorRGB()
|
function ZONE_BASE:GetColorRGB()
|
||||||
local rgb={}
|
local rgb={}
|
||||||
rgb[1]=self.Color[1]
|
local Color=self:GetColor()
|
||||||
rgb[2]=self.Color[2]
|
rgb[1]=Color[1]
|
||||||
rgb[3]=self.Color[3]
|
rgb[2]=Color[2]
|
||||||
|
rgb[3]=Color[3]
|
||||||
return rgb
|
return rgb
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -389,7 +424,55 @@ end
|
|||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE_BASE self
|
||||||
-- @return #number Alpha value.
|
-- @return #number Alpha value.
|
||||||
function ZONE_BASE:GetColorAlpha()
|
function ZONE_BASE:GetColorAlpha()
|
||||||
local alpha=self.Color[4]
|
local Color=self:GetColor()
|
||||||
|
local alpha=Color[4]
|
||||||
|
return alpha
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set fill color of zone.
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @param #table RGBcolor RGB color table. Default `{1, 0, 0}`.
|
||||||
|
-- @param #number Alpha Transparacy between 0 and 1. Default 0.15.
|
||||||
|
-- @return #ZONE_BASE self
|
||||||
|
function ZONE_BASE:SetFillColor(RGBcolor, Alpha)
|
||||||
|
|
||||||
|
RGBcolor=RGBcolor or {1, 0, 0}
|
||||||
|
Alpha=Alpha or 0.15
|
||||||
|
|
||||||
|
self.FillColor={}
|
||||||
|
self.FillColor[1]=RGBcolor[1]
|
||||||
|
self.FillColor[2]=RGBcolor[2]
|
||||||
|
self.FillColor[3]=RGBcolor[3]
|
||||||
|
self.FillColor[4]=Alpha
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get fill color table of the zone.
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @return #table Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value.
|
||||||
|
function ZONE_BASE:GetFillColor()
|
||||||
|
return self.FillColor or {1, 0, 0, 0.15}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get RGB fill color of zone.
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @return #table Table with three entries, e.g. {1, 0, 0}, which is the RGB color code.
|
||||||
|
function ZONE_BASE:GetFillColorRGB()
|
||||||
|
local rgb={}
|
||||||
|
local FillColor=self:GetFillColor()
|
||||||
|
rgb[1]=FillColor[1]
|
||||||
|
rgb[2]=FillColor[2]
|
||||||
|
rgb[3]=FillColor[3]
|
||||||
|
return rgb
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get transperency Alpha fill value of zone.
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @return #number Alpha value.
|
||||||
|
function ZONE_BASE:GetFillColorAlpha()
|
||||||
|
local FillColor=self:GetFillColor()
|
||||||
|
local alpha=FillColor[4]
|
||||||
return alpha
|
return alpha
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -481,6 +564,26 @@ function ZONE_BASE:GetZoneMaybe()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns the Value of the zone with the given PropertyName, or nil if no matching property exists.
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @param #string PropertyName The name of a the TriggerZone Property to be retrieved.
|
||||||
|
-- @return #string The Value of the TriggerZone Property with the given PropertyName, or nil if absent.
|
||||||
|
-- @usage
|
||||||
|
--
|
||||||
|
-- local PropertiesZone = ZONE:FindByName("Properties Zone")
|
||||||
|
-- local Property = "ExampleProperty"
|
||||||
|
-- local PropertyValue = PropertiesZone:GetProperty(Property)
|
||||||
|
--
|
||||||
|
function ZONE_BASE:GetProperty(PropertyName)
|
||||||
|
return self.Properties[PropertyName]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns the zone Properties table.
|
||||||
|
-- @param #ZONE_BASE self
|
||||||
|
-- @return #table The Key:Value table of TriggerZone properties of the zone.
|
||||||
|
function ZONE_BASE:GetAllProperties()
|
||||||
|
return self.Properties
|
||||||
|
end
|
||||||
|
|
||||||
--- The ZONE_RADIUS class, defined by a zone name, a location and a radius.
|
--- The ZONE_RADIUS class, defined by a zone name, a location and a radius.
|
||||||
-- @type ZONE_RADIUS
|
-- @type ZONE_RADIUS
|
||||||
@@ -823,8 +926,8 @@ end
|
|||||||
-- @param ObjectCategories An array of categories of the objects to find in the zone. E.g. `{Object.Category.UNIT}`
|
-- @param ObjectCategories An array of categories of the objects to find in the zone. E.g. `{Object.Category.UNIT}`
|
||||||
-- @param UnitCategories An array of unit categories of the objects to find in the zone. E.g. `{Unit.Category.GROUND_UNIT,Unit.Category.SHIP}`
|
-- @param UnitCategories An array of unit categories of the objects to find in the zone. E.g. `{Unit.Category.GROUND_UNIT,Unit.Category.SHIP}`
|
||||||
-- @usage
|
-- @usage
|
||||||
-- self.Zone:Scan({Object.Category.UNIT},{Unit.Category.GROUND_UNIT})
|
-- myzone:Scan({Object.Category.UNIT},{Unit.Category.GROUND_UNIT})
|
||||||
-- local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
-- local IsAttacked = myzone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||||
function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
||||||
|
|
||||||
self.ScanData = {}
|
self.ScanData = {}
|
||||||
@@ -894,7 +997,7 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
|
|||||||
local SceneryName = ZoneObject:getName()
|
local SceneryName = ZoneObject:getName()
|
||||||
self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {}
|
self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {}
|
||||||
self.ScanData.Scenery[SceneryType][SceneryName] = SCENERY:Register( SceneryName, ZoneObject )
|
self.ScanData.Scenery[SceneryType][SceneryName] = SCENERY:Register( SceneryName, ZoneObject )
|
||||||
self:F2( { SCENERY = self.ScanData.Scenery[SceneryType][SceneryName] } )
|
self:T( { SCENERY = self.ScanData.Scenery[SceneryType][SceneryName] } )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -1157,7 +1260,9 @@ end
|
|||||||
-- @return #boolean true if the location is within the zone.
|
-- @return #boolean true if the location is within the zone.
|
||||||
function ZONE_RADIUS:IsVec2InZone( Vec2 )
|
function ZONE_RADIUS:IsVec2InZone( Vec2 )
|
||||||
self:F2( Vec2 )
|
self:F2( Vec2 )
|
||||||
|
|
||||||
if not Vec2 then return false end
|
if not Vec2 then return false end
|
||||||
|
|
||||||
local ZoneVec2 = self:GetVec2()
|
local ZoneVec2 = self:GetVec2()
|
||||||
|
|
||||||
if ZoneVec2 then
|
if ZoneVec2 then
|
||||||
@@ -1189,13 +1294,13 @@ end
|
|||||||
-- @return DCS#Vec2 The random location within the zone.
|
-- @return DCS#Vec2 The random location within the zone.
|
||||||
function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
||||||
|
|
||||||
local Vec2 = self:GetVec2()
|
local Vec2 = self:GetVec2()
|
||||||
local _inner = inner or 0
|
local _inner = inner or 0
|
||||||
local _outer = outer or self:GetRadius()
|
local _outer = outer or self:GetRadius()
|
||||||
|
|
||||||
if surfacetypes and type(surfacetypes)~="table" then
|
if surfacetypes and type(surfacetypes)~="table" then
|
||||||
surfacetypes={surfacetypes}
|
surfacetypes={surfacetypes}
|
||||||
end
|
end
|
||||||
|
|
||||||
local function _getpoint()
|
local function _getpoint()
|
||||||
local point = {}
|
local point = {}
|
||||||
@@ -1215,10 +1320,10 @@ function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local point=_getpoint()
|
local point=_getpoint()
|
||||||
|
|
||||||
if surfacetypes then
|
if surfacetypes then
|
||||||
local N=1 ; local Nmax=100 ; local gotit=false
|
local N=1 ; local Nmax=100 ; local gotit=false
|
||||||
while gotit==false and N<=Nmax do
|
while gotit==false and N<=Nmax do
|
||||||
gotit=_checkSurface(point)
|
gotit=_checkSurface(point)
|
||||||
if gotit then
|
if gotit then
|
||||||
@@ -1230,7 +1335,7 @@ function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return point
|
return point
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
||||||
@@ -1282,8 +1387,8 @@ end
|
|||||||
|
|
||||||
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 3D location within the zone.
|
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 3D location within the zone.
|
||||||
-- @param #ZONE_RADIUS self
|
-- @param #ZONE_RADIUS self
|
||||||
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0.
|
-- @param #number inner (Optional) Minimal distance from the center of the zone in meters. Default is 0 m.
|
||||||
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone in meters. Default is the radius of the zone.
|
||||||
-- @param #table surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type!
|
-- @param #table surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type!
|
||||||
-- @return Core.Point#COORDINATE The random coordinate.
|
-- @return Core.Point#COORDINATE The random coordinate.
|
||||||
function ZONE_RADIUS:GetRandomCoordinate(inner, outer, surfacetypes)
|
function ZONE_RADIUS:GetRandomCoordinate(inner, outer, surfacetypes)
|
||||||
@@ -1295,7 +1400,86 @@ function ZONE_RADIUS:GetRandomCoordinate(inner, outer, surfacetypes)
|
|||||||
return Coordinate
|
return Coordinate
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns a @{Core.Point#COORDINATE} object reflecting a random location within the zone where there are no **map objects** of type "Building".
|
||||||
|
-- Does not find statics you might have placed there. **Note** This might be quite CPU intensive, use with care.
|
||||||
|
-- @param #ZONE_RADIUS self
|
||||||
|
-- @param #number inner (Optional) Minimal distance from the center of the zone in meters. Default is 0m.
|
||||||
|
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone in meters. Default is the radius of the zone.
|
||||||
|
-- @param #number distance (Optional) Minumum distance from any building coordinate. Defaults to 100m.
|
||||||
|
-- @param #boolean markbuildings (Optional) Place markers on found buildings (if any).
|
||||||
|
-- @param #boolean markfinal (Optional) Place marker on the final coordinate (if any).
|
||||||
|
-- @return Core.Point#COORDINATE The random coordinate or `nil` if cannot be found in 1000 iterations.
|
||||||
|
function ZONE_RADIUS:GetRandomCoordinateWithoutBuildings(inner,outer,distance,markbuildings,markfinal)
|
||||||
|
|
||||||
|
local dist = distance or 100
|
||||||
|
|
||||||
|
local objects = {}
|
||||||
|
|
||||||
|
if self.ScanData and self.ScanData.Scenery then
|
||||||
|
objects = self:GetScannedScenery()
|
||||||
|
else
|
||||||
|
self:Scan({Object.Category.SCENERY})
|
||||||
|
objects = self:GetScannedScenery()
|
||||||
|
end
|
||||||
|
|
||||||
|
local T0 = timer.getTime()
|
||||||
|
local T1 = timer.getTime()
|
||||||
|
|
||||||
|
|
||||||
|
local buildings = {}
|
||||||
|
if self.ScanData and self.ScanData.BuildingCoordinates then
|
||||||
|
buildings = self.ScanData.BuildingCoordinates
|
||||||
|
else
|
||||||
|
-- build table of buildings coordinates
|
||||||
|
for _,_object in pairs (objects) do
|
||||||
|
for _,_scen in pairs (_object) do
|
||||||
|
local scenery = _scen -- Wrapper.Scenery#SCENERY
|
||||||
|
local description=scenery:GetDesc()
|
||||||
|
if description and description.attributes and description.attributes.Buildings then
|
||||||
|
if markbuildings then
|
||||||
|
MARKER:New(scenery:GetCoordinate(),"Building"):ToAll()
|
||||||
|
end
|
||||||
|
buildings[#buildings+1] = scenery:GetCoordinate()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.ScanData.BuildingCoordinates = buildings
|
||||||
|
end
|
||||||
|
|
||||||
|
-- max 1000 tries
|
||||||
|
local rcoord = nil
|
||||||
|
local found = false
|
||||||
|
local iterations = 0
|
||||||
|
|
||||||
|
for i=1,1000 do
|
||||||
|
iterations = iterations + 1
|
||||||
|
rcoord = self:GetRandomCoordinate(inner,outer)
|
||||||
|
found = false
|
||||||
|
for _,_coord in pairs (buildings) do
|
||||||
|
local coord = _coord -- Core.Point#COORDINATE
|
||||||
|
-- keep >50m dist from buildings
|
||||||
|
if coord:Get2DDistance(rcoord) > dist then
|
||||||
|
found = true
|
||||||
|
else
|
||||||
|
found = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if found then
|
||||||
|
-- we have a winner!
|
||||||
|
if markfinal then
|
||||||
|
MARKER:New(rcoord,"FREE"):ToAll()
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
T1=timer.getTime()
|
||||||
|
|
||||||
|
self:T(string.format("Found a coordinate: %s | Iterations: %d | Time: %d",tostring(found),iterations,T1-T0))
|
||||||
|
|
||||||
|
if found then return rcoord else return nil end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- @type ZONE
|
--- @type ZONE
|
||||||
-- @extends #ZONE_RADIUS
|
-- @extends #ZONE_RADIUS
|
||||||
@@ -1371,9 +1555,9 @@ function ZONE:New( ZoneName )
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Find a zone in the _DATABASE using the name of the zone.
|
--- Find a zone in the _DATABASE using the name of the zone.
|
||||||
-- @param #ZONE_BASE self
|
-- @param #ZONE self
|
||||||
-- @param #string ZoneName The name of the zone.
|
-- @param #string ZoneName The name of the zone.
|
||||||
-- @return #ZONE_BASE self
|
-- @return #ZONE self
|
||||||
function ZONE:FindByName( ZoneName )
|
function ZONE:FindByName( ZoneName )
|
||||||
|
|
||||||
local ZoneFound = _DATABASE:FindZone( ZoneName )
|
local ZoneFound = _DATABASE:FindZone( ZoneName )
|
||||||
@@ -1609,7 +1793,7 @@ end
|
|||||||
|
|
||||||
|
|
||||||
--- @type ZONE_POLYGON_BASE
|
--- @type ZONE_POLYGON_BASE
|
||||||
-- --@field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCS#Vec2}.
|
-- @field #ZONE_POLYGON_BASE.ListVec2 Polygon The polygon defined by an array of @{DCS#Vec2}.
|
||||||
-- @extends #ZONE_BASE
|
-- @extends #ZONE_BASE
|
||||||
|
|
||||||
|
|
||||||
@@ -1847,7 +2031,7 @@ function ZONE_POLYGON_BASE:BoundZone( UnBound )
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Draw the zone on the F10 map. **NOTE** Currently, only polygons with **exactly four points** are supported!
|
--- Draw the zone on the F10 map. **NOTE** Currently, only polygons **up to ten points** are supported!
|
||||||
-- @param #ZONE_POLYGON_BASE self
|
-- @param #ZONE_POLYGON_BASE self
|
||||||
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
|
-- @param #number Coalition Coalition: All=-1, Neutral=0, Red=1, Blue=2. Default -1=All.
|
||||||
-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red.
|
-- @param #table Color RGB color table {r, g, b}, e.g. {1,0,0} for red.
|
||||||
@@ -1859,33 +2043,48 @@ end
|
|||||||
-- @return #ZONE_POLYGON_BASE self
|
-- @return #ZONE_POLYGON_BASE self
|
||||||
function ZONE_POLYGON_BASE:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly)
|
function ZONE_POLYGON_BASE:DrawZone(Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly)
|
||||||
|
|
||||||
local coordinate=COORDINATE:NewFromVec2(self._.Polygon[1])
|
if self._.Polygon and #self._.Polygon>=3 then
|
||||||
|
|
||||||
Color=Color or self:GetColorRGB()
|
local coordinate=COORDINATE:NewFromVec2(self._.Polygon[1])
|
||||||
Alpha=Alpha or 1
|
|
||||||
|
|
||||||
FillColor=FillColor or UTILS.DeepCopy(Color)
|
Coalition=Coalition or self:GetDrawCoalition()
|
||||||
FillAlpha=FillAlpha or self:GetColorAlpha()
|
|
||||||
|
|
||||||
|
-- Set draw coalition.
|
||||||
|
self:SetDrawCoalition(Coalition)
|
||||||
|
|
||||||
if #self._.Polygon==4 then
|
Color=Color or self:GetColorRGB()
|
||||||
|
Alpha=Alpha or 1
|
||||||
|
|
||||||
local Coord2=COORDINATE:NewFromVec2(self._.Polygon[2])
|
-- Set color.
|
||||||
local Coord3=COORDINATE:NewFromVec2(self._.Polygon[3])
|
self:SetColor(Color, Alpha)
|
||||||
local Coord4=COORDINATE:NewFromVec2(self._.Polygon[4])
|
|
||||||
|
|
||||||
self.DrawID=coordinate:QuadToAll(Coord2, Coord3, Coord4, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly)
|
FillColor=FillColor or self:GetFillColorRGB()
|
||||||
|
if not FillColor then UTILS.DeepCopy(Color) end
|
||||||
|
FillAlpha=FillAlpha or self:GetFillColorAlpha()
|
||||||
|
if not FillAlpha then FillAlpha=0.15 end
|
||||||
|
|
||||||
else
|
-- Set fill color.
|
||||||
|
self:SetFillColor(FillColor, FillAlpha)
|
||||||
|
|
||||||
local Coordinates=self:GetVerticiesCoordinates()
|
if #self._.Polygon==4 then
|
||||||
table.remove(Coordinates, 1)
|
|
||||||
|
|
||||||
self.DrawID=coordinate:MarkupToAllFreeForm(Coordinates, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly)
|
local Coord2=COORDINATE:NewFromVec2(self._.Polygon[2])
|
||||||
|
local Coord3=COORDINATE:NewFromVec2(self._.Polygon[3])
|
||||||
|
local Coord4=COORDINATE:NewFromVec2(self._.Polygon[4])
|
||||||
|
|
||||||
|
self.DrawID=coordinate:QuadToAll(Coord2, Coord3, Coord4, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly)
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
local Coordinates=self:GetVerticiesCoordinates()
|
||||||
|
table.remove(Coordinates, 1)
|
||||||
|
|
||||||
|
self.DrawID=coordinate:MarkupToAllFreeForm(Coordinates, Coalition, Color, Alpha, FillColor, FillAlpha, LineType, ReadOnly)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1966,7 +2165,7 @@ end
|
|||||||
-- @return #boolean true if the location is within the zone.
|
-- @return #boolean true if the location is within the zone.
|
||||||
function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 )
|
function ZONE_POLYGON_BASE:IsVec2InZone( Vec2 )
|
||||||
self:F2( Vec2 )
|
self:F2( Vec2 )
|
||||||
if not Vec2 then return false end
|
if not Vec2 then return false end
|
||||||
local Next
|
local Next
|
||||||
local Prev
|
local Prev
|
||||||
local InPolygon = false
|
local InPolygon = false
|
||||||
@@ -2218,6 +2417,206 @@ function ZONE_POLYGON:FindByName( ZoneName )
|
|||||||
return ZoneFound
|
return ZoneFound
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do -- ZONE_ELASTIC
|
||||||
|
|
||||||
|
--- @type ZONE_ELASTIC
|
||||||
|
-- @field #table points Points in 2D.
|
||||||
|
-- @field #table setGroups Set of GROUPs.
|
||||||
|
-- @field #table setOpsGroups Set of OPSGROUPS.
|
||||||
|
-- @field #table setUnits Set of UNITs.
|
||||||
|
-- @field #number updateID Scheduler ID for updating.
|
||||||
|
-- @extends #ZONE_POLYGON_BASE
|
||||||
|
|
||||||
|
--- The ZONE_ELASTIC class defines a dynamic polygon zone, where only the convex hull is used.
|
||||||
|
--
|
||||||
|
-- @field #ZONE_ELASTIC
|
||||||
|
ZONE_ELASTIC = {
|
||||||
|
ClassName="ZONE_ELASTIC",
|
||||||
|
points={},
|
||||||
|
setGroups={}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Constructor to create a ZONE_ELASTIC instance.
|
||||||
|
-- @param #ZONE_ELASTIC self
|
||||||
|
-- @param #string ZoneName Name of the zone.
|
||||||
|
-- @param DCS#Vec2 Points (Optional) Fixed points.
|
||||||
|
-- @return #ZONE_ELASTIC self
|
||||||
|
function ZONE_ELASTIC:New(ZoneName, Points)
|
||||||
|
|
||||||
|
local self=BASE:Inherit(self, ZONE_POLYGON_BASE:New(ZoneName, Points)) --#ZONE_ELASTIC
|
||||||
|
|
||||||
|
-- Zone objects are added to the _DATABASE and SET_ZONE objects.
|
||||||
|
_EVENTDISPATCHER:CreateEventNewZone( self )
|
||||||
|
|
||||||
|
if Points then
|
||||||
|
self.points=Points
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a vertex (point) to the polygon.
|
||||||
|
-- @param #ZONE_ELASTIC self
|
||||||
|
-- @param DCS#Vec2 Vec2 Point in 2D (with x and y coordinates).
|
||||||
|
-- @return #ZONE_ELASTIC self
|
||||||
|
function ZONE_ELASTIC:AddVertex2D(Vec2)
|
||||||
|
|
||||||
|
-- Add vec2 to points.
|
||||||
|
table.insert(self.points, Vec2)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add a vertex (point) to the polygon.
|
||||||
|
-- @param #ZONE_ELASTIC self
|
||||||
|
-- @param DCS#Vec3 Vec3 Point in 3D (with x, y and z coordinates). Only the x and z coordinates are used.
|
||||||
|
-- @return #ZONE_ELASTIC self
|
||||||
|
function ZONE_ELASTIC:AddVertex3D(Vec3)
|
||||||
|
|
||||||
|
-- Add vec2 from vec3 to points.
|
||||||
|
table.insert(self.points, {x=Vec3.x, y=Vec3.z})
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Add a set of groups. Positions of the group will be considered as polygon vertices when contructing the convex hull.
|
||||||
|
-- @param #ZONE_ELASTIC self
|
||||||
|
-- @param Core.Set#SET_GROUP SetGroup Set of groups.
|
||||||
|
-- @return #ZONE_ELASTIC self
|
||||||
|
function ZONE_ELASTIC:AddSetGroup(GroupSet)
|
||||||
|
|
||||||
|
-- Add set to table.
|
||||||
|
table.insert(self.setGroups, GroupSet)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Update the convex hull of the polygon.
|
||||||
|
-- This uses the [Graham scan](https://en.wikipedia.org/wiki/Graham_scan).
|
||||||
|
-- @param #ZONE_ELASTIC self
|
||||||
|
-- @param #number Delay Delay in seconds before the zone is updated. Default 0.
|
||||||
|
-- @param #boolean Draw Draw the zone. Default `nil`.
|
||||||
|
-- @return #ZONE_ELASTIC self
|
||||||
|
function ZONE_ELASTIC:Update(Delay, Draw)
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(string.format("Updating ZONE_ELASTIC %s", tostring(self.ZoneName)))
|
||||||
|
|
||||||
|
-- Copy all points.
|
||||||
|
local points=UTILS.DeepCopy(self.points or {})
|
||||||
|
|
||||||
|
if self.setGroups then
|
||||||
|
for _,_setGroup in pairs(self.setGroups) do
|
||||||
|
local setGroup=_setGroup --Core.Set#SET_GROUP
|
||||||
|
for _,_group in pairs(setGroup.Set) do
|
||||||
|
local group=_group --Wrapper.Group#GROUP
|
||||||
|
if group and group:IsAlive() then
|
||||||
|
table.insert(points, group:GetVec2())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update polygon verticies from points.
|
||||||
|
self._.Polygon=self:_ConvexHull(points)
|
||||||
|
|
||||||
|
if Draw~=false then
|
||||||
|
if self.DrawID or Draw==true then
|
||||||
|
self:UndrawZone()
|
||||||
|
self:DrawZone()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Start the updating scheduler.
|
||||||
|
-- @param #ZONE_ELASTIC self
|
||||||
|
-- @param #number Tstart Time in seconds before the updating starts.
|
||||||
|
-- @param #number dT Time interval in seconds between updates. Default 60 sec.
|
||||||
|
-- @param #number Tstop Time in seconds after which the updating stops. Default `nil`.
|
||||||
|
-- @param #boolean Draw Draw the zone. Default `nil`.
|
||||||
|
-- @return #ZONE_ELASTIC self
|
||||||
|
function ZONE_ELASTIC:StartUpdate(Tstart, dT, Tstop, Draw)
|
||||||
|
|
||||||
|
self.updateID=self:ScheduleRepeat(Tstart, dT, 0, Tstop, ZONE_ELASTIC.Update, self, 0, Draw)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Stop the updating scheduler.
|
||||||
|
-- @param #ZONE_ELASTIC self
|
||||||
|
-- @param #number Delay Delay in seconds before the scheduler will be stopped. Default 0.
|
||||||
|
-- @return #ZONE_ELASTIC self
|
||||||
|
function ZONE_ELASTIC:StopUpdate(Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
self:ScheduleOnce(Delay, ZONE_ELASTIC.StopUpdate, self)
|
||||||
|
else
|
||||||
|
|
||||||
|
if self.updateID then
|
||||||
|
|
||||||
|
self:ScheduleStop(self.updateID)
|
||||||
|
|
||||||
|
self.updateID=nil
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Create a convec hull.
|
||||||
|
-- @param #ZONE_ELASTIC self
|
||||||
|
-- @param #table pl Points
|
||||||
|
-- @return #table Points
|
||||||
|
function ZONE_ELASTIC:_ConvexHull(pl)
|
||||||
|
|
||||||
|
if #pl == 0 then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
table.sort(pl, function(left,right)
|
||||||
|
return left.x < right.x
|
||||||
|
end)
|
||||||
|
|
||||||
|
local h = {}
|
||||||
|
|
||||||
|
-- Function: ccw > 0 if three points make a counter-clockwise turn, clockwise if ccw < 0, and collinear if ccw = 0.
|
||||||
|
local function ccw(a,b,c)
|
||||||
|
return (b.x - a.x) * (c.y - a.y) > (b.y - a.y) * (c.x - a.x)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- lower hull
|
||||||
|
for i,pt in pairs(pl) do
|
||||||
|
while #h >= 2 and not ccw(h[#h-1], h[#h], pt) do
|
||||||
|
table.remove(h,#h)
|
||||||
|
end
|
||||||
|
table.insert(h,pt)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- upper hull
|
||||||
|
local t = #h + 1
|
||||||
|
for i=#pl, 1, -1 do
|
||||||
|
local pt = pl[i]
|
||||||
|
while #h >= t and not ccw(h[#h-1], h[#h], pt) do
|
||||||
|
table.remove(h, #h)
|
||||||
|
end
|
||||||
|
table.insert(h, pt)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.remove(h, #h)
|
||||||
|
|
||||||
|
return h
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
do -- ZONE_AIRBASE
|
do -- ZONE_AIRBASE
|
||||||
|
|
||||||
--- @type ZONE_AIRBASE
|
--- @type ZONE_AIRBASE
|
||||||
|
|||||||
@@ -471,6 +471,22 @@ do -- Types
|
|||||||
--@field #boolean lateActivated
|
--@field #boolean lateActivated
|
||||||
--@field #boolean uncontrolled
|
--@field #boolean uncontrolled
|
||||||
|
|
||||||
|
--- DCS template data structure.
|
||||||
|
-- @type Template
|
||||||
|
-- @field #boolean uncontrolled Aircraft is uncontrolled.
|
||||||
|
-- @field #boolean lateActivation Group is late activated.
|
||||||
|
-- @field #number x 2D Position on x-axis in meters.
|
||||||
|
-- @field #number y 2D Position on y-axis in meters.
|
||||||
|
-- @field #table units Unit list.
|
||||||
|
--
|
||||||
|
|
||||||
|
--- Unit data structure.
|
||||||
|
--@type Template.Unit
|
||||||
|
--@field #string name Name of the unit.
|
||||||
|
--@field #number x
|
||||||
|
--@field #number y
|
||||||
|
--@field #number alt
|
||||||
|
|
||||||
end --
|
end --
|
||||||
|
|
||||||
|
|
||||||
@@ -491,7 +507,6 @@ do -- Object
|
|||||||
-- @field SCENERY
|
-- @field SCENERY
|
||||||
-- @field CARGO
|
-- @field CARGO
|
||||||
|
|
||||||
|
|
||||||
--- @type Object.Desc
|
--- @type Object.Desc
|
||||||
-- @extends #Desc
|
-- @extends #Desc
|
||||||
-- @field #number life initial life level
|
-- @field #number life initial life level
|
||||||
@@ -501,6 +516,10 @@ do -- Object
|
|||||||
-- @param #Object self
|
-- @param #Object self
|
||||||
-- @return #boolean
|
-- @return #boolean
|
||||||
|
|
||||||
|
--- @function [parent=#Object] isActive
|
||||||
|
-- @param #Object self
|
||||||
|
-- @return #boolean
|
||||||
|
|
||||||
--- @function [parent=#Object] destroy
|
--- @function [parent=#Object] destroy
|
||||||
-- @param #Object self
|
-- @param #Object self
|
||||||
|
|
||||||
@@ -1133,6 +1152,11 @@ do -- Unit
|
|||||||
-- @param #Unit self
|
-- @param #Unit self
|
||||||
-- @return #Unit.Ammo
|
-- @return #Unit.Ammo
|
||||||
|
|
||||||
|
--- Returns the number of infantry that can be embark onto the aircraft. Only returns a value if run on airplanes or helicopters. Returns nil if run on ground or ship units.
|
||||||
|
-- @function [parent=#Unit] getDescentCapacity
|
||||||
|
-- @param #Unit self
|
||||||
|
-- @return #number Number of soldiers that embark.
|
||||||
|
|
||||||
--- Returns the unit sensors.
|
--- Returns the unit sensors.
|
||||||
-- @function [parent=#Unit] getSensors
|
-- @function [parent=#Unit] getSensors
|
||||||
-- @param #Unit self
|
-- @param #Unit self
|
||||||
@@ -1350,7 +1374,9 @@ do -- AI
|
|||||||
--- @type AI.Option.Ground
|
--- @type AI.Option.Ground
|
||||||
-- @field #AI.Option.Ground.id id
|
-- @field #AI.Option.Ground.id id
|
||||||
-- @field #AI.Option.Ground.val val
|
-- @field #AI.Option.Ground.val val
|
||||||
|
-- @field #AI.Option.Ground.mid mid
|
||||||
|
-- @field #AI.Option.Ground.mval mval
|
||||||
|
--
|
||||||
--- @type AI.Option.Naval
|
--- @type AI.Option.Naval
|
||||||
-- @field #AI.Option.Naval.id id
|
-- @field #AI.Option.Naval.id id
|
||||||
-- @field #AI.Option.Naval.val val
|
-- @field #AI.Option.Naval.val val
|
||||||
@@ -1373,6 +1399,11 @@ do -- AI
|
|||||||
-- @field PROHIBIT_AG
|
-- @field PROHIBIT_AG
|
||||||
-- @field MISSILE_ATTACK
|
-- @field MISSILE_ATTACK
|
||||||
-- @field PROHIBIT_WP_PASS_REPORT
|
-- @field PROHIBIT_WP_PASS_REPORT
|
||||||
|
-- @field OPTION_RADIO_USAGE_CONTACT
|
||||||
|
-- @field OPTION_RADIO_USAGE_ENGAGE
|
||||||
|
-- @field OPTION_RADIO_USAGE_KILL
|
||||||
|
-- @field JETT_TANKS_IF_EMPTY
|
||||||
|
-- @field FORCED_ATTACK
|
||||||
|
|
||||||
--- @type AI.Option.Air.id.FORMATION
|
--- @type AI.Option.Air.id.FORMATION
|
||||||
-- @field LINE_ABREAST
|
-- @field LINE_ABREAST
|
||||||
@@ -1442,19 +1473,35 @@ do -- AI
|
|||||||
--- @type AI.Option.Ground.id
|
--- @type AI.Option.Ground.id
|
||||||
-- @field NO_OPTION
|
-- @field NO_OPTION
|
||||||
-- @field ROE @{#AI.Option.Ground.val.ROE}
|
-- @field ROE @{#AI.Option.Ground.val.ROE}
|
||||||
|
-- @field FORMATION
|
||||||
-- @field DISPERSE_ON_ATTACK true or false
|
-- @field DISPERSE_ON_ATTACK true or false
|
||||||
-- @field ALARM_STATE @{#AI.Option.Ground.val.ALARM_STATE}
|
-- @field ALARM_STATE @{#AI.Option.Ground.val.ALARM_STATE}
|
||||||
-- @field ENGAGE_AIR_WEAPONS
|
-- @field ENGAGE_AIR_WEAPONS
|
||||||
|
-- @field AC_ENGAGEMENT_RANGE_RESTRICTION
|
||||||
|
|
||||||
|
--- @type AI.Option.Ground.mid -- Moose added
|
||||||
|
-- @field RESTRICT_AAA_MIN 27
|
||||||
|
-- @field RESTRICT_AAA_MAX 29
|
||||||
|
-- @field RESTRICT_TARGETS @{#AI.Option.Ground.mval.ENGAGE_TARGETS} 28
|
||||||
|
|
||||||
--- @type AI.Option.Ground.val
|
--- @type AI.Option.Ground.val
|
||||||
-- @field #AI.Option.Ground.val.ROE ROE
|
-- @field #AI.Option.Ground.val.ROE ROE
|
||||||
-- @field #AI.Option.Ground.val.ALARM_STATE ALARM_STATE
|
-- @field #AI.Option.Ground.val.ALARM_STATE ALARM_STATE
|
||||||
|
-- @field #AI.Option.Ground.val.ENGAGE_TARGETS RESTRICT_TARGETS
|
||||||
|
|
||||||
--- @type AI.Option.Ground.val.ROE
|
--- @type AI.Option.Ground.val.ROE
|
||||||
-- @field OPEN_FIRE
|
-- @field OPEN_FIRE
|
||||||
-- @field RETURN_FIRE
|
-- @field RETURN_FIRE
|
||||||
-- @field WEAPON_HOLD
|
-- @field WEAPON_HOLD
|
||||||
|
|
||||||
|
--- @type AI.Option.Ground.mval -- Moose added
|
||||||
|
-- @field #AI.Option.Ground.mval.ENGAGE_TARGETS ENGAGE_TARGETS
|
||||||
|
|
||||||
|
--- @type AI.Option.Ground.mval.ENGAGE_TARGETS -- Moose added
|
||||||
|
-- @field ANY_TARGET -- 0
|
||||||
|
-- @field AIR_UNITS_ONLY -- 1
|
||||||
|
-- @field GROUND_UNITS_ONLY -- 2
|
||||||
|
|
||||||
--- @type AI.Option.Ground.val.ALARM_STATE
|
--- @type AI.Option.Ground.val.ALARM_STATE
|
||||||
-- @field AUTO
|
-- @field AUTO
|
||||||
-- @field GREEN
|
-- @field GREEN
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ do -- DESIGNATE
|
|||||||
-- In order to prevent an overflow of designations due to many Detected Targets, there is a
|
-- In order to prevent an overflow of designations due to many Detected Targets, there is a
|
||||||
-- Maximum Designations scope that is set in the DesignationObject.
|
-- Maximum Designations scope that is set in the DesignationObject.
|
||||||
--
|
--
|
||||||
-- The method @{#DESIGNATE.SetMaximumDesignations}() will put a limit on the amount of designations put in scope of the DesignationObject.
|
-- The method @{#DESIGNATE.SetMaximumDesignations}() will put a limit on the amount of designations (target groups) put in scope of the DesignationObject.
|
||||||
-- Using the menu system, the player can "forget" a designation, so that gradually a new designation can be put in scope when detected.
|
-- Using the menu system, the player can "forget" a designation, so that gradually a new designation can be put in scope when detected.
|
||||||
--
|
--
|
||||||
-- # 4. Laser codes
|
-- # 4. Laser codes
|
||||||
@@ -562,7 +562,8 @@ do -- DESIGNATE
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the maximum amount of designations.
|
--- Set the maximum amount of designations (target groups). This will put a limit on the amount of designations in scope.
|
||||||
|
-- Using the menu system, the player can "forget" a designation, so that gradually a new designation can be put in scope when detected.
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
-- @param #number MaximumDesignations
|
-- @param #number MaximumDesignations
|
||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
@@ -602,7 +603,7 @@ do -- DESIGNATE
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Set the maximum amount of markings FACs will do, per designated target group.
|
--- Set the maximum amount of markings FACs will do, per designated target group. This will limit the number of parallelly marked units of a target group.
|
||||||
-- @param #DESIGNATE self
|
-- @param #DESIGNATE self
|
||||||
-- @param #number MaximumMarkings Maximum markings FACs will do, per designated target group.
|
-- @param #number MaximumMarkings Maximum markings FACs will do, per designated target group.
|
||||||
-- @return #DESIGNATE
|
-- @return #DESIGNATE
|
||||||
@@ -911,8 +912,8 @@ do -- DESIGNATE
|
|||||||
for DesignateIndex, Designating in pairs( self.Designating ) do
|
for DesignateIndex, Designating in pairs( self.Designating ) do
|
||||||
local DetectedItem = DetectedItems[DesignateIndex]
|
local DetectedItem = DetectedItems[DesignateIndex]
|
||||||
if DetectedItem then
|
if DetectedItem then
|
||||||
local Report = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup ):Text( ", " )
|
local Report = self.Detection:DetectedItemReportSummary( DetectedItem, AttackGroup, nil, true ):Text( ", " )
|
||||||
DetectedReport:Add( string.rep( "-", 140 ) )
|
DetectedReport:Add( string.rep( "-", 40 ) )
|
||||||
DetectedReport:Add( " - " .. Report )
|
DetectedReport:Add( " - " .. Report )
|
||||||
if string.find( Designating, "L" ) then
|
if string.find( Designating, "L" ) then
|
||||||
DetectedReport:Add( " - " .. "Lasing Targets" )
|
DetectedReport:Add( " - " .. "Lasing Targets" )
|
||||||
@@ -1192,8 +1193,8 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
local MarkingCount = 0
|
local MarkingCount = 0
|
||||||
local MarkedTypes = {}
|
local MarkedTypes = {}
|
||||||
local ReportTypes = REPORT:New()
|
--local ReportTypes = REPORT:New()
|
||||||
local ReportLaserCodes = REPORT:New()
|
--local ReportLaserCodes = REPORT:New()
|
||||||
|
|
||||||
TargetSetUnit:Flush( self )
|
TargetSetUnit:Flush( self )
|
||||||
|
|
||||||
@@ -1243,7 +1244,7 @@ do -- DESIGNATE
|
|||||||
if not Recce then
|
if not Recce then
|
||||||
|
|
||||||
self:F( "Lasing..." )
|
self:F( "Lasing..." )
|
||||||
self.RecceSet:Flush( self)
|
--self.RecceSet:Flush( self)
|
||||||
|
|
||||||
for RecceGroupID, RecceGroup in pairs( self.RecceSet:GetSet() ) do
|
for RecceGroupID, RecceGroup in pairs( self.RecceSet:GetSet() ) do
|
||||||
for UnitID, UnitData in pairs( RecceGroup:GetUnits() or {} ) do
|
for UnitID, UnitData in pairs( RecceGroup:GetUnits() or {} ) do
|
||||||
@@ -1282,13 +1283,13 @@ do -- DESIGNATE
|
|||||||
-- OK. We have assigned for the Recce a TargetUnit. We can exit the function.
|
-- OK. We have assigned for the Recce a TargetUnit. We can exit the function.
|
||||||
MarkingCount = MarkingCount + 1
|
MarkingCount = MarkingCount + 1
|
||||||
local TargetUnitType = TargetUnit:GetTypeName()
|
local TargetUnitType = TargetUnit:GetTypeName()
|
||||||
--RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.",
|
RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.",
|
||||||
-- 5, self.AttackSet, DesignateName )
|
10, self.AttackSet, DesignateName )
|
||||||
if not MarkedTypes[TargetUnitType] then
|
if not MarkedTypes[TargetUnitType] then
|
||||||
MarkedTypes[TargetUnitType] = true
|
MarkedTypes[TargetUnitType] = true
|
||||||
ReportTypes:Add(TargetUnitType)
|
--ReportTypes:Add(TargetUnitType)
|
||||||
end
|
end
|
||||||
ReportLaserCodes:Add(RecceUnit.LaserCode)
|
--ReportLaserCodes:Add(RecceUnit.LaserCode)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -1303,16 +1304,16 @@ do -- DESIGNATE
|
|||||||
|
|
||||||
if Recce then
|
if Recce then
|
||||||
Recce:LaseOff()
|
Recce:LaseOff()
|
||||||
Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() "out of LOS. Cancelling lase!", 5, self.AttackSet, self.DesignateName )
|
Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() "out of LOS. Cancelling lase!", 10, self.AttackSet, self.DesignateName )
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
--MarkingCount = MarkingCount + 1
|
--MarkingCount = MarkingCount + 1
|
||||||
local TargetUnitType = TargetUnit:GetTypeName()
|
local TargetUnitType = TargetUnit:GetTypeName()
|
||||||
if not MarkedTypes[TargetUnitType] then
|
if not MarkedTypes[TargetUnitType] then
|
||||||
MarkedTypes[TargetUnitType] = true
|
MarkedTypes[TargetUnitType] = true
|
||||||
ReportTypes:Add(TargetUnitType)
|
--ReportTypes:Add(TargetUnitType)
|
||||||
end
|
end
|
||||||
ReportLaserCodes:Add(RecceUnit.LaserCode)
|
--ReportLaserCodes:Add(RecceUnit.LaserCode)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1322,19 +1323,19 @@ do -- DESIGNATE
|
|||||||
local TargetUnitType = TargetUnit:GetTypeName()
|
local TargetUnitType = TargetUnit:GetTypeName()
|
||||||
if not MarkedTypes[TargetUnitType] then
|
if not MarkedTypes[TargetUnitType] then
|
||||||
MarkedTypes[TargetUnitType] = true
|
MarkedTypes[TargetUnitType] = true
|
||||||
ReportTypes:Add(TargetUnitType)
|
--ReportTypes:Add(TargetUnitType)
|
||||||
end
|
end
|
||||||
ReportLaserCodes:Add(Recce.LaserCode)
|
--ReportLaserCodes:Add(Recce.LaserCode)
|
||||||
--Recce:MessageToSetGroup( self.DesignateName .. ": Marking " .. TargetUnit:GetTypeName() .. " with laser " .. Recce.LaserCode .. ".", 5, self.AttackSet )
|
Recce:MessageToSetGroup( self.DesignateName .. ": Marking " .. TargetUnit:GetTypeName() .. " with laser " .. Recce.LaserCode .. ".", 10, self.AttackSet )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
local MarkedTypesText = ReportTypes:Text(', ')
|
--local MarkedTypesText = ReportTypes:Text(', ')
|
||||||
local MarkedLaserCodesText = ReportLaserCodes:Text(', ')
|
--local MarkedLaserCodesText = ReportLaserCodes:Text(', ')
|
||||||
self.CC:GetPositionable():MessageToSetGroup( "Marking " .. MarkingCount .. " x " .. MarkedTypesText .. ", code " .. MarkedLaserCodesText .. ".", 5, self.AttackSet, self.DesignateName )
|
--self.CC:GetPositionable():MessageToSetGroup( "Marking " .. MarkingCount .. " x " .. MarkedTypesText .. ", code " .. MarkedLaserCodesText .. ".", 5, self.AttackSet, self.DesignateName )
|
||||||
|
|
||||||
self:__Lasing( -self.LaseDuration, Index, Duration, LaserCodeRequested )
|
self:__Lasing( -self.LaseDuration, Index, Duration, LaserCodeRequested )
|
||||||
|
|
||||||
|
|||||||
@@ -653,131 +653,132 @@ do -- DETECTION_BASE
|
|||||||
-- self:T2( { TargetIsDetected = TargetIsDetected, TargetIsVisible = TargetIsVisible, TargetLastTime = TargetLastTime, TargetKnowType = TargetKnowType, TargetKnowDistance = TargetKnowDistance, TargetLastPos = TargetLastPos, TargetLastVelocity = TargetLastVelocity } )
|
-- self:T2( { TargetIsDetected = TargetIsDetected, TargetIsVisible = TargetIsVisible, TargetLastTime = TargetLastTime, TargetKnowType = TargetKnowType, TargetKnowDistance = TargetKnowDistance, TargetLastPos = TargetLastPos, TargetLastVelocity = TargetLastVelocity } )
|
||||||
|
|
||||||
-- Only process if the target is visible. Detection also returns invisible units.
|
-- Only process if the target is visible. Detection also returns invisible units.
|
||||||
-- if Detection.visible == true then
|
--if Detection.visible == true then
|
||||||
|
|
||||||
local DetectionAccepted = true
|
local DetectionAccepted = true
|
||||||
|
|
||||||
local DetectedObjectName = DetectedObject:getName()
|
local DetectedObjectName = DetectedObject:getName()
|
||||||
local DetectedObjectType = DetectedObject:getTypeName()
|
local DetectedObjectType = DetectedObject:getTypeName()
|
||||||
|
|
||||||
local DetectedObjectVec3 = DetectedObject:getPoint()
|
local DetectedObjectVec3 = DetectedObject:getPoint()
|
||||||
local DetectedObjectVec2 = { x = DetectedObjectVec3.x, y = DetectedObjectVec3.z }
|
local DetectedObjectVec2 = { x = DetectedObjectVec3.x, y = DetectedObjectVec3.z }
|
||||||
local DetectionGroupVec3 = Detection:GetVec3() or {x=0,y=0,z=0}
|
local DetectionGroupVec3 = Detection:GetVec3() or {x=0,y=0,z=0}
|
||||||
local DetectionGroupVec2 = { x = DetectionGroupVec3.x, y = DetectionGroupVec3.z }
|
local DetectionGroupVec2 = { x = DetectionGroupVec3.x, y = DetectionGroupVec3.z }
|
||||||
|
|
||||||
local Distance = ((DetectedObjectVec3.x - DetectionGroupVec3.x) ^ 2 +
|
local Distance = ( ( DetectedObjectVec3.x - DetectionGroupVec3.x )^2 +
|
||||||
(DetectedObjectVec3.y - DetectionGroupVec3.y) ^ 2 +
|
( DetectedObjectVec3.y - DetectionGroupVec3.y )^2 +
|
||||||
(DetectedObjectVec3.z - DetectionGroupVec3.z) ^ 2) ^ 0.5 / 1000
|
( DetectedObjectVec3.z - DetectionGroupVec3.z )^2
|
||||||
|
) ^ 0.5 / 1000
|
||||||
|
|
||||||
local DetectedUnitCategory = DetectedObject:getDesc().category
|
local DetectedUnitCategory = DetectedObject:getDesc().category
|
||||||
|
|
||||||
-- self:F( { "Detected Target:", DetectionGroupName, DetectedObjectName, DetectedObjectType, Distance, DetectedUnitCategory } )
|
--self:F( { "Detected Target:", DetectionGroupName, DetectedObjectName, DetectedObjectType, Distance, DetectedUnitCategory } )
|
||||||
|
|
||||||
-- Calculate Acceptance
|
-- Calculate Acceptance
|
||||||
|
|
||||||
DetectionAccepted = self._.FilterCategories[DetectedUnitCategory] ~= nil and DetectionAccepted or false
|
DetectionAccepted = self._.FilterCategories[DetectedUnitCategory] ~= nil and DetectionAccepted or false
|
||||||
|
|
||||||
-- if Distance > 15000 then
|
-- if Distance > 15000 then
|
||||||
-- if DetectedUnitCategory == Unit.Category.GROUND_UNIT or DetectedUnitCategory == Unit.Category.SHIP then
|
-- if DetectedUnitCategory == Unit.Category.GROUND_UNIT or DetectedUnitCategory == Unit.Category.SHIP then
|
||||||
-- if DetectedObject:hasSensors( Unit.SensorType.RADAR, Unit.RadarType.AS ) == false then
|
-- if DetectedObject:hasSensors( Unit.SensorType.RADAR, Unit.RadarType.AS ) == false then
|
||||||
-- DetectionAccepted = false
|
-- DetectionAccepted = false
|
||||||
-- end
|
-- end
|
||||||
-- end
|
-- end
|
||||||
-- end
|
-- end
|
||||||
|
|
||||||
if self.AcceptRange and Distance * 1000 > self.AcceptRange then
|
if self.AcceptRange and Distance * 1000 > self.AcceptRange then
|
||||||
DetectionAccepted = false
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.AcceptZones then
|
|
||||||
local AnyZoneDetection = false
|
|
||||||
for AcceptZoneID, AcceptZone in pairs( self.AcceptZones ) do
|
|
||||||
local AcceptZone = AcceptZone -- Core.Zone#ZONE_BASE
|
|
||||||
if AcceptZone:IsVec2InZone( DetectedObjectVec2 ) then
|
|
||||||
AnyZoneDetection = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not AnyZoneDetection then
|
|
||||||
DetectionAccepted = false
|
DetectionAccepted = false
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if self.RejectZones then
|
if self.AcceptZones then
|
||||||
for RejectZoneID, RejectZone in pairs( self.RejectZones ) do
|
local AnyZoneDetection = false
|
||||||
local RejectZone = RejectZone -- Core.Zone#ZONE_BASE
|
for AcceptZoneID, AcceptZone in pairs( self.AcceptZones ) do
|
||||||
if RejectZone:IsVec2InZone( DetectedObjectVec2 ) == true then
|
local AcceptZone = AcceptZone -- Core.Zone#ZONE_BASE
|
||||||
|
if AcceptZone:IsVec2InZone( DetectedObjectVec2 ) then
|
||||||
|
AnyZoneDetection = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not AnyZoneDetection then
|
||||||
DetectionAccepted = false
|
DetectionAccepted = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- Calculate additional probabilities
|
if self.RejectZones then
|
||||||
|
for RejectZoneID, RejectZone in pairs( self.RejectZones ) do
|
||||||
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.DistanceProbability then
|
local RejectZone = RejectZone -- Core.Zone#ZONE_BASE
|
||||||
local DistanceFactor = Distance / 4
|
if RejectZone:IsVec2InZone( DetectedObjectVec2 ) == true then
|
||||||
local DistanceProbabilityReversed = (1 - self.DistanceProbability) * DistanceFactor
|
|
||||||
local DistanceProbability = 1 - DistanceProbabilityReversed
|
|
||||||
DistanceProbability = DistanceProbability * 30 / 300
|
|
||||||
local Probability = math.random() -- Selects a number between 0 and 1
|
|
||||||
-- self:T( { Probability, DistanceProbability } )
|
|
||||||
if Probability > DistanceProbability then
|
|
||||||
DetectionAccepted = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.AlphaAngleProbability then
|
|
||||||
local NormalVec2 = { x = DetectedObjectVec2.x - DetectionGroupVec2.x, y = DetectedObjectVec2.y - DetectionGroupVec2.y }
|
|
||||||
local AlphaAngle = math.atan2( NormalVec2.y, NormalVec2.x )
|
|
||||||
local Sinus = math.sin( AlphaAngle )
|
|
||||||
local AlphaAngleProbabilityReversed = (1 - self.AlphaAngleProbability) * (1 - Sinus)
|
|
||||||
local AlphaAngleProbability = 1 - AlphaAngleProbabilityReversed
|
|
||||||
|
|
||||||
AlphaAngleProbability = AlphaAngleProbability * 30 / 300
|
|
||||||
|
|
||||||
local Probability = math.random() -- Selects a number between 0 and 1
|
|
||||||
-- self:T( { Probability, AlphaAngleProbability } )
|
|
||||||
if Probability > AlphaAngleProbability then
|
|
||||||
DetectionAccepted = false
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.ZoneProbability then
|
|
||||||
|
|
||||||
for ZoneDataID, ZoneData in pairs( self.ZoneProbability ) do
|
|
||||||
self:F( { ZoneData } )
|
|
||||||
local ZoneObject = ZoneData[1] -- Core.Zone#ZONE_BASE
|
|
||||||
local ZoneProbability = ZoneData[2] -- #number
|
|
||||||
ZoneProbability = ZoneProbability * 30 / 300
|
|
||||||
|
|
||||||
if ZoneObject:IsVec2InZone( DetectedObjectVec2 ) == true then
|
|
||||||
local Probability = math.random() -- Selects a number between 0 and 1
|
|
||||||
-- self:T( { Probability, ZoneProbability } )
|
|
||||||
if Probability > ZoneProbability then
|
|
||||||
DetectionAccepted = false
|
DetectionAccepted = false
|
||||||
break
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if DetectionAccepted then
|
-- Calculate additional probabilities
|
||||||
|
|
||||||
HasDetectedObjects = true
|
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.DistanceProbability then
|
||||||
|
local DistanceFactor = Distance / 4
|
||||||
self.DetectedObjects[DetectedObjectName] = self.DetectedObjects[DetectedObjectName] or {}
|
local DistanceProbabilityReversed = ( 1 - self.DistanceProbability ) * DistanceFactor
|
||||||
self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName
|
local DistanceProbability = 1 - DistanceProbabilityReversed
|
||||||
|
DistanceProbability = DistanceProbability * 30 / 300
|
||||||
if TargetIsDetected and TargetIsDetected == true then
|
local Probability = math.random() -- Selects a number between 0 and 1
|
||||||
self.DetectedObjects[DetectedObjectName].IsDetected = TargetIsDetected
|
--self:T( { Probability, DistanceProbability } )
|
||||||
|
if Probability > DistanceProbability then
|
||||||
|
DetectionAccepted = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if TargetIsDetected and TargetIsVisible and TargetIsVisible == true then
|
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.AlphaAngleProbability then
|
||||||
self.DetectedObjects[DetectedObjectName].IsVisible = TargetIsDetected and TargetIsVisible
|
local NormalVec2 = { x = DetectedObjectVec2.x - DetectionGroupVec2.x, y = DetectedObjectVec2.y - DetectionGroupVec2.y }
|
||||||
|
local AlphaAngle = math.atan2( NormalVec2.y, NormalVec2.x )
|
||||||
|
local Sinus = math.sin( AlphaAngle )
|
||||||
|
local AlphaAngleProbabilityReversed = ( 1 - self.AlphaAngleProbability ) * ( 1 - Sinus )
|
||||||
|
local AlphaAngleProbability = 1 - AlphaAngleProbabilityReversed
|
||||||
|
|
||||||
|
AlphaAngleProbability = AlphaAngleProbability * 30 / 300
|
||||||
|
|
||||||
|
local Probability = math.random() -- Selects a number between 0 and 1
|
||||||
|
--self:T( { Probability, AlphaAngleProbability } )
|
||||||
|
if Probability > AlphaAngleProbability then
|
||||||
|
DetectionAccepted = false
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if TargetIsDetected and not self.DetectedObjects[DetectedObjectName].KnowType then
|
if not self.DetectedObjects[DetectedObjectName] and TargetIsVisible and self.ZoneProbability then
|
||||||
self.DetectedObjects[DetectedObjectName].KnowType = TargetIsDetected and TargetKnowType
|
|
||||||
|
for ZoneDataID, ZoneData in pairs( self.ZoneProbability ) do
|
||||||
|
self:F({ZoneData})
|
||||||
|
local ZoneObject = ZoneData[1] -- Core.Zone#ZONE_BASE
|
||||||
|
local ZoneProbability = ZoneData[2] -- #number
|
||||||
|
ZoneProbability = ZoneProbability * 30 / 300
|
||||||
|
|
||||||
|
if ZoneObject:IsVec2InZone( DetectedObjectVec2 ) == true then
|
||||||
|
local Probability = math.random() -- Selects a number between 0 and 1
|
||||||
|
--self:T( { Probability, ZoneProbability } )
|
||||||
|
if Probability > ZoneProbability then
|
||||||
|
DetectionAccepted = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if DetectionAccepted then
|
||||||
|
|
||||||
|
HasDetectedObjects = true
|
||||||
|
|
||||||
|
self.DetectedObjects[DetectedObjectName] = self.DetectedObjects[DetectedObjectName] or {}
|
||||||
|
self.DetectedObjects[DetectedObjectName].Name = DetectedObjectName
|
||||||
|
|
||||||
|
if TargetIsDetected and TargetIsDetected == true then
|
||||||
|
self.DetectedObjects[DetectedObjectName].IsDetected = TargetIsDetected
|
||||||
|
end
|
||||||
|
|
||||||
|
if TargetIsDetected and TargetIsVisible and TargetIsVisible == true then
|
||||||
|
self.DetectedObjects[DetectedObjectName].IsVisible = TargetIsDetected and TargetIsVisible
|
||||||
|
end
|
||||||
|
|
||||||
|
if TargetIsDetected and not self.DetectedObjects[DetectedObjectName].KnowType then
|
||||||
|
self.DetectedObjects[DetectedObjectName].KnowType = TargetIsDetected and TargetKnowType
|
||||||
end
|
end
|
||||||
self.DetectedObjects[DetectedObjectName].KnowDistance = TargetKnowDistance -- Detection.distance -- TargetKnowDistance
|
self.DetectedObjects[DetectedObjectName].KnowDistance = TargetKnowDistance -- Detection.distance -- TargetKnowDistance
|
||||||
self.DetectedObjects[DetectedObjectName].LastTime = (TargetIsDetected and TargetIsVisible == false) and TargetLastTime
|
self.DetectedObjects[DetectedObjectName].LastTime = (TargetIsDetected and TargetIsVisible == false) and TargetLastTime
|
||||||
@@ -2151,8 +2152,9 @@ do -- DETECTION_UNITS
|
|||||||
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
-- @param #DETECTION_BASE.DetectedItem DetectedItem The DetectedItem.
|
||||||
-- @param Wrapper.Group#GROUP AttackGroup The group to generate the report for.
|
-- @param Wrapper.Group#GROUP AttackGroup The group to generate the report for.
|
||||||
-- @param Core.Settings#SETTINGS Settings Message formatting settings to use.
|
-- @param Core.Settings#SETTINGS Settings Message formatting settings to use.
|
||||||
|
-- @param #boolean ForceA2GCoordinate Set creation of A2G coordinate
|
||||||
-- @return Core.Report#REPORT The report of the detection items.
|
-- @return Core.Report#REPORT The report of the detection items.
|
||||||
function DETECTION_UNITS:DetectedItemReportSummary( DetectedItem, AttackGroup, Settings )
|
function DETECTION_UNITS:DetectedItemReportSummary( DetectedItem, AttackGroup, Settings, ForceA2GCoordinate )
|
||||||
self:F( { DetectedItem = DetectedItem } )
|
self:F( { DetectedItem = DetectedItem } )
|
||||||
|
|
||||||
local DetectedItemID = self:GetDetectedItemID( DetectedItem )
|
local DetectedItemID = self:GetDetectedItemID( DetectedItem )
|
||||||
@@ -2188,6 +2190,10 @@ do -- DETECTION_UNITS
|
|||||||
local DetectedItemCoordinate = self:GetDetectedItemCoordinate( DetectedItem )
|
local DetectedItemCoordinate = self:GetDetectedItemCoordinate( DetectedItem )
|
||||||
local DetectedItemCoordText = DetectedItemCoordinate:ToString( AttackGroup, Settings )
|
local DetectedItemCoordText = DetectedItemCoordinate:ToString( AttackGroup, Settings )
|
||||||
|
|
||||||
|
if ForceA2GCoordinate then
|
||||||
|
DetectedItemCoordText = DetectedItemCoordinate:ToStringA2G(AttackGroup,Settings)
|
||||||
|
end
|
||||||
|
|
||||||
local ThreatLevelA2G = self:GetDetectedItemThreatLevel( DetectedItem )
|
local ThreatLevelA2G = self:GetDetectedItemThreatLevel( DetectedItem )
|
||||||
|
|
||||||
local Report = REPORT:New()
|
local Report = REPORT:New()
|
||||||
@@ -2440,7 +2446,7 @@ do -- DETECTION_AREAS
|
|||||||
--
|
--
|
||||||
-- ## 4.1) Retrieve the Detected Unit Sets and Detected Zones
|
-- ## 4.1) Retrieve the Detected Unit Sets and Detected Zones
|
||||||
--
|
--
|
||||||
-- The methods to manage the DetectedItems[].Set(s) are implemented in @{Functional.Detection#DETECTION_BASE} and
|
-- The methods to manage the DetectedItems[].Set(s) are implemented in @{Functional.Detection#DECTECTION_BASE} and
|
||||||
-- the methods to manage the DetectedItems[].Zone(s) are implemented in @{Functional.Detection#DETECTION_AREAS}.
|
-- the methods to manage the DetectedItems[].Zone(s) are implemented in @{Functional.Detection#DETECTION_AREAS}.
|
||||||
--
|
--
|
||||||
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
|
-- Retrieve the DetectedItems[].Set with the method @{Functional.Detection#DETECTION_BASE.GetDetectedSet}(). A @{Core.Set#SET_UNIT} object will be returned.
|
||||||
|
|||||||
@@ -792,7 +792,7 @@ function FOX:onafterMissileLaunch(From, Event, To, missile)
|
|||||||
local text=string.format("Missile launch detected! Distance %.1f NM, bearing %03d°.", UTILS.MetersToNM(distance), bearing)
|
local text=string.format("Missile launch detected! Distance %.1f NM, bearing %03d°.", UTILS.MetersToNM(distance), bearing)
|
||||||
|
|
||||||
-- Say notching headings.
|
-- Say notching headings.
|
||||||
BASE:ScheduleOnce(5, FOX._SayNotchingHeadings, self, player, missile.weapon)
|
self:ScheduleOnce(5, FOX._SayNotchingHeadings, self, player, missile.weapon)
|
||||||
|
|
||||||
--TODO: ALERT or INFO depending on whether this is a direct target.
|
--TODO: ALERT or INFO depending on whether this is a direct target.
|
||||||
--TODO: lauchalertall option.
|
--TODO: lauchalertall option.
|
||||||
@@ -1114,6 +1114,13 @@ end
|
|||||||
-- Event Functions
|
-- Event Functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- FOX event handler for event birth.
|
||||||
|
-- @param #FOX self
|
||||||
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
|
function FOX:OnEventPlayerEnterAircraft(EventData)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- FOX event handler for event birth.
|
--- FOX event handler for event birth.
|
||||||
-- @param #FOX self
|
-- @param #FOX self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
@@ -1155,7 +1162,7 @@ function FOX:OnEventBirth(EventData)
|
|||||||
|
|
||||||
-- Add F10 radio menu for player.
|
-- Add F10 radio menu for player.
|
||||||
if not self.menudisabled then
|
if not self.menudisabled then
|
||||||
SCHEDULER:New(nil, self._AddF10Commands, {self,_unitName}, 0.1)
|
self:ScheduleOnce(0.1, FOX._AddF10Commands, self, _unitname)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Player data.
|
-- Player data.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
|||||||
-- ## Features:
|
-- ## Features:
|
||||||
--
|
--
|
||||||
-- * Track the missiles fired at you and other players, providing bearing and range information of the missiles towards the airplanes.
|
-- * Track the missiles fired at you and other players, providing bearing and range information of the missiles towards the airplanes.
|
||||||
-- * Provide alerts of missile launches, including detailed information of the units launching, including bearing, range °
|
-- * Provide alerts of missile launches, including detailed information of the units launching, including bearing, range
|
||||||
-- * Provide alerts when a missile would have killed your aircraft.
|
-- * Provide alerts when a missile would have killed your aircraft.
|
||||||
-- * Provide alerts when the missile self destructs.
|
-- * Provide alerts when the missile self destructs.
|
||||||
-- * Enable / Disable and Configure the Missile Trainer using the various menu options.
|
-- * Enable / Disable and Configure the Missile Trainer using the various menu options.
|
||||||
|
|||||||
@@ -1044,6 +1044,3 @@ function PSEUDOATC:_myname(unitname)
|
|||||||
|
|
||||||
return string.format("%s (%s)", csign, pname)
|
return string.format("%s (%s)", csign, pname)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2049,9 +2049,15 @@ function RAT:_InitAircraft(DCSgroup)
|
|||||||
--self.aircraft.descriptors=DCSdesc
|
--self.aircraft.descriptors=DCSdesc
|
||||||
|
|
||||||
-- aircraft dimensions
|
-- aircraft dimensions
|
||||||
self.aircraft.length=DCSdesc.box.max.x
|
if DCSdesc.box then
|
||||||
self.aircraft.height=DCSdesc.box.max.y
|
self.aircraft.length=DCSdesc.box.max.x
|
||||||
self.aircraft.width=DCSdesc.box.max.z
|
self.aircraft.height=DCSdesc.box.max.y
|
||||||
|
self.aircraft.width=DCSdesc.box.max.z
|
||||||
|
elseif DCStype == "Mirage-F1CE" then
|
||||||
|
self.aircraft.length=16
|
||||||
|
self.aircraft.height=5
|
||||||
|
self.aircraft.width=9
|
||||||
|
end
|
||||||
self.aircraft.box=math.max(self.aircraft.length,self.aircraft.width)
|
self.aircraft.box=math.max(self.aircraft.length,self.aircraft.width)
|
||||||
|
|
||||||
-- info message
|
-- info message
|
||||||
@@ -5371,7 +5377,7 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take
|
|||||||
|
|
||||||
if spawnonground then
|
if spawnonground then
|
||||||
|
|
||||||
-- Sh°ps and FARPS seem to have a build in queue.
|
-- Ships and FARPS seem to have a build in queue.
|
||||||
if spawnonship or spawnonfarp or spawnonrunway or automatic then
|
if spawnonship or spawnonfarp or spawnonrunway or automatic then
|
||||||
self:T(RAT.id..string.format("RAT group %s spawning at farp, ship or runway %s.", self.alias, departure:GetName()))
|
self:T(RAT.id..string.format("RAT group %s spawning at farp, ship or runway %s.", self.alias, departure:GetName()))
|
||||||
|
|
||||||
@@ -6145,4 +6151,3 @@ function RATMANAGER:_RollDice(nrat,ntot,min,alive)
|
|||||||
-- Return number of groups to be spawned.
|
-- Return number of groups to be spawned.
|
||||||
return N
|
return N
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
|
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
|
||||||
--
|
--
|
||||||
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536), [Ciribob](https://forums.eagle.ru/member.php?u=112175)
|
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536), [Ciribob](https://forums.eagle.ru/member.php?u=112175)
|
||||||
|
-- ### SRS Additions: Applevangelist
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
-- @module Functional.Range
|
-- @module Functional.Range
|
||||||
@@ -101,6 +102,10 @@
|
|||||||
-- @field #boolean targetsheet If true, players can save their target sheets. Rangeboss will not work if targetsheets do not save.
|
-- @field #boolean targetsheet If true, players can save their target sheets. Rangeboss will not work if targetsheets do not save.
|
||||||
-- @field #string targetpath Path where to save the target sheets.
|
-- @field #string targetpath Path where to save the target sheets.
|
||||||
-- @field #string targetprefix File prefix for target sheet files.
|
-- @field #string targetprefix File prefix for target sheet files.
|
||||||
|
-- @field Sound.SRS#MSRS controlmsrs
|
||||||
|
-- @field Sound.SRS#MSRSQUEUE controlsrsQ
|
||||||
|
-- @field Sound.SRS#MSRS instructmsrs
|
||||||
|
-- @field Sound.SRS#MSRSQUEUE instructsrsQ
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *Don't only practice your art, but force your way into its secrets; art deserves that, for it and knowledge can raise man to the Divine.* - Ludwig van Beethoven
|
--- *Don't only practice your art, but force your way into its secrets; art deserves that, for it and knowledge can raise man to the Divine.* - Ludwig van Beethoven
|
||||||
@@ -225,6 +230,11 @@
|
|||||||
--
|
--
|
||||||
-- By default, the sound files are placed in the "Range Soundfiles/" folder inside the mission (.miz) file. Another folder can be specified via the @{#RANGE.SetSoundfilesPath}(*path*) function.
|
-- By default, the sound files are placed in the "Range Soundfiles/" folder inside the mission (.miz) file. Another folder can be specified via the @{#RANGE.SetSoundfilesPath}(*path*) function.
|
||||||
--
|
--
|
||||||
|
-- ## Voice output via SRS
|
||||||
|
--
|
||||||
|
-- Alternatively, the voice output can be fully done via SRS, **no sound file additions needed**. Set up SRS with @{#RANGE.SetSRS}(). Range control and instructor frequencies and voices can then be
|
||||||
|
-- set via @{#RANGE.SetSRSRangeControl}() and @{#RANGE.SetSRSRangeInstructor}()
|
||||||
|
--
|
||||||
-- # Persistence
|
-- # Persistence
|
||||||
--
|
--
|
||||||
-- To automatically save bombing results to disk, use the @{#RANGE.SetAutosave}() function. Bombing results will be saved as csv file in your "Saved Games\DCS.openbeta\Logs" directory.
|
-- To automatically save bombing results to disk, use the @{#RANGE.SetAutosave}() function. Bombing results will be saved as csv file in your "Saved Games\DCS.openbeta\Logs" directory.
|
||||||
@@ -429,6 +439,25 @@ RANGE.TargetType = {
|
|||||||
-- @field #string airframe Aircraft type of player.
|
-- @field #string airframe Aircraft type of player.
|
||||||
-- @field #number time Time via timer.getAbsTime() in seconds of impact.
|
-- @field #number time Time via timer.getAbsTime() in seconds of impact.
|
||||||
-- @field #string date OS date.
|
-- @field #string date OS date.
|
||||||
|
-- @field #number attackHdg Attack heading in degrees.
|
||||||
|
-- @field #number attackVel Attack velocity in knots.
|
||||||
|
-- @field #number attackAlt Attack altitude in feet.
|
||||||
|
-- @field #string clock Time of the run.
|
||||||
|
-- @field #string rangename Name of the range.
|
||||||
|
|
||||||
|
--- Strafe result.
|
||||||
|
-- @type RANGE.StrafeResult
|
||||||
|
-- @field #string player Player name.
|
||||||
|
-- @field #string airframe Aircraft type of player.
|
||||||
|
-- @field #number time Time via timer.getAbsTime() in seconds of impact.
|
||||||
|
-- @field #string date OS date.
|
||||||
|
-- @field #string name Name of the target pit.
|
||||||
|
-- @field #number roundsFired Number of rounds fired.
|
||||||
|
-- @field #number roundsHit Number of rounds that hit the target.
|
||||||
|
-- @field #number strafeAccuracy Accuracy of the run in percent.
|
||||||
|
-- @field #string clock Time of the run.
|
||||||
|
-- @field #string rangename Name of the range.
|
||||||
|
-- @field #boolean invalid Invalid pass.
|
||||||
|
|
||||||
--- Strafe result.
|
--- Strafe result.
|
||||||
-- @type RANGE.StrafeResult
|
-- @type RANGE.StrafeResult
|
||||||
@@ -549,7 +578,7 @@ RANGE.MenuF10Root = nil
|
|||||||
|
|
||||||
--- Range script version.
|
--- Range script version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
RANGE.version = "2.4.0"
|
RANGE.version = "2.5.0"
|
||||||
|
|
||||||
-- TODO list:
|
-- TODO list:
|
||||||
-- TODO: Verbosity level for messages.
|
-- TODO: Verbosity level for messages.
|
||||||
@@ -569,17 +598,16 @@ RANGE.version = "2.4.0"
|
|||||||
|
|
||||||
--- RANGE contructor. Creates a new RANGE object.
|
--- RANGE contructor. Creates a new RANGE object.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #string rangename Name of the range. Has to be unique. Will we used to create F10 menu items etc.
|
-- @param #string RangeName Name of the range. Has to be unique. Will we used to create F10 menu items etc.
|
||||||
-- @return #RANGE RANGE object.
|
-- @return #RANGE RANGE object.
|
||||||
function RANGE:New( rangename )
|
function RANGE:New( RangeName )
|
||||||
BASE:F( { rangename = rangename } )
|
|
||||||
|
|
||||||
-- Inherit BASE.
|
-- Inherit BASE.
|
||||||
local self = BASE:Inherit( self, FSM:New() ) -- #RANGE
|
local self = BASE:Inherit( self, FSM:New() ) -- #RANGE
|
||||||
|
|
||||||
-- Get range name.
|
-- Get range name.
|
||||||
-- TODO: make sure that the range name is not given twice. This would lead to problems in the F10 radio menu.
|
-- TODO: make sure that the range name is not given twice. This would lead to problems in the F10 radio menu.
|
||||||
self.rangename = rangename or "Practice Range"
|
self.rangename = RangeName or "Practice Range"
|
||||||
|
|
||||||
-- Log id.
|
-- Log id.
|
||||||
self.id = string.format( "RANGE %s | ", self.rangename )
|
self.id = string.format( "RANGE %s | ", self.rangename )
|
||||||
@@ -815,7 +843,7 @@ function RANGE:onafterStart()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Init range control.
|
-- Init range control.
|
||||||
if self.rangecontrolfreq then
|
if self.rangecontrolfreq and not self.useSRS then
|
||||||
|
|
||||||
-- Radio queue.
|
-- Radio queue.
|
||||||
self.rangecontrol = RADIOQUEUE:New( self.rangecontrolfreq, nil, self.rangename )
|
self.rangecontrol = RADIOQUEUE:New( self.rangecontrolfreq, nil, self.rangename )
|
||||||
@@ -841,7 +869,7 @@ function RANGE:onafterStart()
|
|||||||
self.rangecontrol:Start( 1, 0.1 )
|
self.rangecontrol:Start( 1, 0.1 )
|
||||||
|
|
||||||
-- Init range control.
|
-- Init range control.
|
||||||
if self.instructorfreq then
|
if self.instructorfreq and not self.useSRS then
|
||||||
|
|
||||||
-- Radio queue.
|
-- Radio queue.
|
||||||
self.instructor = RADIOQUEUE:New( self.instructorfreq, nil, self.rangename )
|
self.instructor = RADIOQUEUE:New( self.instructorfreq, nil, self.rangename )
|
||||||
@@ -950,6 +978,19 @@ function RANGE:SetTargetSheet( path, prefix )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Set FunkMan socket. Bombing and strafing results will be send to your Discord bot.
|
||||||
|
-- **Requires running FunkMan program**.
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #number Port Port. Default `10042`.
|
||||||
|
-- @param #string Host Host. Default "127.0.0.1".
|
||||||
|
-- @return #RANGE self
|
||||||
|
function RANGE:SetFunkManOn(Port, Host)
|
||||||
|
|
||||||
|
self.funkmanSocket=SOCKET:New(Port, Host)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set messages to examiner. The examiner will receive messages from all clients.
|
--- Set messages to examiner. The examiner will receive messages from all clients.
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #string examinergroupname Name of the group of the examiner.
|
-- @param #string examinergroupname Name of the group of the examiner.
|
||||||
@@ -1146,7 +1187,91 @@ function RANGE:TrackMissilesOFF()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Enable range control and set frequency.
|
--- Use SRS Simple-Text-To-Speech for transmissions. No sound files necessary.
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #string PathToSRS Path to SRS directory.
|
||||||
|
-- @param #number Port SRS port. Default 5002.
|
||||||
|
-- @param #number Coalition Coalition side, e.g. coalition.side.BLUE or coalition.side.RED
|
||||||
|
-- @param #number Frequency Frequency to use, defaults to 256 (same as rangecontrol)
|
||||||
|
-- @param #number Modulation Modulation to use, defaults to radio.modulation.AM
|
||||||
|
-- @param #number Volume Volume, between 0.0 and 1.0. Defaults to 1.0
|
||||||
|
-- @param #string PathToGoogleKey Path to Google TTS credentials.
|
||||||
|
-- @return #RANGE self
|
||||||
|
function RANGE:SetSRS(PathToSRS, Port, Coalition, Frequency, Modulation, Volume, PathToGoogleKey)
|
||||||
|
if PathToSRS then
|
||||||
|
|
||||||
|
self.useSRS=true
|
||||||
|
|
||||||
|
self.controlmsrs=MSRS:New(PathToSRS, Frequency or 256, Modulation or radio.modulation.AM, Volume or 1.0)
|
||||||
|
self.controlmsrs:SetPort(Port)
|
||||||
|
self.controlmsrs:SetCoalition(Coalition or coalition.side.BLUE)
|
||||||
|
self.controlmsrs:SetLabel("RANGEC")
|
||||||
|
self.controlsrsQ = MSRSQUEUE:New("CONTROL")
|
||||||
|
|
||||||
|
self.instructmsrs=MSRS:New(PathToSRS, Frequency or 305, Modulation or radio.modulation.AM, Volume or 1.0)
|
||||||
|
self.instructmsrs:SetPort(Port)
|
||||||
|
self.instructmsrs:SetCoalition(Coalition or coalition.side.BLUE)
|
||||||
|
self.instructmsrs:SetLabel("RANGEI")
|
||||||
|
self.instructsrsQ = MSRSQUEUE:New("INSTRUCT")
|
||||||
|
|
||||||
|
else
|
||||||
|
self:E(self.lid..string.format("ERROR: No SRS path specified!"))
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (SRS) Set range control frequency and voice.
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #number frequency Frequency in MHz. Default 256 MHz.
|
||||||
|
-- @param #number modulation Modulation, defaults to radio.modulation.AM.
|
||||||
|
-- @param #string voice Voice.
|
||||||
|
-- @param #string culture Culture, defaults to "en-US".
|
||||||
|
-- @param #string gender Gender, defaults to "female".
|
||||||
|
-- @param #string relayunitname Name of the unit used for transmission location.
|
||||||
|
-- @return #RANGE self
|
||||||
|
function RANGE:SetSRSRangeControl( frequency, modulation, voice, culture, gender, relayunitname )
|
||||||
|
self.rangecontrolfreq = frequency or 256
|
||||||
|
self.controlmsrs:SetFrequencies(self.rangecontrolfreq)
|
||||||
|
self.controlmsrs:SetModulations(modulation or radio.modulation.AM)
|
||||||
|
self.controlmsrs:SetVoice(voice)
|
||||||
|
self.controlmsrs:SetCulture(culture or "en-US")
|
||||||
|
self.controlmsrs:SetGender(gender or "female")
|
||||||
|
self.rangecontrol = true
|
||||||
|
if relayunitname then
|
||||||
|
local unit = UNIT:FindByName(relayunitname)
|
||||||
|
local Coordinate = unit:GetCoordinate()
|
||||||
|
self.rangecontrolrelayname = relayunitname
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (SRS) Set range instructor frequency and voice.
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #number frequency Frequency in MHz. Default 305 MHz.
|
||||||
|
-- @param #number modulation Modulation, defaults to radio.modulation.AM.
|
||||||
|
-- @param #string voice Voice.
|
||||||
|
-- @param #string culture Culture, defaults to "en-US".
|
||||||
|
-- @param #string gender Gender, defaults to "male".
|
||||||
|
-- @param #string relayunitname Name of the unit used for transmission location.
|
||||||
|
-- @return #RANGE self
|
||||||
|
function RANGE:SetSRSRangeInstructor( frequency, modulation, voice, culture, gender, relayunitname )
|
||||||
|
self.instructorfreq = frequency or 305
|
||||||
|
self.instructmsrs:SetFrequencies(self.instructorfreq)
|
||||||
|
self.instructmsrs:SetModulations(modulation or radio.modulation.AM)
|
||||||
|
self.instructmsrs:SetVoice(voice)
|
||||||
|
self.instructmsrs:SetCulture(culture or "en-US")
|
||||||
|
self.instructmsrs:SetGender(gender or "male")
|
||||||
|
self.instructor = true
|
||||||
|
if relayunitname then
|
||||||
|
local unit = UNIT:FindByName(relayunitname)
|
||||||
|
local Coordinate = unit:GetCoordinate()
|
||||||
|
self.instructmsrs:SetCoordinate(Coordinate)
|
||||||
|
self.instructorrelayname = relayunitname
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Enable range control and set frequency (non-SRS).
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number frequency Frequency in MHz. Default 256 MHz.
|
-- @param #number frequency Frequency in MHz. Default 256 MHz.
|
||||||
-- @param #string relayunitname Name of the unit used for transmission.
|
-- @param #string relayunitname Name of the unit used for transmission.
|
||||||
@@ -1157,7 +1282,7 @@ function RANGE:SetRangeControl( frequency, relayunitname )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Enable instructor radio and set frequency.
|
--- Enable instructor radio and set frequency (non-SRS).
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param #number frequency Frequency in MHz. Default 305 MHz.
|
-- @param #number frequency Frequency in MHz. Default 305 MHz.
|
||||||
-- @param #string relayunitname Name of the unit used for transmission.
|
-- @param #string relayunitname Name of the unit used for transmission.
|
||||||
@@ -1388,7 +1513,7 @@ function RANGE:AddBombingTargets( targetnames, goodhitrange, randommove )
|
|||||||
elseif _isstatic == false then
|
elseif _isstatic == false then
|
||||||
local _unit = UNIT:FindByName( name )
|
local _unit = UNIT:FindByName( name )
|
||||||
self:T2( self.id .. string.format( "Adding unit bombing target %s with hit range %d.", name, goodhitrange, randommove ) )
|
self:T2( self.id .. string.format( "Adding unit bombing target %s with hit range %d.", name, goodhitrange, randommove ) )
|
||||||
self:AddBombingTargetUnit( _unit, goodhitrange )
|
self:AddBombingTargetUnit( _unit, goodhitrange, randommove )
|
||||||
else
|
else
|
||||||
self:E( self.id .. string.format( "ERROR! Could not find bombing target %s.", name ) )
|
self:E( self.id .. string.format( "ERROR! Could not find bombing target %s.", name ) )
|
||||||
end
|
end
|
||||||
@@ -1728,7 +1853,6 @@ function RANGE:OnEventHit( EventData )
|
|||||||
self:_DisplayMessageToGroup( _unit, text )
|
self:_DisplayMessageToGroup( _unit, text )
|
||||||
self:T2( self.id .. text )
|
self:T2( self.id .. text )
|
||||||
_currentTarget.pastfoulline = true
|
_currentTarget.pastfoulline = true
|
||||||
invalidStrafe = true -- Rangeboss Edit
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1760,6 +1884,13 @@ function RANGE:OnEventHit( EventData )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Range event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun).
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #table weapon Weapon
|
||||||
|
function RANGE:_TrackWeapon(weapon)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
--- Range event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun).
|
--- Range event handler for event shot (when a unit releases a rocket or bomb (but not a fast firing gun).
|
||||||
-- @param #RANGE self
|
-- @param #RANGE self
|
||||||
-- @param Core.Event#EVENTDATA EventData
|
-- @param Core.Event#EVENTDATA EventData
|
||||||
@@ -1774,6 +1905,10 @@ function RANGE:OnEventShot( EventData )
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if EventData.IniPlayerName == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- Weapon data.
|
-- Weapon data.
|
||||||
local _weapon = EventData.Weapon:getTypeName() -- should be the same as Event.WeaponTypeName
|
local _weapon = EventData.Weapon:getTypeName() -- should be the same as Event.WeaponTypeName
|
||||||
local _weaponStrArray = UTILS.Split( _weapon, "%." )
|
local _weaponStrArray = UTILS.Split( _weapon, "%." )
|
||||||
@@ -1807,6 +1942,11 @@ function RANGE:OnEventShot( EventData )
|
|||||||
-- Get player unit and name.
|
-- Get player unit and name.
|
||||||
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
|
local _unit, _playername = self:_GetPlayerUnitAndName( _unitName )
|
||||||
|
|
||||||
|
-- Attack parameters.
|
||||||
|
local attackHdg=_unit:GetHeading()
|
||||||
|
local attackAlt=_unit:GetHeight()
|
||||||
|
local attackVel=_unit:GetVelocityKNOTS()
|
||||||
|
|
||||||
-- Set this to larger value than the threshold.
|
-- Set this to larger value than the threshold.
|
||||||
local dPR = self.BombtrackThreshold * 2
|
local dPR = self.BombtrackThreshold * 2
|
||||||
|
|
||||||
@@ -1848,7 +1988,6 @@ function RANGE:OnEventShot( EventData )
|
|||||||
|
|
||||||
-- Check again in ~0.005 seconds ==> 200 checks per second.
|
-- Check again in ~0.005 seconds ==> 200 checks per second.
|
||||||
return timer.getTime() + self.dtBombtrack
|
return timer.getTime() + self.dtBombtrack
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-----------------------------
|
-----------------------------
|
||||||
@@ -1858,7 +1997,7 @@ function RANGE:OnEventShot( EventData )
|
|||||||
-- Get closet target to last position.
|
-- Get closet target to last position.
|
||||||
local _closetTarget = nil -- #RANGE.BombTarget
|
local _closetTarget = nil -- #RANGE.BombTarget
|
||||||
local _distance = nil
|
local _distance = nil
|
||||||
local _closeCoord = nil
|
local _closeCoord = nil --Core.Point#COORDINATE
|
||||||
local _hitquality = "POOR"
|
local _hitquality = "POOR"
|
||||||
|
|
||||||
-- Get callsign.
|
-- Get callsign.
|
||||||
@@ -1886,6 +2025,7 @@ function RANGE:OnEventShot( EventData )
|
|||||||
|
|
||||||
-- Loop over defined bombing targets.
|
-- Loop over defined bombing targets.
|
||||||
for _, _bombtarget in pairs( self.bombingTargets ) do
|
for _, _bombtarget in pairs( self.bombingTargets ) do
|
||||||
|
local bombtarget=_bombtarget --#RANGE.BombTarget
|
||||||
|
|
||||||
-- Get target coordinate.
|
-- Get target coordinate.
|
||||||
local targetcoord = self:_GetBombTargetCoordinate( _bombtarget )
|
local targetcoord = self:_GetBombTargetCoordinate( _bombtarget )
|
||||||
@@ -1898,15 +2038,15 @@ function RANGE:OnEventShot( EventData )
|
|||||||
-- Find closest target to last known position of the bomb.
|
-- Find closest target to last known position of the bomb.
|
||||||
if _distance == nil or _temp < _distance then
|
if _distance == nil or _temp < _distance then
|
||||||
_distance = _temp
|
_distance = _temp
|
||||||
_closetTarget = _bombtarget
|
_closetTarget = bombtarget
|
||||||
_closeCoord = targetcoord
|
_closeCoord = targetcoord
|
||||||
if _distance <= 1.53 then -- Rangeboss Edit
|
if _distance <= 1.53 then -- Rangeboss Edit
|
||||||
_hitquality = "SHACK" -- Rangeboss Edit
|
_hitquality = "SHACK" -- Rangeboss Edit
|
||||||
elseif _distance <= 0.5 * _bombtarget.goodhitrange then -- Rangeboss Edit
|
elseif _distance <= 0.5 * bombtarget.goodhitrange then -- Rangeboss Edit
|
||||||
_hitquality = "EXCELLENT"
|
_hitquality = "EXCELLENT"
|
||||||
elseif _distance <= _bombtarget.goodhitrange then
|
elseif _distance <= bombtarget.goodhitrange then
|
||||||
_hitquality = "GOOD"
|
_hitquality = "GOOD"
|
||||||
elseif _distance <= 2 * _bombtarget.goodhitrange then
|
elseif _distance <= 2 * bombtarget.goodhitrange then
|
||||||
_hitquality = "INEFFECTIVE"
|
_hitquality = "INEFFECTIVE"
|
||||||
else
|
else
|
||||||
_hitquality = "POOR"
|
_hitquality = "POOR"
|
||||||
@@ -1927,6 +2067,7 @@ function RANGE:OnEventShot( EventData )
|
|||||||
local _results = self.bombPlayerResults[_playername]
|
local _results = self.bombPlayerResults[_playername]
|
||||||
|
|
||||||
local result = {} -- #RANGE.BombResult
|
local result = {} -- #RANGE.BombResult
|
||||||
|
result.command=SOCKET.DataType.BOMBRESULT
|
||||||
result.name = _closetTarget.name or "unknown"
|
result.name = _closetTarget.name or "unknown"
|
||||||
result.distance = _distance
|
result.distance = _distance
|
||||||
result.radial = _closeCoord:HeadingTo( impactcoord )
|
result.radial = _closeCoord:HeadingTo( impactcoord )
|
||||||
@@ -1934,11 +2075,17 @@ function RANGE:OnEventShot( EventData )
|
|||||||
result.quality = _hitquality
|
result.quality = _hitquality
|
||||||
result.player = playerData.playername
|
result.player = playerData.playername
|
||||||
result.time = timer.getAbsTime()
|
result.time = timer.getAbsTime()
|
||||||
|
result.clock = UTILS.SecondsToClock(result.time, true)
|
||||||
|
result.midate = UTILS.GetDCSMissionDate()
|
||||||
|
result.theatre = env.mission.theatre
|
||||||
result.airframe = playerData.airframe
|
result.airframe = playerData.airframe
|
||||||
result.roundsFired = 0 -- Rangeboss Edit
|
result.roundsFired = 0 -- Rangeboss Edit
|
||||||
result.roundsHit = 0 -- Rangeboss Edit
|
result.roundsHit = 0 -- Rangeboss Edit
|
||||||
result.roundsQuality = "N/A" -- Rangeboss Edit
|
result.roundsQuality = "N/A" -- Rangeboss Edit
|
||||||
result.rangename = self.rangename
|
result.rangename = self.rangename
|
||||||
|
result.attackHdg = attackHdg
|
||||||
|
result.attackVel = attackVel
|
||||||
|
result.attackAlt = attackAlt
|
||||||
|
|
||||||
-- Add to table.
|
-- Add to table.
|
||||||
table.insert( _results, result )
|
table.insert( _results, result )
|
||||||
@@ -1953,7 +2100,12 @@ function RANGE:OnEventShot( EventData )
|
|||||||
self:_DisplayMessageToGroup( _unit, _message, nil, false )
|
self:_DisplayMessageToGroup( _unit, _message, nil, false )
|
||||||
|
|
||||||
if self.rangecontrol then
|
if self.rangecontrol then
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCWeaponImpactedTooFar.filename, RANGE.Sound.RCWeaponImpactedTooFar.duration, self.soundpath, nil, nil, _message, self.subduration )
|
-- weapon impacted too far from the nearest target! No Score!
|
||||||
|
if self.useSRS then
|
||||||
|
self.controlsrsQ:NewTransmission(_message,nil,self.controlmsrs,nil,1)
|
||||||
|
else
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCWeaponImpactedTooFar.filename, RANGE.Sound.RCWeaponImpactedTooFar.duration, self.soundpath, nil, nil, _message, self.subduration )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -2037,17 +2189,25 @@ function RANGE:onafterEnterRange( From, Event, To, player )
|
|||||||
|
|
||||||
if self.instructor and self.rangecontrol then
|
if self.instructor and self.rangecontrol then
|
||||||
|
|
||||||
-- Range control radio frequency split.
|
if self.useSRS then
|
||||||
local RF = UTILS.Split( string.format( "%.3f", self.rangecontrolfreq ), "." )
|
local text = string.format("You entered the bombing range. For hit assessment, contact the range controller at %.3f MHz", self.rangecontrolfreq)
|
||||||
|
local ttstext = string.format("You entered the bombing range. For hit assessment, contact the range controller at %.3f mega hertz.", self.rangecontrolfreq)
|
||||||
|
local group = player.client:GetGroup()
|
||||||
|
self.instructsrsQ:NewTransmission(ttstext,nil,self.instructmsrs,nil,1,{group},text,10)
|
||||||
|
else
|
||||||
|
-- Range control radio frequency split.
|
||||||
|
local RF = UTILS.Split( string.format( "%.3f", self.rangecontrolfreq ), "." )
|
||||||
|
|
||||||
-- Radio message that player entered the range
|
-- Radio message that player entered the range
|
||||||
self.instructor:NewTransmission( RANGE.Sound.IREnterRange.filename, RANGE.Sound.IREnterRange.duration, self.soundpath )
|
-- You entered the bombing range. For hit assessment, contact the range controller at xy MHz
|
||||||
self.instructor:Number2Transmission( RF[1] )
|
self.instructor:NewTransmission( RANGE.Sound.IREnterRange.filename, RANGE.Sound.IREnterRange.duration, self.soundpath )
|
||||||
if tonumber( RF[2] ) > 0 then
|
self.instructor:Number2Transmission( RF[1] )
|
||||||
self.instructor:NewTransmission( RANGE.Sound.IRDecimal.filename, RANGE.Sound.IRDecimal.duration, self.soundpath )
|
if tonumber( RF[2] ) > 0 then
|
||||||
self.instructor:Number2Transmission( RF[2] )
|
self.instructor:NewTransmission( RANGE.Sound.IRDecimal.filename, RANGE.Sound.IRDecimal.duration, self.soundpath )
|
||||||
|
self.instructor:Number2Transmission( RF[2] )
|
||||||
|
end
|
||||||
|
self.instructor:NewTransmission( RANGE.Sound.IRMegaHertz.filename, RANGE.Sound.IRMegaHertz.duration, self.soundpath )
|
||||||
end
|
end
|
||||||
self.instructor:NewTransmission( RANGE.Sound.IRMegaHertz.filename, RANGE.Sound.IRMegaHertz.duration, self.soundpath )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -2061,7 +2221,14 @@ end
|
|||||||
function RANGE:onafterExitRange( From, Event, To, player )
|
function RANGE:onafterExitRange( From, Event, To, player )
|
||||||
|
|
||||||
if self.instructor then
|
if self.instructor then
|
||||||
self.instructor:NewTransmission( RANGE.Sound.IRExitRange.filename, RANGE.Sound.IRExitRange.duration, self.soundpath )
|
-- You left the bombing range zone. Have a nice day!
|
||||||
|
if self.useSRS then
|
||||||
|
local text = "You left the bombing range zone. Have a nice day!"
|
||||||
|
local group = player.client:GetGroup()
|
||||||
|
self.instructsrsQ:NewTransmission(text,nil,self.instructmsrs,nil,1,{group},text,10)
|
||||||
|
else
|
||||||
|
self.instructor:NewTransmission( RANGE.Sound.IRExitRange.filename, RANGE.Sound.IRExitRange.duration, self.soundpath )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -2078,49 +2245,78 @@ function RANGE:onafterImpact( From, Event, To, result, player )
|
|||||||
-- Only display target name if there is more than one bomb target.
|
-- Only display target name if there is more than one bomb target.
|
||||||
local targetname = nil
|
local targetname = nil
|
||||||
if #self.bombingTargets > 1 then
|
if #self.bombingTargets > 1 then
|
||||||
local targetname = result.name
|
targetname = result.name
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Send message to player.
|
-- Send message to player.
|
||||||
local text = string.format( "%s, impact %03d° for %d ft", player.playername, result.radial, UTILS.MetersToFeet( result.distance ) )
|
local text = string.format( "%s, impact %03d° for %d ft", player.playername, result.radial, UTILS.MetersToFeet( result.distance ) )
|
||||||
if targetname then
|
if targetname then
|
||||||
text = text .. string.format( " from bulls of target %s." )
|
text = text .. string.format( " from bulls of target %s.", targetname )
|
||||||
else
|
else
|
||||||
text = text .. "."
|
text = text .. "."
|
||||||
end
|
end
|
||||||
text = text .. string.format( " %s hit.", result.quality )
|
text = text .. string.format( " %s hit.", result.quality )
|
||||||
|
|
||||||
if self.rangecontrol then
|
if self.rangecontrol then
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCImpact.filename, RANGE.Sound.RCImpact.duration, self.soundpath, nil, nil, text, self.subduration )
|
|
||||||
self.rangecontrol:Number2Transmission( string.format( "%03d", result.radial ), nil, 0.1 )
|
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCDegrees.filename, RANGE.Sound.RCDegrees.duration, self.soundpath )
|
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCFor.filename, RANGE.Sound.RCFor.duration, self.soundpath )
|
|
||||||
self.rangecontrol:Number2Transmission( string.format( "%d", UTILS.MetersToFeet( result.distance ) ) )
|
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCFeet.filename, RANGE.Sound.RCFeet.duration, self.soundpath )
|
|
||||||
if result.quality == "POOR" then
|
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCPoorHit.filename, RANGE.Sound.RCPoorHit.duration, self.soundpath, nil, 0.5 )
|
|
||||||
elseif result.quality == "INEFFECTIVE" then
|
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCIneffectiveHit.filename, RANGE.Sound.RCIneffectiveHit.duration, self.soundpath, nil, 0.5 )
|
|
||||||
elseif result.quality == "GOOD" then
|
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCGoodHit.filename, RANGE.Sound.RCGoodHit.duration, self.soundpath, nil, 0.5 )
|
|
||||||
elseif result.quality == "EXCELLENT" then
|
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCExcellentHit.filename, RANGE.Sound.RCExcellentHit.duration, self.soundpath, nil, 0.5 )
|
|
||||||
end
|
|
||||||
|
|
||||||
|
if self.useSRS then
|
||||||
|
local group = player.client:GetGroup()
|
||||||
|
self.controlsrsQ:NewTransmission(text,nil,self.controlmsrs,nil,1,{group},text,10)
|
||||||
|
else
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCImpact.filename, RANGE.Sound.RCImpact.duration, self.soundpath, nil, nil, text, self.subduration )
|
||||||
|
self.rangecontrol:Number2Transmission( string.format( "%03d", result.radial ), nil, 0.1 )
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCDegrees.filename, RANGE.Sound.RCDegrees.duration, self.soundpath )
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCFor.filename, RANGE.Sound.RCFor.duration, self.soundpath )
|
||||||
|
self.rangecontrol:Number2Transmission( string.format( "%d", UTILS.MetersToFeet( result.distance ) ) )
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCFeet.filename, RANGE.Sound.RCFeet.duration, self.soundpath )
|
||||||
|
if result.quality == "POOR" then
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCPoorHit.filename, RANGE.Sound.RCPoorHit.duration, self.soundpath, nil, 0.5 )
|
||||||
|
elseif result.quality == "INEFFECTIVE" then
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCIneffectiveHit.filename, RANGE.Sound.RCIneffectiveHit.duration, self.soundpath, nil, 0.5 )
|
||||||
|
elseif result.quality == "GOOD" then
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCGoodHit.filename, RANGE.Sound.RCGoodHit.duration, self.soundpath, nil, 0.5 )
|
||||||
|
elseif result.quality == "EXCELLENT" then
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCExcellentHit.filename, RANGE.Sound.RCExcellentHit.duration, self.soundpath, nil, 0.5 )
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Unit.
|
-- Unit.
|
||||||
local unit = UNIT:FindByName( player.unitname )
|
if player.unitname and not self.useSRS then
|
||||||
|
|
||||||
-- Send message.
|
-- Get unit.
|
||||||
self:_DisplayMessageToGroup( unit, text, nil, true )
|
local unit = UNIT:FindByName( player.unitname )
|
||||||
self:T( self.id .. text )
|
|
||||||
|
-- Send message.
|
||||||
|
self:_DisplayMessageToGroup( unit, text, nil, true )
|
||||||
|
self:T( self.id .. text )
|
||||||
|
end
|
||||||
|
|
||||||
-- Save results.
|
-- Save results.
|
||||||
if self.autosave then
|
if self.autosave then
|
||||||
self:Save()
|
self:Save()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Send result to FunkMan, which creates fancy MatLab figures and sends them to Discord via a bot.
|
||||||
|
if self.funkmanSocket then
|
||||||
|
self.funkmanSocket:SendTable(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function called after strafing run.
|
||||||
|
-- @param #RANGE self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
-- @param #RANGE.PlayerData player Player data table.
|
||||||
|
-- @param #RANGE.StrafeResult result Result of run.
|
||||||
|
function RANGE:onafterStrafeResult( From, Event, To, player, result)
|
||||||
|
|
||||||
|
if self.funkmanSocket then
|
||||||
|
self.funkmanSocket:SendTable(result)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Function called before save event. Checks that io and lfs are desanitized.
|
--- Function called before save event. Checks that io and lfs are desanitized.
|
||||||
@@ -2175,7 +2371,7 @@ function RANGE:onafterSave( From, Event, To )
|
|||||||
local target = result.name
|
local target = result.name
|
||||||
local radial = result.radial
|
local radial = result.radial
|
||||||
local quality = result.quality
|
local quality = result.quality
|
||||||
local time = UTILS.SecondsToClock( result.time )
|
local time = UTILS.SecondsToClock(result.time, true)
|
||||||
local airframe = result.airframe
|
local airframe = result.airframe
|
||||||
local date = "n/a"
|
local date = "n/a"
|
||||||
if os then
|
if os then
|
||||||
@@ -2353,7 +2549,8 @@ end
|
|||||||
--- Start smoking a coordinate with a delay.
|
--- Start smoking a coordinate with a delay.
|
||||||
-- @param #table _args Argements passed.
|
-- @param #table _args Argements passed.
|
||||||
function RANGE._DelayedSmoke( _args )
|
function RANGE._DelayedSmoke( _args )
|
||||||
trigger.action.smoke( _args.coord:GetVec3(), _args.color )
|
_args.coord:Smoke(_args.color)
|
||||||
|
--trigger.action.smoke( _args.coord:GetVec3(), _args.color )
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Display top 10 stafing results of a specific player.
|
--- Display top 10 stafing results of a specific player.
|
||||||
@@ -2603,7 +2800,7 @@ function RANGE:_DisplayRangeInfo( _unitname )
|
|||||||
|
|
||||||
-- Check if we have a player.
|
-- Check if we have a player.
|
||||||
if unit and playername then
|
if unit and playername then
|
||||||
|
self:I(playername)
|
||||||
-- Message text.
|
-- Message text.
|
||||||
local text = ""
|
local text = ""
|
||||||
|
|
||||||
@@ -2672,7 +2869,8 @@ function RANGE:_DisplayRangeInfo( _unitname )
|
|||||||
if self.instructorrelayname then
|
if self.instructorrelayname then
|
||||||
local relay = UNIT:FindByName( self.instructorrelayname )
|
local relay = UNIT:FindByName( self.instructorrelayname )
|
||||||
if relay then
|
if relay then
|
||||||
alive = tostring( relay:IsAlive() )
|
--alive = tostring( relay:IsAlive() )
|
||||||
|
alive = relay:IsAlive() and "ok" or "N/A"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
text = text .. string.format( "Instructor %.3f MHz (Relay=%s)\n", self.instructorfreq, alive )
|
text = text .. string.format( "Instructor %.3f MHz (Relay=%s)\n", self.instructorfreq, alive )
|
||||||
@@ -2683,6 +2881,7 @@ function RANGE:_DisplayRangeInfo( _unitname )
|
|||||||
local relay = UNIT:FindByName( self.rangecontrolrelayname )
|
local relay = UNIT:FindByName( self.rangecontrolrelayname )
|
||||||
if relay then
|
if relay then
|
||||||
alive = tostring( relay:IsAlive() )
|
alive = tostring( relay:IsAlive() )
|
||||||
|
alive = relay:IsAlive() and "ok" or "N/A"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
text = text .. string.format( "Control %.3f MHz (Relay=%s)\n", self.rangecontrolfreq, alive )
|
text = text .. string.format( "Control %.3f MHz (Relay=%s)\n", self.rangecontrolfreq, alive )
|
||||||
@@ -2969,9 +3168,16 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
self:_DisplayMessageToGroup( _unit, _msg, nil, true )
|
self:_DisplayMessageToGroup( _unit, _msg, nil, true )
|
||||||
|
|
||||||
if self.rangecontrol then
|
if self.rangecontrol then
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCLeftStrafePitTooQuickly.filename, RANGE.Sound.RCLeftStrafePitTooQuickly.duration, self.soundpath )
|
if self.useSRS then
|
||||||
|
local group = _unit:GetGroup()
|
||||||
|
local text = "You left the strafing zone too quickly! No score!"
|
||||||
|
--self.controlsrsQ:NewTransmission(text,nil,self.controlmsrs,nil,1,{group},text,10)
|
||||||
|
self.controlsrsQ:NewTransmission(text,nil,self.controlmsrs,nil,1)
|
||||||
|
else
|
||||||
|
-- You left the strafing zone too quickly! No score!
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCLeftStrafePitTooQuickly.filename, RANGE.Sound.RCLeftStrafePitTooQuickly.duration, self.soundpath )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Get current ammo.
|
-- Get current ammo.
|
||||||
@@ -3035,19 +3241,26 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
|
|
||||||
-- Message text.
|
-- Message text.
|
||||||
local _text = string.format( "%s, hits on target %s: %d", self:_myname( _unitName ), _result.zone.name, _result.hits )
|
local _text = string.format( "%s, hits on target %s: %d", self:_myname( _unitName ), _result.zone.name, _result.hits )
|
||||||
|
local ttstext = string.format( "%s, hits on target %s: %d.", self:_myname( _unitName ), _result.zone.name, _result.hits )
|
||||||
if shots and accur then
|
if shots and accur then
|
||||||
_text = _text .. string.format( "\nTotal rounds fired %d. Accuracy %.1f %%.", shots, accur )
|
_text = _text .. string.format( "\nTotal rounds fired %d. Accuracy %.1f %%.", shots, accur )
|
||||||
|
ttstext = ttstext .. string.format( ". Total rounds fired %d. Accuracy %.1f percent.", shots, accur )
|
||||||
end
|
end
|
||||||
_text = _text .. string.format( "\n%s", resulttext )
|
_text = _text .. string.format( "\n%s", resulttext )
|
||||||
|
ttstext = ttstext .. string.format( " %s", resulttext )
|
||||||
|
|
||||||
-- Send message.
|
-- Send message.
|
||||||
self:_DisplayMessageToGroup( _unit, _text )
|
self:_DisplayMessageToGroup( _unit, _text )
|
||||||
|
|
||||||
-- Strafe result.
|
-- Strafe result.
|
||||||
local result = {} -- #RANGE.StrafeResult
|
local result = {} -- #RANGE.StrafeResult
|
||||||
|
result.command=SOCKET.DataType.STRAFERESULT
|
||||||
result.player=_playername
|
result.player=_playername
|
||||||
result.name=_result.zone.name or "unknown"
|
result.name=_result.zone.name or "unknown"
|
||||||
result.time = timer.getAbsTime()
|
result.time = timer.getAbsTime()
|
||||||
|
result.clock = UTILS.SecondsToClock(result.time)
|
||||||
|
result.midate = UTILS.GetDCSMissionDate()
|
||||||
|
result.theatre = env.mission.theatre
|
||||||
result.roundsFired = shots
|
result.roundsFired = shots
|
||||||
result.roundsHit = _result.hits
|
result.roundsHit = _result.hits
|
||||||
result.roundsQuality = resulttext
|
result.roundsQuality = resulttext
|
||||||
@@ -3066,16 +3279,20 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
|
|
||||||
-- Voice over.
|
-- Voice over.
|
||||||
if self.rangecontrol then
|
if self.rangecontrol then
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCHitsOnTarget.filename, RANGE.Sound.RCHitsOnTarget.duration, self.soundpath )
|
if self.useSRS then
|
||||||
self.rangecontrol:Number2Transmission( string.format( "%d", _result.hits ) )
|
self.controlsrsQ:NewTransmission(ttstext,nil,self.controlmsrs,nil,1)
|
||||||
if shots and accur then
|
else
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCTotalRoundsFired.filename, RANGE.Sound.RCTotalRoundsFired.duration, self.soundpath, nil, 0.2 )
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCHitsOnTarget.filename, RANGE.Sound.RCHitsOnTarget.duration, self.soundpath )
|
||||||
self.rangecontrol:Number2Transmission( string.format( "%d", shots ), nil, 0.2 )
|
self.rangecontrol:Number2Transmission( string.format( "%d", _result.hits ) )
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCAccuracy.filename, RANGE.Sound.RCAccuracy.duration, self.soundpath, nil, 0.2 )
|
if shots and accur then
|
||||||
self.rangecontrol:Number2Transmission( string.format( "%d", UTILS.Round( accur, 0 ) ) )
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCTotalRoundsFired.filename, RANGE.Sound.RCTotalRoundsFired.duration, self.soundpath, nil, 0.2 )
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCPercent.filename, RANGE.Sound.RCPercent.duration, self.soundpath )
|
self.rangecontrol:Number2Transmission( string.format( "%d", shots ), nil, 0.2 )
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCAccuracy.filename, RANGE.Sound.RCAccuracy.duration, self.soundpath, nil, 0.2 )
|
||||||
|
self.rangecontrol:Number2Transmission( string.format( "%d", UTILS.Round( accur, 0 ) ) )
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCPercent.filename, RANGE.Sound.RCPercent.duration, self.soundpath )
|
||||||
|
end
|
||||||
|
self.rangecontrol:NewTransmission( _sound.filename, _sound.duration, self.soundpath, nil, 0.5 )
|
||||||
end
|
end
|
||||||
self.rangecontrol:NewTransmission( _sound.filename, _sound.duration, self.soundpath, nil, 0.5 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Set strafe status to nil.
|
-- Set strafe status to nil.
|
||||||
@@ -3114,7 +3331,11 @@ function RANGE:_CheckInZone( _unitName )
|
|||||||
local _msg = string.format( "%s, rolling in on strafe pit %s.", self:_myname( _unitName ), target.name )
|
local _msg = string.format( "%s, rolling in on strafe pit %s.", self:_myname( _unitName ), target.name )
|
||||||
|
|
||||||
if self.rangecontrol then
|
if self.rangecontrol then
|
||||||
self.rangecontrol:NewTransmission( RANGE.Sound.RCRollingInOnStrafeTarget.filename, RANGE.Sound.RCRollingInOnStrafeTarget.duration, self.soundpath )
|
if self.useSRS then
|
||||||
|
self.controlsrsQ:NewTransmission(_msg,nil,self.controlmsrs,nil,1)
|
||||||
|
else
|
||||||
|
self.rangecontrol:NewTransmission( RANGE.Sound.RCRollingInOnStrafeTarget.filename, RANGE.Sound.RCRollingInOnStrafeTarget.duration, self.soundpath )
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Send message.
|
-- Send message.
|
||||||
@@ -3473,6 +3694,7 @@ function RANGE:_DisplayMessageToGroup( _unit, _text, _time, _clear, display )
|
|||||||
|
|
||||||
-- Group ID.
|
-- Group ID.
|
||||||
local _gid = _unit:GetGroup():GetID()
|
local _gid = _unit:GetGroup():GetID()
|
||||||
|
local _grp = _unit:GetGroup()
|
||||||
|
|
||||||
-- Get playername and player settings
|
-- Get playername and player settings
|
||||||
local _, playername = self:_GetPlayerUnitAndName( _unit:GetName() )
|
local _, playername = self:_GetPlayerUnitAndName( _unit:GetName() )
|
||||||
@@ -3480,14 +3702,14 @@ function RANGE:_DisplayMessageToGroup( _unit, _text, _time, _clear, display )
|
|||||||
|
|
||||||
-- Send message to player if messages enabled and not only for the examiner.
|
-- Send message to player if messages enabled and not only for the examiner.
|
||||||
if _gid and (playermessage == true or display) and (not self.examinerexclusive) then
|
if _gid and (playermessage == true or display) and (not self.examinerexclusive) then
|
||||||
trigger.action.outTextForGroup( _gid, _text, _time, _clear )
|
local m = MESSAGE:New(_text,_time,nil,_clear):ToUnit(_unit)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Send message to examiner.
|
-- Send message to examiner.
|
||||||
if self.examinergroupname ~= nil then
|
if self.examinergroupname ~= nil then
|
||||||
local _examinerid = GROUP:FindByName( self.examinergroupname ):GetID()
|
local _examinerid = GROUP:FindByName( self.examinergroupname )
|
||||||
if _examinerid then
|
if _examinerid then
|
||||||
trigger.action.outTextForGroup( _examinerid, _text, _time, _clear )
|
local m = MESSAGE:New(_text,_time,nil,_clear):ToGroup(_examinerid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3840,6 +4062,7 @@ function RANGE:_GetPlayerUnitAndName( _unitName )
|
|||||||
|
|
||||||
self:T2( { DCSunit = DCSunit, unit = unit, playername = playername } )
|
self:T2( { DCSunit = DCSunit, unit = unit, playername = playername } )
|
||||||
if DCSunit and unit and playername then
|
if DCSunit and unit and playername then
|
||||||
|
self:F2(playername)
|
||||||
return unit, playername
|
return unit, playername
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3856,13 +4079,22 @@ end
|
|||||||
-- @param #string unitname Name of the player unit.
|
-- @param #string unitname Name of the player unit.
|
||||||
function RANGE:_myname( unitname )
|
function RANGE:_myname( unitname )
|
||||||
self:F2( unitname )
|
self:F2( unitname )
|
||||||
|
local pname = "Ghost 1 1"
|
||||||
local unit = UNIT:FindByName( unitname )
|
local unit = UNIT:FindByName( unitname )
|
||||||
|
if unit then
|
||||||
|
local grp = unit:GetGroup()
|
||||||
|
if grp then
|
||||||
|
pname = grp:GetCustomCallSign(true,true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--[[
|
||||||
local pname = unit:GetPlayerName()
|
local pname = unit:GetPlayerName()
|
||||||
-- local csign = unit:GetCallsign()
|
-- local csign = unit:GetCallsign()
|
||||||
|
|
||||||
-- return string.format("%s (%s)", csign, pname)
|
-- return string.format("%s (%s)", csign, pname)
|
||||||
return string.format( "%s", pname )
|
return string.format( "%s", pname )
|
||||||
|
--]]
|
||||||
|
return pname
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -656,11 +656,12 @@ function SCORING:_AddPlayerFromUnit( UnitData )
|
|||||||
if self.Players[PlayerName].UnitCoalition ~= UnitCoalition and self.penaltyoncoalitionchange then
|
if self.Players[PlayerName].UnitCoalition ~= UnitCoalition and self.penaltyoncoalitionchange then
|
||||||
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + self.CoalitionChangePenalty or 50
|
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + self.CoalitionChangePenalty or 50
|
||||||
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
|
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] .. "(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). " ..
|
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] ..
|
||||||
self.CoalitionChangePenalty .. "Penalty points added.",
|
"(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). ".. self.CoalitionChangePenalty .."Penalty points added.",
|
||||||
MESSAGE.Type.Information )
|
MESSAGE.Type.Information
|
||||||
:ToAll()
|
):ToAll()
|
||||||
self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -1 * self.CoalitionChangePenalty, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType, UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
|
self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -1*self.CoalitionChangePenalty, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType,
|
||||||
|
UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1112,16 +1113,18 @@ function SCORING:_EventOnHit( Event )
|
|||||||
if InitCoalition then -- A coalition object was hit, probably a static.
|
if InitCoalition then -- A coalition object was hit, probably a static.
|
||||||
if InitCoalition == TargetCoalition then
|
if InitCoalition == TargetCoalition then
|
||||||
-- TODO: Penalty according scale
|
-- TODO: Penalty according scale
|
||||||
Player.Penalty = Player.Penalty + 10 -- * self.ScaleDestroyPenalty
|
Player.Penalty = Player.Penalty + 10 --* self.ScaleDestroyPenalty
|
||||||
PlayerHit.Penalty = PlayerHit.Penalty + 10 -- * self.ScaleDestroyPenalty
|
PlayerHit.Penalty = PlayerHit.Penalty + 10 --* self.ScaleDestroyPenalty
|
||||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 * self.ScaleDestroyPenalty
|
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1 * self.ScaleDestroyPenalty
|
||||||
|
|
||||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " .. TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
MESSAGE
|
||||||
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
|
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
|
||||||
MESSAGE.Type.Update )
|
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
||||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||||
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
MESSAGE.Type.Update
|
||||||
|
)
|
||||||
|
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||||
|
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||||
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
self:ScoreCSV( Event.WeaponPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, Event.WeaponName, Event.WeaponCoalition, Event.WeaponCategory, Event.WeaponTypeName, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||||
else
|
else
|
||||||
Player.Score = Player.Score + 1
|
Player.Score = Player.Score + 1
|
||||||
@@ -1652,17 +1655,18 @@ function SCORING:ReportScoreGroupDetailed( PlayerGroup )
|
|||||||
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
||||||
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
||||||
|
|
||||||
PlayerMessage = string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s",
|
PlayerMessage =
|
||||||
PlayerName,
|
string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )%s%s%s%s%s",
|
||||||
PlayerScore - PlayerPenalty,
|
PlayerName,
|
||||||
PlayerScore,
|
PlayerScore - PlayerPenalty,
|
||||||
PlayerPenalty,
|
PlayerScore,
|
||||||
ReportHits,
|
PlayerPenalty,
|
||||||
ReportDestroys,
|
ReportHits,
|
||||||
ReportCoalitionChanges,
|
ReportDestroys,
|
||||||
ReportGoals,
|
ReportCoalitionChanges,
|
||||||
ReportMissions
|
ReportGoals,
|
||||||
)
|
ReportMissions
|
||||||
|
)
|
||||||
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup )
|
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1707,12 +1711,13 @@ function SCORING:ReportScoreAllSummary( PlayerGroup )
|
|||||||
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
local PlayerScore = ScoreHits + ScoreDestroys + ScoreCoalitionChanges + ScoreGoals + ScoreMissions
|
||||||
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
local PlayerPenalty = PenaltyHits + PenaltyDestroys + PenaltyCoalitionChanges + PenaltyGoals + PenaltyMissions
|
||||||
|
|
||||||
PlayerMessage = string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )",
|
PlayerMessage =
|
||||||
PlayerName,
|
string.format( "Player '%s' Score = %d ( %d Score, -%d Penalties )",
|
||||||
PlayerScore - PlayerPenalty,
|
PlayerName,
|
||||||
PlayerScore,
|
PlayerScore - PlayerPenalty,
|
||||||
PlayerPenalty
|
PlayerScore,
|
||||||
)
|
PlayerPenalty
|
||||||
|
)
|
||||||
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Overview ):ToGroup( PlayerGroup )
|
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Overview ):ToGroup( PlayerGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ SEAD = {
|
|||||||
["Kh25"] = "Kh25",
|
["Kh25"] = "Kh25",
|
||||||
["BGM_109"] = "BGM_109",
|
["BGM_109"] = "BGM_109",
|
||||||
["AGM_154"] = "AGM_154",
|
["AGM_154"] = "AGM_154",
|
||||||
|
["HY-2"] = "HY-2",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Missile enumerators - from DCS ME and Wikipedia
|
--- Missile enumerators - from DCS ME and Wikipedia
|
||||||
@@ -98,6 +99,7 @@ SEAD = {
|
|||||||
["Kh25"] = {25, 0.8},
|
["Kh25"] = {25, 0.8},
|
||||||
["BGM_109"] = {460, 0.705}, --in-game ~465kn
|
["BGM_109"] = {460, 0.705}, --in-game ~465kn
|
||||||
["AGM_154"] = {130, 0.61},
|
["AGM_154"] = {130, 0.61},
|
||||||
|
["HY-2"] = {90,1},
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
|
--- Creates the main object which is handling defensive actions for SA sites or moving SA vehicles.
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
-- @module Functional.Shorad
|
-- @module Functional.Shorad
|
||||||
-- @image Functional.Shorad.jpg
|
-- @image Functional.Shorad.jpg
|
||||||
--
|
--
|
||||||
-- Date: July 2021
|
-- Date: Nov 2021
|
||||||
|
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--- **SHORAD** class, extends Core.Base#BASE
|
--- **SHORAD** class, extends Core.Base#BASE
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
-- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green.
|
-- @field #boolean UseEmOnOff Decide if we are using Emission on/off (default) or AlarmState red/green.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
|
|
||||||
--- *Good friends are worth defending.* Mr Tushman, Wonder (the Movie)
|
--- *Good friends are worth defending.* Mr Tushman, Wonder (the Movie)
|
||||||
--
|
--
|
||||||
-- Simple Class for a more intelligent Short Range Air Defense System
|
-- Simple Class for a more intelligent Short Range Air Defense System
|
||||||
@@ -131,6 +132,7 @@ do
|
|||||||
["Kh29"] = "Kh29",
|
["Kh29"] = "Kh29",
|
||||||
["Kh31"] = "Kh31",
|
["Kh31"] = "Kh31",
|
||||||
["Kh66"] = "Kh66",
|
["Kh66"] = "Kh66",
|
||||||
|
--["BGM_109"] = "BGM_109",
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Instantiates a new SHORAD object
|
--- Instantiates a new SHORAD object
|
||||||
@@ -138,13 +140,13 @@ do
|
|||||||
-- @param #string Name Name of this SHORAD
|
-- @param #string Name Name of this SHORAD
|
||||||
-- @param #string ShoradPrefix Filter for the Shorad #SET_GROUP
|
-- @param #string ShoradPrefix Filter for the Shorad #SET_GROUP
|
||||||
-- @param Core.Set#SET_GROUP Samset The #SET_GROUP of SAM sites to defend
|
-- @param Core.Set#SET_GROUP Samset The #SET_GROUP of SAM sites to defend
|
||||||
-- @param #number Radius Defense radius in meters, used to switch on groups
|
-- @param #number Radius Defense radius in meters, used to switch on SHORAD groups **within** this radius
|
||||||
-- @param #number ActiveTimer Determines how many seconds the systems stay on red alert after wake-up call
|
-- @param #number ActiveTimer Determines how many seconds the systems stay on red alert after wake-up call
|
||||||
-- @param #string Coalition Coalition, i.e. "blue", "red", or "neutral"
|
-- @param #string Coalition Coalition, i.e. "blue", "red", or "neutral"
|
||||||
-- @param #boolean UseEmOnOff Use Emissions On/Off rather than Alarm State Red/Green (default: use Emissions switch)
|
-- @param #boolean UseEmOnOff Use Emissions On/Off rather than Alarm State Red/Green (default: use Emissions switch)
|
||||||
-- @retunr #SHORAD self
|
-- @retunr #SHORAD self
|
||||||
function SHORAD:New(Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition, UseEmOnOff)
|
function SHORAD:New(Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition, UseEmOnOff)
|
||||||
local self = BASE:Inherit( self, BASE:New() )
|
local self = BASE:Inherit( self, FSM:New() )
|
||||||
self:T({Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition})
|
self:T({Name, ShoradPrefix, Samset, Radius, ActiveTimer, Coalition})
|
||||||
|
|
||||||
local GroupSet = SET_GROUP:New():FilterPrefixes(ShoradPrefix):FilterCoalitions(Coalition):FilterCategoryGround():FilterStart()
|
local GroupSet = SET_GROUP:New():FilterPrefixes(ShoradPrefix):FilterCoalitions(Coalition):FilterCategoryGround():FilterStart()
|
||||||
@@ -162,11 +164,17 @@ do
|
|||||||
self.DefenseLowProb = 70 -- probability to detect a missile shot, low margin
|
self.DefenseLowProb = 70 -- probability to detect a missile shot, low margin
|
||||||
self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin
|
self.DefenseHighProb = 90 -- probability to detect a missile shot, high margin
|
||||||
self.UseEmOnOff = UseEmOnOff or false -- Decide if we are using Emission on/off (default) or AlarmState red/green
|
self.UseEmOnOff = UseEmOnOff or false -- Decide if we are using Emission on/off (default) or AlarmState red/green
|
||||||
self:I("*** SHORAD - Started Version 0.2.8")
|
self:I("*** SHORAD - Started Version 0.3.1")
|
||||||
-- Set the string id for output to DCS.log file.
|
-- Set the string id for output to DCS.log file.
|
||||||
self.lid=string.format("SHORAD %s | ", self.name)
|
self.lid=string.format("SHORAD %s | ", self.name)
|
||||||
self:_InitState()
|
self:_InitState()
|
||||||
self:HandleEvent(EVENTS.Shot, self.HandleEventShot)
|
self:HandleEvent(EVENTS.Shot, self.HandleEventShot)
|
||||||
|
|
||||||
|
-- Start State.
|
||||||
|
self:SetStartState("Running")
|
||||||
|
self:AddTransition("*", "WakeUpShorad", "*")
|
||||||
|
self:AddTransition("*", "CalculateHitZone", "*")
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -310,7 +318,7 @@ do
|
|||||||
local hit = false
|
local hit = false
|
||||||
if self.DefendHarms then
|
if self.DefendHarms then
|
||||||
for _,_name in pairs (SHORAD.Harms) do
|
for _,_name in pairs (SHORAD.Harms) do
|
||||||
if string.find(WeaponName,_name,1) then hit = true end
|
if string.find(WeaponName,_name,1,true) then hit = true end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return hit
|
return hit
|
||||||
@@ -326,7 +334,7 @@ do
|
|||||||
local hit = false
|
local hit = false
|
||||||
if self.DefendMavs then
|
if self.DefendMavs then
|
||||||
for _,_name in pairs (SHORAD.Mavs) do
|
for _,_name in pairs (SHORAD.Mavs) do
|
||||||
if string.find(WeaponName,_name,1) then hit = true end
|
if string.find(WeaponName,_name,1,true) then hit = true end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return hit
|
return hit
|
||||||
@@ -367,7 +375,7 @@ do
|
|||||||
local returnname = false
|
local returnname = false
|
||||||
for _,_groups in pairs (shoradset) do
|
for _,_groups in pairs (shoradset) do
|
||||||
local groupname = _groups:GetName()
|
local groupname = _groups:GetName()
|
||||||
if string.find(groupname, tgtgrp, 1) then
|
if string.find(groupname, tgtgrp, 1, true) then
|
||||||
returnname = true
|
returnname = true
|
||||||
--_groups:RelocateGroundRandomInRadius(7,100,false,false) -- be a bit evasive
|
--_groups:RelocateGroundRandomInRadius(7,100,false,false) -- be a bit evasive
|
||||||
end
|
end
|
||||||
@@ -388,7 +396,7 @@ do
|
|||||||
local returnname = false
|
local returnname = false
|
||||||
for _,_groups in pairs (shoradset) do
|
for _,_groups in pairs (shoradset) do
|
||||||
local groupname = _groups:GetName()
|
local groupname = _groups:GetName()
|
||||||
if string.find(groupname, tgtgrp, 1) then
|
if string.find(groupname, tgtgrp, 1, true) then
|
||||||
returnname = true
|
returnname = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -400,6 +408,7 @@ do
|
|||||||
-- @return #boolean Returns true for a detection, else false
|
-- @return #boolean Returns true for a detection, else false
|
||||||
function SHORAD:_ShotIsDetected()
|
function SHORAD:_ShotIsDetected()
|
||||||
self:T(self.lid .. " _ShotIsDetected")
|
self:T(self.lid .. " _ShotIsDetected")
|
||||||
|
if self.debug then return true end
|
||||||
local IsDetected = false
|
local IsDetected = false
|
||||||
local DetectionProb = math.random(self.DefenseLowProb, self.DefenseHighProb) -- reference value
|
local DetectionProb = math.random(self.DefenseLowProb, self.DefenseHighProb) -- reference value
|
||||||
local ActualDetection = math.random(1,100) -- value for this shot
|
local ActualDetection = math.random(1,100) -- value for this shot
|
||||||
@@ -423,7 +432,7 @@ do
|
|||||||
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
-- mymantis = MANTIS:New("BlueMantis","Blue SAM","Blue EWR",nil,"blue",false,"Blue Awacs")
|
||||||
-- mymantis:AddShorad(myshorad,720)
|
-- mymantis:AddShorad(myshorad,720)
|
||||||
-- mymantis:Start()
|
-- mymantis:Start()
|
||||||
function SHORAD:WakeUpShorad(TargetGroup, Radius, ActiveTimer, TargetCat)
|
function SHORAD:onafterWakeUpShorad(From, Event, To, TargetGroup, Radius, ActiveTimer, TargetCat)
|
||||||
self:T(self.lid .. " WakeUpShorad")
|
self:T(self.lid .. " WakeUpShorad")
|
||||||
self:T({TargetGroup, Radius, ActiveTimer, TargetCat})
|
self:T({TargetGroup, Radius, ActiveTimer, TargetCat})
|
||||||
local targetcat = TargetCat or Object.Category.UNIT
|
local targetcat = TargetCat or Object.Category.UNIT
|
||||||
@@ -477,6 +486,76 @@ do
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (Internal) Calculate hit zone of an AGM-88
|
||||||
|
-- @param #SHORAD self
|
||||||
|
-- @param #table SEADWeapon DCS.Weapon object
|
||||||
|
-- @param Core.Point#COORDINATE pos0 Position of the plane when it fired
|
||||||
|
-- @param #number height Height when the missile was fired
|
||||||
|
-- @param Wrapper.Group#GROUP SEADGroup Attacker group
|
||||||
|
-- @return #SHORAD self
|
||||||
|
function SHORAD:onafterCalculateHitZone(From,Event,To,SEADWeapon,pos0,height,SEADGroup)
|
||||||
|
self:T("**** Calculating hit zone")
|
||||||
|
if SEADWeapon and SEADWeapon:isExist() then
|
||||||
|
--local pos = SEADWeapon:getPoint()
|
||||||
|
|
||||||
|
-- postion and height
|
||||||
|
local position = SEADWeapon:getPosition()
|
||||||
|
local mheight = height
|
||||||
|
-- heading
|
||||||
|
local wph = math.atan2(position.x.z, position.x.x)
|
||||||
|
if wph < 0 then
|
||||||
|
wph=wph+2*math.pi
|
||||||
|
end
|
||||||
|
wph=math.deg(wph)
|
||||||
|
|
||||||
|
-- velocity
|
||||||
|
local wpndata = SEAD.HarmData["AGM_88"]
|
||||||
|
local mveloc = math.floor(wpndata[2] * 340.29)
|
||||||
|
local c1 = (2*mheight*9.81)/(mveloc^2)
|
||||||
|
local c2 = (mveloc^2) / 9.81
|
||||||
|
local Ropt = c2 * math.sqrt(c1+1)
|
||||||
|
if height <= 5000 then
|
||||||
|
Ropt = Ropt * 0.72
|
||||||
|
elseif height <= 7500 then
|
||||||
|
Ropt = Ropt * 0.82
|
||||||
|
elseif height <= 10000 then
|
||||||
|
Ropt = Ropt * 0.87
|
||||||
|
elseif height <= 12500 then
|
||||||
|
Ropt = Ropt * 0.98
|
||||||
|
end
|
||||||
|
|
||||||
|
-- look at a couple of zones across the trajectory
|
||||||
|
for n=1,3 do
|
||||||
|
local dist = Ropt - ((n-1)*20000)
|
||||||
|
local predpos= pos0:Translate(dist,wph)
|
||||||
|
if predpos then
|
||||||
|
|
||||||
|
local targetzone = ZONE_RADIUS:New("Target Zone",predpos:GetVec2(),20000)
|
||||||
|
|
||||||
|
if self.debug then
|
||||||
|
predpos:MarkToAll(string.format("height=%dm | heading=%d | velocity=%ddeg | Ropt=%dm",mheight,wph,mveloc,Ropt),false)
|
||||||
|
targetzone:DrawZone(coalition.side.BLUE,{0,0,1},0.2,nil,nil,3,true)
|
||||||
|
end
|
||||||
|
|
||||||
|
local seadset = self.Groupset
|
||||||
|
local tgtcoord = targetzone:GetRandomPointVec2()
|
||||||
|
local tgtgrp = seadset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||||
|
local _targetgroup = nil
|
||||||
|
local _targetgroupname = "none"
|
||||||
|
local _targetskill = "Random"
|
||||||
|
if tgtgrp and tgtgrp:IsAlive() then
|
||||||
|
_targetgroup = tgtgrp
|
||||||
|
_targetgroupname = tgtgrp:GetName() -- group name
|
||||||
|
_targetskill = tgtgrp:GetUnit(1):GetSkill()
|
||||||
|
self:T("*** Found Target = ".. _targetgroupname)
|
||||||
|
self:WakeUpShorad(_targetgroupname, self.Radius, self.ActiveTimer, Object.Category.UNIT)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Main function - work on the EventData
|
--- Main function - work on the EventData
|
||||||
-- @param #SHORAD self
|
-- @param #SHORAD self
|
||||||
-- @param Core.Event#EVENTDATA EventData The event details table data set
|
-- @param Core.Event#EVENTDATA EventData The event details table data set
|
||||||
@@ -504,13 +583,48 @@ do
|
|||||||
if (self:_CheckHarms(ShootingWeaponName) or self:_CheckMavs(ShootingWeaponName)) and IsDetected then
|
if (self:_CheckHarms(ShootingWeaponName) or self:_CheckMavs(ShootingWeaponName)) and IsDetected then
|
||||||
-- get target data
|
-- get target data
|
||||||
local targetdata = EventData.Weapon:getTarget() -- Identify target
|
local targetdata = EventData.Weapon:getTarget() -- Identify target
|
||||||
|
-- Is there target data?
|
||||||
|
if not targetdata or self.debug then
|
||||||
|
if string.find(ShootingWeaponName,"AGM_88",1,true) then
|
||||||
|
self:I("**** Tracking AGM-88 with no target data.")
|
||||||
|
local pos0 = EventData.IniUnit:GetCoordinate()
|
||||||
|
local fheight = EventData.IniUnit:GetHeight()
|
||||||
|
self:__CalculateHitZone(20,ShootingWeapon,pos0,fheight,EventData.IniGroup)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
local targetcat = targetdata:getCategory() -- Identify category
|
local targetcat = targetdata:getCategory() -- Identify category
|
||||||
self:T(string.format("Target Category (3=STATIC, 1=UNIT)= %s",tostring(targetcat)))
|
self:T(string.format("Target Category (3=STATIC, 1=UNIT)= %s",tostring(targetcat)))
|
||||||
|
self:T({targetdata})
|
||||||
local targetunit = nil
|
local targetunit = nil
|
||||||
if targetcat == Object.Category.UNIT then -- UNIT
|
if targetcat == Object.Category.UNIT then -- UNIT
|
||||||
targetunit = UNIT:Find(targetdata)
|
targetunit = UNIT:Find(targetdata)
|
||||||
elseif targetcat == Object.Category.STATIC then -- STATIC
|
elseif targetcat == Object.Category.STATIC then -- STATIC
|
||||||
targetunit = STATIC:Find(targetdata)
|
--self:T("Static Target Data")
|
||||||
|
--self:T({targetdata:isExist()})
|
||||||
|
--self:T({targetdata:getPoint()})
|
||||||
|
local tgtcoord = COORDINATE:NewFromVec3(targetdata:getPoint())
|
||||||
|
--tgtcoord:MarkToAll("Missile Target",true)
|
||||||
|
|
||||||
|
local tgtgrp1 = self.Samset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||||
|
local tgtcoord1 = tgtgrp1:GetCoordinate()
|
||||||
|
--tgtcoord1:MarkToAll("Close target SAM",true)
|
||||||
|
|
||||||
|
local tgtgrp2 = self.Groupset:FindNearestGroupFromPointVec2(tgtcoord)
|
||||||
|
local tgtcoord2 = tgtgrp2:GetCoordinate()
|
||||||
|
--tgtcoord2:MarkToAll("Close target SHORAD",true)
|
||||||
|
|
||||||
|
local dist1 = tgtcoord:Get2DDistance(tgtcoord1)
|
||||||
|
local dist2 = tgtcoord:Get2DDistance(tgtcoord2)
|
||||||
|
|
||||||
|
if dist1 < dist2 then
|
||||||
|
targetunit = tgtgrp1
|
||||||
|
targetcat = Object.Category.UNIT
|
||||||
|
else
|
||||||
|
targetunit = tgtgrp2
|
||||||
|
targetcat = Object.Category.UNIT
|
||||||
|
end
|
||||||
end
|
end
|
||||||
--local targetunitname = Unit.getName(targetdata) -- Unit name
|
--local targetunitname = Unit.getName(targetdata) -- Unit name
|
||||||
if targetunit and targetunit:IsAlive() then
|
if targetunit and targetunit:IsAlive() then
|
||||||
@@ -519,7 +633,11 @@ do
|
|||||||
local targetgroup = nil
|
local targetgroup = nil
|
||||||
local targetgroupname = "none"
|
local targetgroupname = "none"
|
||||||
if targetcat == Object.Category.UNIT then
|
if targetcat == Object.Category.UNIT then
|
||||||
targetgroup = targetunit:GetGroup()
|
if targetunit.ClassName == "UNIT" then
|
||||||
|
targetgroup = targetunit:GetGroup()
|
||||||
|
elseif targetunit.ClassName == "GROUP" then
|
||||||
|
targetgroup = targetunit
|
||||||
|
end
|
||||||
targetgroupname = targetgroup:GetName() -- group name
|
targetgroupname = targetgroup:GetName() -- group name
|
||||||
elseif targetcat == Object.Category.STATIC then
|
elseif targetcat == Object.Category.STATIC then
|
||||||
targetgroup = targetunit
|
targetgroup = targetunit
|
||||||
@@ -540,6 +658,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return self
|
||||||
end
|
end
|
||||||
--
|
--
|
||||||
end
|
end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,9 +5,12 @@ __Moose.Include( 'Scripts/Moose/Utilities/Profiler.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Utilities/Templates.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/Templates.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Utilities/STTS.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/STTS.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Utilities/FiFo.lua' )
|
__Moose.Include( 'Scripts/Moose/Utilities/FiFo.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Utilities/Socket.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Base.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Base.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Core/Astar.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Beacon.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Beacon.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Core/Condition.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/UserFlag.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/UserFlag.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Report.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Report.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Scheduler.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Scheduler.lua' )
|
||||||
@@ -28,6 +31,8 @@ __Moose.Include( 'Scripts/Moose/Core/SpawnStatic.lua' )
|
|||||||
__Moose.Include( 'Scripts/Moose/Core/Timer.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Timer.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Goal.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Goal.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Core/Spot.lua' )
|
__Moose.Include( 'Scripts/Moose/Core/Spot.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Core/MarkerOps_Base.lua' )
|
||||||
|
__Moose.Include( 'Scripts/Moose/Core/TextAndSound.lua' )
|
||||||
|
|
||||||
__Moose.Include( 'Scripts/Moose/Wrapper/Object.lua' )
|
__Moose.Include( 'Scripts/Moose/Wrapper/Object.lua' )
|
||||||
__Moose.Include( 'Scripts/Moose/Wrapper/Identifiable.lua' )
|
__Moose.Include( 'Scripts/Moose/Wrapper/Identifiable.lua' )
|
||||||
|
|||||||
@@ -52,7 +52,6 @@
|
|||||||
--- ATIS class.
|
--- ATIS class.
|
||||||
-- @type ATIS
|
-- @type ATIS
|
||||||
-- @field #string ClassName Name of the class.
|
-- @field #string ClassName Name of the class.
|
||||||
-- @field #boolean Debug Debug mode. Messages to all about status.
|
|
||||||
-- @field #string lid Class id string for output to DCS log file.
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
-- @field #string theatre DCS map name.
|
-- @field #string theatre DCS map name.
|
||||||
-- @field #string airbasename The name of the airbase.
|
-- @field #string airbasename The name of the airbase.
|
||||||
@@ -309,7 +308,6 @@
|
|||||||
-- @field #ATIS
|
-- @field #ATIS
|
||||||
ATIS = {
|
ATIS = {
|
||||||
ClassName = "ATIS",
|
ClassName = "ATIS",
|
||||||
Debug = false,
|
|
||||||
lid = nil,
|
lid = nil,
|
||||||
theatre = nil,
|
theatre = nil,
|
||||||
airbasename = nil,
|
airbasename = nil,
|
||||||
@@ -588,7 +586,7 @@ _ATIS = {}
|
|||||||
|
|
||||||
--- ATIS class version.
|
--- ATIS class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
ATIS.version = "0.9.6"
|
ATIS.version = "0.9.8"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -613,26 +611,26 @@ ATIS.version = "0.9.6"
|
|||||||
|
|
||||||
--- Create a new ATIS class object for a specific aircraft carrier unit.
|
--- Create a new ATIS class object for a specific aircraft carrier unit.
|
||||||
-- @param #ATIS self
|
-- @param #ATIS self
|
||||||
-- @param #string airbasename Name of the airbase.
|
-- @param #string AirbaseName Name of the airbase.
|
||||||
-- @param #number frequency Radio frequency in MHz. Default 143.00 MHz.
|
-- @param #number Frequency Radio frequency in MHz. Default 143.00 MHz.
|
||||||
-- @param #number modulation Radio modulation: 0=AM, 1=FM. Default 0=AM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators
|
-- @param #number Modulation Radio modulation: 0=AM, 1=FM. Default 0=AM. See `radio.modulation.AM` and `radio.modulation.FM` enumerators.
|
||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
function ATIS:New( airbasename, frequency, modulation )
|
function ATIS:New(AirbaseName, Frequency, Modulation)
|
||||||
|
|
||||||
-- Inherit everything from FSM class.
|
-- Inherit everything from FSM class.
|
||||||
local self = BASE:Inherit( self, FSM:New() ) -- #ATIS
|
local self = BASE:Inherit( self, FSM:New() ) -- #ATIS
|
||||||
|
|
||||||
self.airbasename = airbasename
|
self.airbasename=AirbaseName
|
||||||
self.airbase = AIRBASE:FindByName( airbasename )
|
self.airbase=AIRBASE:FindByName(AirbaseName)
|
||||||
|
|
||||||
if self.airbase == nil then
|
if self.airbase==nil then
|
||||||
self:E( "ERROR: Airbase %s for ATIS could not be found!", tostring( airbasename ) )
|
self:E("ERROR: Airbase %s for ATIS could not be found!", tostring(AirbaseName))
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Default freq and modulation.
|
-- Default freq and modulation.
|
||||||
self.frequency = frequency or 143.00
|
self.frequency=Frequency or 143.00
|
||||||
self.modulation = modulation or 0
|
self.modulation=Modulation or 0
|
||||||
|
|
||||||
-- Get map.
|
-- Get map.
|
||||||
self.theatre = env.mission.theatre
|
self.theatre = env.mission.theatre
|
||||||
@@ -734,14 +732,6 @@ function ATIS:New( airbasename, frequency, modulation )
|
|||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
-- @param #string Text Report text.
|
-- @param #string Text Report text.
|
||||||
|
|
||||||
-- Debug trace.
|
|
||||||
if false then
|
|
||||||
self.Debug = true
|
|
||||||
BASE:TraceOnOff( true )
|
|
||||||
BASE:TraceClass( self.ClassName )
|
|
||||||
BASE:TraceLevel( 1 )
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -755,7 +745,7 @@ end
|
|||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
function ATIS:SetSoundfilesPath( path )
|
function ATIS:SetSoundfilesPath( path )
|
||||||
self.soundpath = tostring( path or "ATIS Soundfiles/" )
|
self.soundpath = tostring( path or "ATIS Soundfiles/" )
|
||||||
self:I( self.lid .. string.format( "Setting sound files path to %s", self.soundpath ) )
|
self:T( self.lid .. string.format( "Setting sound files path to %s", self.soundpath ) )
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -766,7 +756,7 @@ end
|
|||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
function ATIS:SetRadioRelayUnitName( unitname )
|
function ATIS:SetRadioRelayUnitName( unitname )
|
||||||
self.relayunitname = unitname
|
self.relayunitname = unitname
|
||||||
self:I( self.lid .. string.format( "Setting radio relay unit to %s", self.relayunitname ) )
|
self:T( self.lid .. string.format( "Setting radio relay unit to %s", self.relayunitname ) )
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -802,6 +792,15 @@ function ATIS:SetRunwayLength()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Give information on runway length.
|
||||||
|
-- @param #ATIS self
|
||||||
|
-- @return #ATIS self
|
||||||
|
function ATIS:SetRunwayLength()
|
||||||
|
self.rwylength=true
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Give information on airfield elevation
|
--- Give information on airfield elevation
|
||||||
-- @param #ATIS self
|
-- @param #ATIS self
|
||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
@@ -852,7 +851,7 @@ function ATIS:SetRunwayHeadingsMagnetic( headings )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Add runway heading to table.
|
-- Add runway heading to table.
|
||||||
self:I( self.lid .. string.format( "Adding user specified magnetic runway heading %s", heading ) )
|
self:T( self.lid .. string.format( "Adding user specified magnetic runway heading %s", heading ) )
|
||||||
table.insert( self.runwaymag, heading )
|
table.insert( self.runwaymag, heading )
|
||||||
|
|
||||||
local h = self:GetRunwayWithoutLR( heading )
|
local h = self:GetRunwayWithoutLR( heading )
|
||||||
@@ -874,7 +873,7 @@ function ATIS:SetRunwayHeadingsMagnetic( headings )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Add inverse runway heading to table.
|
-- Add inverse runway heading to table.
|
||||||
self:I( self.lid .. string.format( "Adding user specified magnetic runway heading %s (inverse)", head2 ) )
|
self:T( self.lid .. string.format( "Adding user specified magnetic runway heading %s (inverse)", head2 ) )
|
||||||
table.insert( self.runwaymag, head2 )
|
table.insert( self.runwaymag, head2 )
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1128,16 +1127,22 @@ end
|
|||||||
-- @param #string Voice Specific voice. Overrides `Gender` and `Culture`.
|
-- @param #string Voice Specific voice. Overrides `Gender` and `Culture`.
|
||||||
-- @param #number Port SRS port. Default 5002.
|
-- @param #number Port SRS port. Default 5002.
|
||||||
-- @return #ATIS self
|
-- @return #ATIS self
|
||||||
function ATIS:SetSRS( PathToSRS, Gender, Culture, Voice, Port )
|
function ATIS:SetSRS(PathToSRS, Gender, Culture, Voice, Port)
|
||||||
self.useSRS = true
|
if PathToSRS then
|
||||||
self.msrs = MSRS:New( PathToSRS, self.frequency, self.modulation )
|
self.useSRS=true
|
||||||
self.msrs:SetGender( Gender )
|
self.msrs=MSRS:New(PathToSRS, self.frequency, self.modulation)
|
||||||
self.msrs:SetCulture( Culture )
|
self.msrs:SetGender(Gender)
|
||||||
self.msrs:SetVoice( Voice )
|
self.msrs:SetCulture(Culture)
|
||||||
self.msrs:SetPort( Port )
|
self.msrs:SetVoice(Voice)
|
||||||
self.msrs:SetCoalition( self:GetCoalition() )
|
self.msrs:SetPort(Port)
|
||||||
if self.dTQueueCheck <= 10 then
|
self.msrs:SetCoalition(self:GetCoalition())
|
||||||
self:SetQueueUpdateTime( 90 )
|
self.msrs:SetLabel("ATIS")
|
||||||
|
self.msrsQ = MSRSQUEUE:New("ATIS")
|
||||||
|
if self.dTQueueCheck<=10 then
|
||||||
|
self:SetQueueUpdateTime(90)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self:E(self.lid..string.format("ERROR: No SRS path specified!"))
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1179,31 +1184,33 @@ function ATIS:onafterStart( From, Event, To )
|
|||||||
self:I( self.lid .. string.format( "Starting ATIS v%s for airbase %s on %.3f MHz Modulation=%d", ATIS.version, self.airbasename, self.frequency, self.modulation ) )
|
self:I( self.lid .. string.format( "Starting ATIS v%s for airbase %s on %.3f MHz Modulation=%d", ATIS.version, self.airbasename, self.frequency, self.modulation ) )
|
||||||
|
|
||||||
-- Start radio queue.
|
-- Start radio queue.
|
||||||
self.radioqueue = RADIOQUEUE:New( self.frequency, self.modulation, string.format( "ATIS %s", self.airbasename ) )
|
if not self.useSRS then
|
||||||
|
self.radioqueue = RADIOQUEUE:New( self.frequency, self.modulation, string.format( "ATIS %s", self.airbasename ) )
|
||||||
|
|
||||||
-- Send coordinate is airbase coord.
|
-- Send coordinate is airbase coord.
|
||||||
self.radioqueue:SetSenderCoordinate( self.airbase:GetCoordinate() )
|
self.radioqueue:SetSenderCoordinate( self.airbase:GetCoordinate() )
|
||||||
|
|
||||||
-- Set relay unit if we have one.
|
-- Set relay unit if we have one.
|
||||||
self.radioqueue:SetSenderUnitName( self.relayunitname )
|
self.radioqueue:SetSenderUnitName( self.relayunitname )
|
||||||
|
|
||||||
-- Set radio power.
|
-- Set radio power.
|
||||||
self.radioqueue:SetRadioPower( self.power )
|
self.radioqueue:SetRadioPower( self.power )
|
||||||
|
|
||||||
-- Init numbers.
|
-- Init numbers.
|
||||||
self.radioqueue:SetDigit( 0, ATIS.Sound.N0.filename, ATIS.Sound.N0.duration, self.soundpath )
|
self.radioqueue:SetDigit( 0, ATIS.Sound.N0.filename, ATIS.Sound.N0.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 1, ATIS.Sound.N1.filename, ATIS.Sound.N1.duration, self.soundpath )
|
self.radioqueue:SetDigit( 1, ATIS.Sound.N1.filename, ATIS.Sound.N1.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 2, ATIS.Sound.N2.filename, ATIS.Sound.N2.duration, self.soundpath )
|
self.radioqueue:SetDigit( 2, ATIS.Sound.N2.filename, ATIS.Sound.N2.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 3, ATIS.Sound.N3.filename, ATIS.Sound.N3.duration, self.soundpath )
|
self.radioqueue:SetDigit( 3, ATIS.Sound.N3.filename, ATIS.Sound.N3.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 4, ATIS.Sound.N4.filename, ATIS.Sound.N4.duration, self.soundpath )
|
self.radioqueue:SetDigit( 4, ATIS.Sound.N4.filename, ATIS.Sound.N4.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 5, ATIS.Sound.N5.filename, ATIS.Sound.N5.duration, self.soundpath )
|
self.radioqueue:SetDigit( 5, ATIS.Sound.N5.filename, ATIS.Sound.N5.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 6, ATIS.Sound.N6.filename, ATIS.Sound.N6.duration, self.soundpath )
|
self.radioqueue:SetDigit( 6, ATIS.Sound.N6.filename, ATIS.Sound.N6.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 7, ATIS.Sound.N7.filename, ATIS.Sound.N7.duration, self.soundpath )
|
self.radioqueue:SetDigit( 7, ATIS.Sound.N7.filename, ATIS.Sound.N7.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 8, ATIS.Sound.N8.filename, ATIS.Sound.N8.duration, self.soundpath )
|
self.radioqueue:SetDigit( 8, ATIS.Sound.N8.filename, ATIS.Sound.N8.duration, self.soundpath )
|
||||||
self.radioqueue:SetDigit( 9, ATIS.Sound.N9.filename, ATIS.Sound.N9.duration, self.soundpath )
|
self.radioqueue:SetDigit( 9, ATIS.Sound.N9.filename, ATIS.Sound.N9.duration, self.soundpath )
|
||||||
|
|
||||||
-- Start radio queue.
|
-- Start radio queue.
|
||||||
self.radioqueue:Start( 1, 0.1 )
|
self.radioqueue:Start( 1, 0.1 )
|
||||||
|
end
|
||||||
|
|
||||||
-- Handle airbase capture
|
-- Handle airbase capture
|
||||||
-- Handle events.
|
-- Handle events.
|
||||||
@@ -1239,7 +1246,7 @@ function ATIS:onafterStatus( From, Event, To )
|
|||||||
else
|
else
|
||||||
text = text .. string.format( ", Relay unit=%s (alive=%s)", tostring( self.relayunitname ), relayunitstatus )
|
text = text .. string.format( ", Relay unit=%s (alive=%s)", tostring( self.relayunitname ), relayunitstatus )
|
||||||
end
|
end
|
||||||
self:I( self.lid .. text )
|
self:T( self.lid .. text )
|
||||||
|
|
||||||
self:__Status( -60 )
|
self:__Status( -60 )
|
||||||
end
|
end
|
||||||
@@ -1378,7 +1385,8 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
--- Runway ---
|
--- Runway ---
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
local runway, rwyLeft = self:GetActiveRunway()
|
local runwayLanding, rwyLandingLeft=self:GetActiveRunway()
|
||||||
|
local runwayTakeoff, rwyTakeoffLeft=self:GetActiveRunway(true)
|
||||||
|
|
||||||
------------
|
------------
|
||||||
--- Time ---
|
--- Time ---
|
||||||
@@ -1444,8 +1452,8 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
|
|
||||||
-- Convert to °F.
|
-- Convert to °F.
|
||||||
if self.TDegF then
|
if self.TDegF then
|
||||||
temperature = UTILS.CelsiusToFahrenheit( temperature )
|
temperature=UTILS.CelsiusToFahrenheit(temperature)
|
||||||
dewpoint = UTILS.CelsiusToFahrenheit( dewpoint )
|
dewpoint=UTILS.CelsiusToFahrenheit(dewpoint)
|
||||||
end
|
end
|
||||||
|
|
||||||
local TEMPERATURE = string.format( "%d", math.abs( temperature ) )
|
local TEMPERATURE = string.format( "%d", math.abs( temperature ) )
|
||||||
@@ -1740,10 +1748,10 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Wind
|
-- Wind
|
||||||
-- Adding a space after each digit of WINDFROM to convert this to aviation-speak for TTS via SRS
|
-- Adding a space after each digit of WINDFROM to convert this to aviation-speak for TTS via SRS
|
||||||
if self.useSRS then
|
if self.useSRS then
|
||||||
WINDFROM = string.gsub(WINDFROM,".", "%1 ")
|
WINDFROM = string.gsub(WINDFROM,".", "%1 ")
|
||||||
end
|
end
|
||||||
if self.metric then
|
if self.metric then
|
||||||
subtitle = string.format( "Wind from %s at %s m/s", WINDFROM, WINDSPEED )
|
subtitle = string.format( "Wind from %s at %s m/s", WINDFROM, WINDSPEED )
|
||||||
else
|
else
|
||||||
@@ -2002,20 +2010,20 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
alltext = alltext .. ";\n" .. subtitle
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
|
|
||||||
-- Active runway.
|
-- Active runway.
|
||||||
local subtitle = string.format( "Active runway %s", runway )
|
local subtitle=string.format("Active runway %s", runwayLanding)
|
||||||
if rwyLeft == true then
|
if rwyLandingLeft==true then
|
||||||
subtitle = subtitle .. " Left"
|
subtitle=subtitle.." Left"
|
||||||
elseif rwyLeft == false then
|
elseif rwyLandingLeft==false then
|
||||||
subtitle = subtitle .. " Right"
|
subtitle=subtitle.." Right"
|
||||||
end
|
end
|
||||||
local _RUNACT = subtitle
|
local _RUNACT = subtitle
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
self:Transmission( ATIS.Sound.ActiveRunway, 1.0, subtitle )
|
self:Transmission(ATIS.Sound.ActiveRunway, 1.0, subtitle)
|
||||||
self.radioqueue:Number2Transmission( runway )
|
self.radioqueue:Number2Transmission(runwayLanding)
|
||||||
if rwyLeft == true then
|
if rwyLandingLeft==true then
|
||||||
self:Transmission( ATIS.Sound.Left, 0.2 )
|
self:Transmission(ATIS.Sound.Left, 0.2)
|
||||||
elseif rwyLeft == false then
|
elseif rwyLandingLeft==false then
|
||||||
self:Transmission( ATIS.Sound.Right, 0.2 )
|
self:Transmission(ATIS.Sound.Right, 0.2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
alltext = alltext .. ";\n" .. subtitle
|
alltext = alltext .. ";\n" .. subtitle
|
||||||
@@ -2126,7 +2134,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- ILS
|
-- ILS
|
||||||
local ils = self:GetNavPoint( self.ils, runway, rwyLeft )
|
local ils=self:GetNavPoint(self.ils, runwayLanding, rwyLandingLeft)
|
||||||
if ils then
|
if ils then
|
||||||
subtitle = string.format( "ILS frequency %.2f MHz", ils.frequency )
|
subtitle = string.format( "ILS frequency %.2f MHz", ils.frequency )
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
@@ -2144,7 +2152,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Outer NDB
|
-- Outer NDB
|
||||||
local ndb = self:GetNavPoint( self.ndbouter, runway, rwyLeft )
|
local ndb=self:GetNavPoint(self.ndbouter, runwayLanding, rwyLandingLeft)
|
||||||
if ndb then
|
if ndb then
|
||||||
subtitle = string.format( "Outer NDB frequency %.2f MHz", ndb.frequency )
|
subtitle = string.format( "Outer NDB frequency %.2f MHz", ndb.frequency )
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
@@ -2162,7 +2170,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Inner NDB
|
-- Inner NDB
|
||||||
local ndb = self:GetNavPoint( self.ndbinner, runway, rwyLeft )
|
local ndb=self:GetNavPoint(self.ndbinner, runwayLanding, rwyLandingLeft)
|
||||||
if ndb then
|
if ndb then
|
||||||
subtitle = string.format( "Inner NDB frequency %.2f MHz", ndb.frequency )
|
subtitle = string.format( "Inner NDB frequency %.2f MHz", ndb.frequency )
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
@@ -2201,7 +2209,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
|
|
||||||
-- TACAN
|
-- TACAN
|
||||||
if self.tacan then
|
if self.tacan then
|
||||||
subtitle = string.format( "TACAN channel %dX Ray", self.tacan )
|
subtitle=string.format("TACAN channel %dX Ray", self.tacan)
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
self:Transmission( ATIS.Sound.TACANChannel, 1.0, subtitle )
|
self:Transmission( ATIS.Sound.TACANChannel, 1.0, subtitle )
|
||||||
self.radioqueue:Number2Transmission( tostring( self.tacan ), nil, 0.2 )
|
self.radioqueue:Number2Transmission( tostring( self.tacan ), nil, 0.2 )
|
||||||
@@ -2221,7 +2229,7 @@ function ATIS:onafterBroadcast( From, Event, To )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- PRMG
|
-- PRMG
|
||||||
local ndb = self:GetNavPoint( self.prmg, runway, rwyLeft )
|
local ndb=self:GetNavPoint(self.prmg, runwayLanding, rwyLandingLeft)
|
||||||
if ndb then
|
if ndb then
|
||||||
subtitle = string.format( "PRMG channel %d", ndb.frequency )
|
subtitle = string.format( "PRMG channel %d", ndb.frequency )
|
||||||
if not self.useSRS then
|
if not self.useSRS then
|
||||||
@@ -2279,7 +2287,9 @@ function ATIS:onafterReport( From, Event, To, Text )
|
|||||||
self:T( "SRS TTS: " .. text )
|
self:T( "SRS TTS: " .. text )
|
||||||
|
|
||||||
-- Play text-to-speech report.
|
-- Play text-to-speech report.
|
||||||
self.msrs:PlayText( text )
|
local duration = STTS.getSpeechTime(text,0.95)
|
||||||
|
self.msrsQ:NewTransmission(text,duration,self.msrs,nil,2)
|
||||||
|
--self.msrs:PlayText( text )
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2348,39 +2358,19 @@ end
|
|||||||
|
|
||||||
--- Get active runway runway.
|
--- Get active runway runway.
|
||||||
-- @param #ATIS self
|
-- @param #ATIS self
|
||||||
|
-- @param #boolean Takeoff If `true`, get runway for takeoff. Default is for landing.
|
||||||
-- @return #string Active runway, e.g. "31" for 310 deg.
|
-- @return #string Active runway, e.g. "31" for 310 deg.
|
||||||
-- @return #boolean Use Left=true, Right=false, or nil.
|
-- @return #boolean Use Left=true, Right=false, or nil.
|
||||||
function ATIS:GetActiveRunway()
|
function ATIS:GetActiveRunway(Takeoff)
|
||||||
|
|
||||||
local coord = self.airbase:GetCoordinate()
|
local runway=nil --Wrapper.Airbase#AIRBASE.Runway
|
||||||
local height = coord:GetLandHeight()
|
if Takeoff then
|
||||||
|
runway=self.airbase:GetActiveRunwayTakeoff()
|
||||||
-- Get wind direction and speed in m/s.
|
else
|
||||||
local windFrom, windSpeed = coord:GetWind( height + 10 )
|
runway=self.airbase:GetActiveRunwayLanding()
|
||||||
|
|
||||||
-- Get active runway data based on wind direction.
|
|
||||||
local runact = self.airbase:GetActiveRunway( self.runwaym2t )
|
|
||||||
|
|
||||||
-- Active runway "31".
|
|
||||||
local runway = self:GetMagneticRunway( windFrom ) or runact.idx
|
|
||||||
|
|
||||||
-- Left or right in case there are two runways with the same heading.
|
|
||||||
local rwyLeft = nil
|
|
||||||
|
|
||||||
-- Check if user explicitly specified a runway.
|
|
||||||
if self.activerunway then
|
|
||||||
|
|
||||||
-- Get explicit runway heading if specified.
|
|
||||||
local runwayno = self:GetRunwayWithoutLR( self.activerunway )
|
|
||||||
if runwayno ~= "" then
|
|
||||||
runway = runwayno
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Was "L"eft or "R"ight given?
|
|
||||||
rwyLeft = self:GetRunwayLR( self.activerunway )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return runway, rwyLeft
|
return runway.name, runway.isLeft
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get runway from user supplied magnetic heading.
|
--- Get runway from user supplied magnetic heading.
|
||||||
@@ -2446,7 +2436,7 @@ end
|
|||||||
-- @return #string Runway heading without left or right, *e.g.* "31".
|
-- @return #string Runway heading without left or right, *e.g.* "31".
|
||||||
function ATIS:GetRunwayWithoutLR( runway )
|
function ATIS:GetRunwayWithoutLR( runway )
|
||||||
local rwywo = runway:gsub( "%D+", "" )
|
local rwywo = runway:gsub( "%D+", "" )
|
||||||
-- self:I(string.format("FF runway=%s ==> rwywo=%s", runway, rwywo))
|
-- self:T(string.format("FF runway=%s ==> rwywo=%s", runway, rwywo))
|
||||||
return rwywo
|
return rwywo
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
-- @field #number verbose Verbosity level.
|
-- @field #number verbose Verbosity level.
|
||||||
-- @field #string lid Class id string for output to DCS log file.
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
-- @field #number coalition Coalition side number, e.g. `coalition.side.RED`.
|
-- @field #number coalition Coalition side number, e.g. `coalition.side.RED`.
|
||||||
|
-- @field Core.Set#SET_GROUP allheligroupset Set of CSAR heli groups.
|
||||||
-- @extends Core.Fsm#FSM
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
--- *Combat search and rescue (CSAR) are search and rescue operations that are carried out during war that are within or near combat zones.* (Wikipedia)
|
--- *Combat search and rescue (CSAR) are search and rescue operations that are carried out during war that are within or near combat zones.* (Wikipedia)
|
||||||
@@ -129,9 +130,11 @@
|
|||||||
-- mycsar.SRSVoice = nil -- SRS voice, relevant for Google TTS
|
-- mycsar.SRSVoice = nil -- SRS voice, relevant for Google TTS
|
||||||
-- mycsar.SRSGPathToCredentials = nil -- Path to your Google credentials json file, set this if you want to use Google TTS
|
-- mycsar.SRSGPathToCredentials = nil -- Path to your Google credentials json file, set this if you want to use Google TTS
|
||||||
-- mycsar.SRSVolume = 1 -- Volume, between 0 and 1
|
-- mycsar.SRSVolume = 1 -- Volume, between 0 and 1
|
||||||
|
-- mycsar.SRSGender = "male" -- male or female voice
|
||||||
-- --
|
-- --
|
||||||
-- mycsar.csarUsePara = false -- If set to true, will use the LandingAfterEjection Event instead of Ejection. Requires mycsar.enableForAI to be set to true. --shagrat
|
-- mycsar.csarUsePara = false -- If set to true, will use the LandingAfterEjection Event instead of Ejection. Requires mycsar.enableForAI to be set to true. --shagrat
|
||||||
-- mycsar.wetfeettemplate = "man in floating thingy" -- if you use a mod to have a pilot in a rescue float, put the template name in here for wet feet spawns. Note: in conjunction with csarUsePara this might create dual ejected pilots in edge cases.
|
-- mycsar.wetfeettemplate = "man in floating thingy" -- if you use a mod to have a pilot in a rescue float, put the template name in here for wet feet spawns. Note: in conjunction with csarUsePara this might create dual ejected pilots in edge cases.
|
||||||
|
-- mycsar.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane
|
||||||
--
|
--
|
||||||
-- ## 3. Results
|
-- ## 3. Results
|
||||||
--
|
--
|
||||||
@@ -228,6 +231,7 @@ CSAR = {
|
|||||||
rescuedpilots = 0,
|
rescuedpilots = 0,
|
||||||
limitmaxdownedpilots = true,
|
limitmaxdownedpilots = true,
|
||||||
maxdownedpilots = 10,
|
maxdownedpilots = 10,
|
||||||
|
allheligroupset = nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Downed pilots info.
|
--- Downed pilots info.
|
||||||
@@ -261,10 +265,11 @@ CSAR.AircraftType["Mi-24V"] = 8
|
|||||||
CSAR.AircraftType["Bell-47"] = 2
|
CSAR.AircraftType["Bell-47"] = 2
|
||||||
CSAR.AircraftType["UH-60L"] = 10
|
CSAR.AircraftType["UH-60L"] = 10
|
||||||
CSAR.AircraftType["AH-64D_BLK_II"] = 2
|
CSAR.AircraftType["AH-64D_BLK_II"] = 2
|
||||||
|
CSAR.AircraftType["Bronco-OV-10A"] = 2
|
||||||
|
|
||||||
--- CSAR class version.
|
--- CSAR class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
CSAR.version="1.0.6"
|
CSAR.version="1.0.9"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- ToDo list
|
-- ToDo list
|
||||||
@@ -412,18 +417,22 @@ function CSAR:New(Coalition, Template, Alias)
|
|||||||
self.wetfeettemplate = nil
|
self.wetfeettemplate = nil
|
||||||
self.usewetfeet = false
|
self.usewetfeet = false
|
||||||
|
|
||||||
|
-- added 0.1.8
|
||||||
|
self.allowbronco = false -- set to true to use the Bronco mod as a CSAR plane
|
||||||
|
|
||||||
-- WARNING - here\'ll be dragons
|
-- WARNING - here\'ll be dragons
|
||||||
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
|
-- for this to work you need to de-sanitize your mission environment in <DCS root>\Scripts\MissionScripting.lua
|
||||||
-- needs SRS => 1.9.6 to work (works on the *server* side)
|
-- needs SRS => 1.9.6 to work (works on the *server* side)
|
||||||
self.useSRS = false -- Use FF\'s SRS integration
|
self.useSRS = false -- Use FF\'s SRS integration
|
||||||
self.SRSPath = "E:\\Progra~1\\DCS-SimpleRadio-Standalone\\" -- adjust your own path in your server(!)
|
self.SRSPath = "E:\\Program Files\\DCS-SimpleRadio-Standalone" -- adjust your own path in your server(!)
|
||||||
self.SRSchannel = 300 -- radio channel
|
self.SRSchannel = 300 -- radio channel
|
||||||
self.SRSModulation = radio.modulation.AM -- modulation
|
self.SRSModulation = radio.modulation.AM -- modulation
|
||||||
self.SRSport = 5002 -- port
|
self.SRSport = 5002 -- port
|
||||||
self.SRSCulture = "en-GB"
|
self.SRSCulture = "en-GB"
|
||||||
self.SRSVoice = nil
|
self.SRSVoice = nil
|
||||||
self.SRSGPathToCredentials = nil
|
self.SRSGPathToCredentials = nil
|
||||||
self.SRSVolume = 1
|
self.SRSVolume = 1.0 -- volume 0.0 to 1.0
|
||||||
|
self.SRSGender = "male" -- male or female
|
||||||
|
|
||||||
------------------------
|
------------------------
|
||||||
--- Pseudo Functions ---
|
--- Pseudo Functions ---
|
||||||
@@ -925,7 +934,16 @@ function CSAR:_EventHandler(EventData)
|
|||||||
|
|
||||||
local _unit = _event.IniUnit
|
local _unit = _event.IniUnit
|
||||||
local _group = _event.IniGroup
|
local _group = _event.IniGroup
|
||||||
if _unit:IsHelicopter() or _group:IsHelicopter() then
|
|
||||||
|
local function IsBronco(Group)
|
||||||
|
local grp = Group -- Wrapper.Group#GROUP
|
||||||
|
local typename = grp:GetTypeName()
|
||||||
|
self:T(typename)
|
||||||
|
if typename == "Bronco-OV-10A" then return true end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if _unit:IsHelicopter() or _group:IsHelicopter() or IsBronco(_group) then
|
||||||
self:_AddMedevacMenuItem()
|
self:_AddMedevacMenuItem()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1580,21 +1598,7 @@ function CSAR:_DisplayMessageToSAR(_unit, _text, _time, _clear, _speak, _overrid
|
|||||||
end
|
end
|
||||||
-- integrate SRS
|
-- integrate SRS
|
||||||
if _speak and self.useSRS then
|
if _speak and self.useSRS then
|
||||||
local srstext = SOUNDTEXT:New(_text)
|
self.SRSQueue:NewTransmission(_text,nil,self.msrs,nil,2)
|
||||||
local path = self.SRSPath
|
|
||||||
local modulation = self.SRSModulation
|
|
||||||
local channel = self.SRSchannel
|
|
||||||
local msrs = MSRS:New(path,channel,modulation)
|
|
||||||
msrs:SetPort(self.SRSport)
|
|
||||||
msrs:SetLabel("CSAR")
|
|
||||||
msrs:SetCulture(self.SRSCulture)
|
|
||||||
msrs:SetCoalition(self.coalition)
|
|
||||||
msrs:SetVoice(self.SRSVoice)
|
|
||||||
if self.SRSGPathToCredentials then
|
|
||||||
msrs:SetGoogle(self.SRSGPathToCredentials)
|
|
||||||
end
|
|
||||||
msrs:SetVolume(self.SRSVolume)
|
|
||||||
msrs:PlaySoundText(srstext, 2)
|
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1894,7 +1898,7 @@ function CSAR:_AddMedevacMenuItem()
|
|||||||
self:T(self.lid .. " _AddMedevacMenuItem")
|
self:T(self.lid .. " _AddMedevacMenuItem")
|
||||||
|
|
||||||
local coalition = self.coalition
|
local coalition = self.coalition
|
||||||
local allheligroupset = self.allheligroupset
|
local allheligroupset = self.allheligroupset -- Core.Set#SET_GROUP
|
||||||
local _allHeliGroups = allheligroupset:GetSetObjects()
|
local _allHeliGroups = allheligroupset:GetSetObjects()
|
||||||
|
|
||||||
-- rebuild units table
|
-- rebuild units table
|
||||||
@@ -2026,9 +2030,12 @@ function CSAR:_AddBeaconToGroup(_group, _freq)
|
|||||||
|
|
||||||
if _group:IsAlive() then
|
if _group:IsAlive() then
|
||||||
local _radioUnit = _group:GetUnit(1)
|
local _radioUnit = _group:GetUnit(1)
|
||||||
local Frequency = _freq -- Freq in Hertz
|
if _radioUnit then
|
||||||
local Sound = "l10n/DEFAULT/"..self.radioSound
|
local Frequency = _freq -- Freq in Hertz
|
||||||
trigger.action.radioTransmission(Sound, _radioUnit:GetPositionVec3(), 0, false, Frequency, 1000) -- Beacon in MP only runs for exactly 30secs straight
|
local Sound = "l10n/DEFAULT/"..self.radioSound
|
||||||
|
local vec3 = _radioUnit:GetVec3() or _radioUnit:GetPositionVec3() or {x=0,y=0,z=0}
|
||||||
|
trigger.action.radioTransmission(Sound, vec3, 0, false, Frequency, 1000) -- Beacon in MP only runs for exactly 30secs straight
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -2103,7 +2110,11 @@ function CSAR:onafterStart(From, Event, To)
|
|||||||
self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler)
|
self:HandleEvent(EVENTS.PlayerEnterAircraft, self._EventHandler)
|
||||||
self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler)
|
self:HandleEvent(EVENTS.PlayerEnterUnit, self._EventHandler)
|
||||||
self:HandleEvent(EVENTS.PilotDead, self._EventHandler)
|
self:HandleEvent(EVENTS.PilotDead, self._EventHandler)
|
||||||
if self.useprefix then
|
|
||||||
|
if self.allowbronco then
|
||||||
|
local prefixes = self.csarPrefix or {}
|
||||||
|
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(prefixes):FilterStart()
|
||||||
|
elseif self.useprefix then
|
||||||
local prefixes = self.csarPrefix or {}
|
local prefixes = self.csarPrefix or {}
|
||||||
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(prefixes):FilterCategoryHelicopter():FilterStart()
|
self.allheligroupset = SET_GROUP:New():FilterCoalitions(self.coalitiontxt):FilterPrefixes(prefixes):FilterCategoryHelicopter():FilterStart()
|
||||||
else
|
else
|
||||||
@@ -2113,6 +2124,24 @@ function CSAR:onafterStart(From, Event, To)
|
|||||||
if self.wetfeettemplate then
|
if self.wetfeettemplate then
|
||||||
self.usewetfeet = true
|
self.usewetfeet = true
|
||||||
end
|
end
|
||||||
|
if self.useSRS then
|
||||||
|
local path = self.SRSPath
|
||||||
|
local modulation = self.SRSModulation
|
||||||
|
local channel = self.SRSchannel
|
||||||
|
self.msrs = MSRS:New(path,channel,modulation)
|
||||||
|
self.msrs:SetPort(self.SRSport)
|
||||||
|
self.msrs:SetLabel("CSAR")
|
||||||
|
self.msrs:SetCulture(self.SRSCulture)
|
||||||
|
self.msrs:SetCoalition(self.coalition)
|
||||||
|
self.msrs:SetVoice(self.SRSVoice)
|
||||||
|
self.msrs:SetGender(self.SRSGender)
|
||||||
|
if self.SRSGPathToCredentials then
|
||||||
|
self.msrs:SetGoogle(self.SRSGPathToCredentials)
|
||||||
|
end
|
||||||
|
self.msrs:SetVolume(self.SRSVolume)
|
||||||
|
self.msrs:SetLabel("CSAR")
|
||||||
|
self.SRSQueue = MSRSQUEUE:New("CSAR")
|
||||||
|
end
|
||||||
self:__Status(-10)
|
self:__Status(-10)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
-- @field #string tankergroupname Name of the late activated tanker template group.
|
-- @field #string tankergroupname Name of the late activated tanker template group.
|
||||||
-- @field Wrapper.Group#GROUP tanker Tanker group.
|
-- @field Wrapper.Group#GROUP tanker Tanker group.
|
||||||
-- @field Wrapper.Airbase#AIRBASE airbase The home airbase object of the tanker. Normally the aircraft carrier.
|
-- @field Wrapper.Airbase#AIRBASE airbase The home airbase object of the tanker. Normally the aircraft carrier.
|
||||||
-- @field Core.Radio#BEACON beacon Tanker TACAN beacon.
|
-- @field Core.Beacon#BEACON beacon Tanker TACAN beacon.
|
||||||
-- @field #number TACANchannel TACAN channel. Default 1.
|
-- @field #number TACANchannel TACAN channel. Default 1.
|
||||||
-- @field #string TACANmode TACAN mode, i.e. "X" or "Y". Default "Y". Use only "Y" for AA TACAN stations!
|
-- @field #string TACANmode TACAN mode, i.e. "X" or "Y". Default "Y". Use only "Y" for AA TACAN stations!
|
||||||
-- @field #string TACANmorse TACAN morse code. Three letters identifying the TACAN station. Default "TKR".
|
-- @field #string TACANmorse TACAN morse code. Three letters identifying the TACAN station. Default "TKR".
|
||||||
@@ -784,10 +784,11 @@ end
|
|||||||
-- @param #RECOVERYTANKER self
|
-- @param #RECOVERYTANKER self
|
||||||
-- @param #number channel TACAN channel. Default 1.
|
-- @param #number channel TACAN channel. Default 1.
|
||||||
-- @param #string morse TACAN morse code identifier. Three letters. Default "TKR".
|
-- @param #string morse TACAN morse code identifier. Three letters. Default "TKR".
|
||||||
|
-- @param #string mode TACAN mode, which can be either "Y" (default) or "X".
|
||||||
-- @return #RECOVERYTANKER self
|
-- @return #RECOVERYTANKER self
|
||||||
function RECOVERYTANKER:SetTACAN(channel, morse)
|
function RECOVERYTANKER:SetTACAN(channel, morse, mode)
|
||||||
self.TACANchannel=channel or 1
|
self.TACANchannel=channel or 1
|
||||||
self.TACANmode="Y"
|
self.TACANmode=mode or "Y"
|
||||||
self.TACANmorse=morse or "TKR"
|
self.TACANmorse=morse or "TKR"
|
||||||
self.TACANon=true
|
self.TACANon=true
|
||||||
return self
|
return self
|
||||||
@@ -1625,7 +1626,6 @@ function RECOVERYTANKER:_ActivateTACAN(delay)
|
|||||||
if delay and delay>0 then
|
if delay and delay>0 then
|
||||||
|
|
||||||
-- Schedule TACAN activation.
|
-- Schedule TACAN activation.
|
||||||
--SCHEDULER:New(nil, self._ActivateTACAN, {self}, delay)
|
|
||||||
self:ScheduleOnce(delay, RECOVERYTANKER._ActivateTACAN, self)
|
self:ScheduleOnce(delay, RECOVERYTANKER._ActivateTACAN, self)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ function RADIO:SetFrequency(Frequency)
|
|||||||
if type(Frequency) == "number" then
|
if type(Frequency) == "number" then
|
||||||
|
|
||||||
-- If frequency is in range
|
-- If frequency is in range
|
||||||
-- if (Frequency >= 30 and Frequency <= 87.995) or (Frequency >= 108 and Frequency <= 173.995) or (Frequency >= 225 and Frequency <= 399.975) then
|
--if (Frequency >= 30 and Frequency <= 87.995) or (Frequency >= 108 and Frequency <= 173.995) or (Frequency >= 225 and Frequency <= 399.975) then
|
||||||
|
|
||||||
-- Convert frequency from MHz to Hz
|
-- Convert frequency from MHz to Hz
|
||||||
self.Frequency = Frequency * 1000000
|
self.Frequency = Frequency * 1000000
|
||||||
@@ -186,7 +186,7 @@ function RADIO:SetFrequency(Frequency)
|
|||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
-- end
|
--end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:E({"Frequency is not a number. Frequency unchanged.", Frequency})
|
self:E({"Frequency is not a number. Frequency unchanged.", Frequency})
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ RADIOSPEECH.Vocabulary.RU = {
|
|||||||
["br"] = { "br", 1.1 },
|
["br"] = { "br", 1.1 },
|
||||||
["bra"] = { "bra", 0.3 },
|
["bra"] = { "bra", 0.3 },
|
||||||
|
|
||||||
|
|
||||||
["возвращение на базу"] = { "returning_to_base", 1.40 },
|
["возвращение на базу"] = { "returning_to_base", 1.40 },
|
||||||
["на пути к наземной цели"] = { "on_route_to_ground_target", 1.45 },
|
["на пути к наземной цели"] = { "on_route_to_ground_target", 1.45 },
|
||||||
["перехват боги"] = { "intercepting_bogeys", 1.22 },
|
["перехват боги"] = { "intercepting_bogeys", 1.22 },
|
||||||
|
|||||||
@@ -143,6 +143,107 @@ MSRS = {
|
|||||||
-- @field #string version
|
-- @field #string version
|
||||||
MSRS.version="0.1.0"
|
MSRS.version="0.1.0"
|
||||||
|
|
||||||
|
--- Voices
|
||||||
|
-- @type Voices
|
||||||
|
MSRS.Voices = {
|
||||||
|
Microsoft = {
|
||||||
|
["Hedda"] = "Microsoft Hedda Desktop", -- de-DE
|
||||||
|
["Hazel"] = "Microsoft Hazel Desktop", -- en-GB
|
||||||
|
["David"] = "Microsoft David Desktop", -- en-US
|
||||||
|
["Zira"] = "Microsoft Zira Desktop", -- en-US
|
||||||
|
["Hortense"] = "Microsoft Hortense Desktop", --fr-FR
|
||||||
|
},
|
||||||
|
Google = {
|
||||||
|
Standard = {
|
||||||
|
["en-AU-Standard-A"] = 'en-AU-Standard-A', -- [1] FEMALE
|
||||||
|
["en-AU-Standard-B"] = 'en-AU-Standard-B', -- [2] MALE
|
||||||
|
["en-AU-Standard-C"] = 'en-AU-Standard-C', -- [3] FEMALE
|
||||||
|
["en-AU-Standard-D"] = 'en-AU-Standard-D', -- [4] MALE
|
||||||
|
["en-IN-Standard-A"] = 'en-IN-Standard-A', -- [5] FEMALE
|
||||||
|
["en-IN-Standard-B"] = 'en-IN-Standard-B', -- [6] MALE
|
||||||
|
["en-IN-Standard-C"] = 'en-IN-Standard-C', -- [7] MALE
|
||||||
|
["en-IN-Standard-D"] = 'en-IN-Standard-D', -- [8] FEMALE
|
||||||
|
["en-GB-Standard-A"] = 'en-GB-Standard-A', -- [9] FEMALE
|
||||||
|
["en-GB-Standard-B"] = 'en-GB-Standard-B', -- [10] MALE
|
||||||
|
["en-GB-Standard-C"] = 'en-GB-Standard-C', -- [11] FEMALE
|
||||||
|
["en-GB-Standard-D"] = 'en-GB-Standard-D', -- [12] MALE
|
||||||
|
["en-GB-Standard-F"] = 'en-GB-Standard-F', -- [13] FEMALE
|
||||||
|
["en-US-Standard-A"] = 'en-US-Standard-A', -- [14] MALE
|
||||||
|
["en-US-Standard-B"] = 'en-US-Standard-B', -- [15] MALE
|
||||||
|
["en-US-Standard-C"] = 'en-US-Standard-C', -- [16] FEMALE
|
||||||
|
["en-US-Standard-D"] = 'en-US-Standard-D', -- [17] MALE
|
||||||
|
["en-US-Standard-E"] = 'en-US-Standard-E', -- [18] FEMALE
|
||||||
|
["en-US-Standard-F"] = 'en-US-Standard-F', -- [19] FEMALE
|
||||||
|
["en-US-Standard-G"] = 'en-US-Standard-G', -- [20] FEMALE
|
||||||
|
["en-US-Standard-H"] = 'en-US-Standard-H', -- [21] FEMALE
|
||||||
|
["en-US-Standard-I"] = 'en-US-Standard-I', -- [22] MALE
|
||||||
|
["en-US-Standard-J"] = 'en-US-Standard-J', -- [23] MALE
|
||||||
|
["fr-FR-Standard-A"] = "fr-FR-Standard-A", -- Female
|
||||||
|
["fr-FR-Standard-B"] = "fr-FR-Standard-B", -- Male
|
||||||
|
["fr-FR-Standard-C"] = "fr-FR-Standard-C", -- Female
|
||||||
|
["fr-FR-Standard-D"] = "fr-FR-Standard-D", -- Male
|
||||||
|
["fr-FR-Standard-E"] = "fr-FR-Standard-E", -- Female
|
||||||
|
["de-DE-Standard-A"] = "de-DE-Standard-A", -- Female
|
||||||
|
["de-DE-Standard-B"] = "de-DE-Standard-B", -- Male
|
||||||
|
["de-DE-Standard-C"] = "de-DE-Standard-C", -- Female
|
||||||
|
["de-DE-Standard-D"] = "de-DE-Standard-D", -- Male
|
||||||
|
["de-DE-Standard-E"] = "de-DE-Standard-E", -- Male
|
||||||
|
["de-DE-Standard-F"] = "de-DE-Standard-F", -- Female
|
||||||
|
["es-ES-Standard-A"] = "es-ES-Standard-A", -- Female
|
||||||
|
["es-ES-Standard-B"] = "es-ES-Standard-B", -- Male
|
||||||
|
["es-ES-Standard-C"] = "es-ES-Standard-C", -- Female
|
||||||
|
["es-ES-Standard-D"] = "es-ES-Standard-D", -- Female
|
||||||
|
["it-IT-Standard-A"] = "it-IT-Standard-A", -- Female
|
||||||
|
["it-IT-Standard-B"] = "it-IT-Standard-B", -- Female
|
||||||
|
["it-IT-Standard-C"] = "it-IT-Standard-C", -- Male
|
||||||
|
["it-IT-Standard-D"] = "it-IT-Standard-D", -- Male
|
||||||
|
},
|
||||||
|
Wavenet = {
|
||||||
|
["en-AU-Wavenet-A"] = 'en-AU-Wavenet-A', -- [1] FEMALE
|
||||||
|
["en-AU-Wavenet-B"] = 'en-AU-Wavenet-B', -- [2] MALE
|
||||||
|
["en-AU-Wavenet-C"] = 'en-AU-Wavenet-C', -- [3] FEMALE
|
||||||
|
["en-AU-Wavenet-D"] = 'en-AU-Wavenet-D', -- [4] MALE
|
||||||
|
["en-IN-Wavenet-A"] = 'en-IN-Wavenet-A', -- [5] FEMALE
|
||||||
|
["en-IN-Wavenet-B"] = 'en-IN-Wavenet-B', -- [6] MALE
|
||||||
|
["en-IN-Wavenet-C"] = 'en-IN-Wavenet-C', -- [7] MALE
|
||||||
|
["en-IN-Wavenet-D"] = 'en-IN-Wavenet-D', -- [8] FEMALE
|
||||||
|
["en-GB-Wavenet-A"] = 'en-GB-Wavenet-A', -- [9] FEMALE
|
||||||
|
["en-GB-Wavenet-B"] = 'en-GB-Wavenet-B', -- [10] MALE
|
||||||
|
["en-GB-Wavenet-C"] = 'en-GB-Wavenet-C', -- [11] FEMALE
|
||||||
|
["en-GB-Wavenet-D"] = 'en-GB-Wavenet-D', -- [12] MALE
|
||||||
|
["en-GB-Wavenet-F"] = 'en-GB-Wavenet-F', -- [13] FEMALE
|
||||||
|
["en-US-Wavenet-A"] = 'en-US-Wavenet-A', -- [14] MALE
|
||||||
|
["en-US-Wavenet-B"] = 'en-US-Wavenet-B', -- [15] MALE
|
||||||
|
["en-US-Wavenet-C"] = 'en-US-Wavenet-C', -- [16] FEMALE
|
||||||
|
["en-US-Wavenet-D"] = 'en-US-Wavenet-D', -- [17] MALE
|
||||||
|
["en-US-Wavenet-E"] = 'en-US-Wavenet-E', -- [18] FEMALE
|
||||||
|
["en-US-Wavenet-F"] = 'en-US-Wavenet-F', -- [19] FEMALE
|
||||||
|
["en-US-Wavenet-G"] = 'en-US-Wavenet-G', -- [20] FEMALE
|
||||||
|
["en-US-Wavenet-H"] = 'en-US-Wavenet-H', -- [21] FEMALE
|
||||||
|
["en-US-Wavenet-I"] = 'en-US-Wavenet-I', -- [22] MALE
|
||||||
|
["en-US-Wavenet-J"] = 'en-US-Wavenet-J', -- [23] MALE
|
||||||
|
["fr-FR-Wavenet-A"] = "fr-FR-Wavenet-A", -- Female
|
||||||
|
["fr-FR-Wavenet-B"] = "fr-FR-Wavenet-B", -- Male
|
||||||
|
["fr-FR-Wavenet-C"] = "fr-FR-Wavenet-C", -- Female
|
||||||
|
["fr-FR-Wavenet-D"] = "fr-FR-Wavenet-D", -- Male
|
||||||
|
["fr-FR-Wavenet-E"] = "fr-FR-Wavenet-E", -- Female
|
||||||
|
["de-DE-Wavenet-A"] = "de-DE-Wavenet-A", -- Female
|
||||||
|
["de-DE-Wavenet-B"] = "de-DE-Wavenet-B", -- Male
|
||||||
|
["de-DE-Wavenet-C"] = "de-DE-Wavenet-C", -- Female
|
||||||
|
["de-DE-Wavenet-D"] = "de-DE-Wavenet-D", -- Male
|
||||||
|
["de-DE-Wavenet-E"] = "de-DE-Wavenet-E", -- Male
|
||||||
|
["de-DE-Wavenet-F"] = "de-DE-Wavenet-F", -- Female
|
||||||
|
["es-ES-Wavenet-B"] = "es-ES-Wavenet-B", -- Male
|
||||||
|
["es-ES-Wavenet-C"] = "es-ES-Wavenet-C", -- Female
|
||||||
|
["es-ES-Wavenet-D"] = "es-ES-Wavenet-D", -- Female
|
||||||
|
["it-IT-Wavenet-A"] = "it-IT-Wavenet-A", -- Female
|
||||||
|
["it-IT-Wavenet-B"] = "it-IT-Wavenet-B", -- Female
|
||||||
|
["it-IT-Wavenet-C"] = "it-IT-Wavenet-C", -- Male
|
||||||
|
["it-IT-Wavenet-D"] = "it-IT-Wavenet-D", -- Male
|
||||||
|
} ,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ do -- UserSound
|
|||||||
-- @return #USERSOUND The usersound instance.
|
-- @return #USERSOUND The usersound instance.
|
||||||
-- @usage
|
-- @usage
|
||||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||||
-- local PlayerUnit = UNIT:FindByName( "PlayerUnit" ) -- Search for the active group named "PlayerUnit", a human player.
|
-- local PlayerUnit = UNIT:FindByName( "PlayerUnit" ) -- Search for the active unit named "PlayerUnit", a human player.
|
||||||
-- BlueVictory:ToUnit( PlayerUnit ) -- Play the victory sound to the player unit.
|
-- BlueVictory:ToUnit( PlayerUnit ) -- Play the victory sound to the player unit.
|
||||||
--
|
--
|
||||||
function USERSOUND:ToUnit( Unit, Delay )
|
function USERSOUND:ToUnit( Unit, Delay )
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
|||||||
local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", CommandCenterMenu )
|
local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", CommandCenterMenu )
|
||||||
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportSummary, self, EventGroup )
|
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportSummary, self, EventGroup )
|
||||||
local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Players Report", MenuReporting, self.ReportMissionsPlayers, self, EventGroup )
|
local MenuMissionsDetails = MENU_GROUP_COMMAND:New( EventGroup, "Missions Players Report", MenuReporting, self.ReportMissionsPlayers, self, EventGroup )
|
||||||
self:ReportSummary( EventGroup )
|
--self:ReportSummary( EventGroup )
|
||||||
local PlayerUnit = EventData.IniUnit
|
local PlayerUnit = EventData.IniUnit
|
||||||
for MissionID, Mission in pairs( self:GetMissions() ) do
|
for MissionID, Mission in pairs( self:GetMissions() ) do
|
||||||
local Mission = Mission -- Tasking.Mission#MISSION
|
local Mission = Mission -- Tasking.Mission#MISSION
|
||||||
@@ -560,9 +560,11 @@ function COMMANDCENTER:SetAutoAssignTasks( AutoAssign )
|
|||||||
self.AutoAssignTasks = AutoAssign or false
|
self.AutoAssignTasks = AutoAssign or false
|
||||||
|
|
||||||
if self.AutoAssignTasks == true then
|
if self.AutoAssignTasks == true then
|
||||||
self:ScheduleRepeat( 10, 30, 0, nil, self.AssignTasks, self )
|
self.autoAssignTasksScheduleID=self:ScheduleRepeat( 10, 30, 0, nil, self.AssignTasks, self )
|
||||||
else
|
else
|
||||||
self:ScheduleStop( self.AssignTasks )
|
self:ScheduleStop()
|
||||||
|
-- FF this is not the schedule ID
|
||||||
|
--self:ScheduleStop( self.AssignTasks )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -683,6 +683,7 @@ do -- TASK_CARGO_DISPATCHER
|
|||||||
-- If no TaskPrefix is given, then "Transport" will be used as the prefix.
|
-- If no TaskPrefix is given, then "Transport" will be used as the prefix.
|
||||||
-- @param Core.SetCargo#SET_CARGO SetCargo The SetCargo to be transported.
|
-- @param Core.SetCargo#SET_CARGO SetCargo The SetCargo to be transported.
|
||||||
-- @param #string Briefing The briefing of the task transport to be shown to the player.
|
-- @param #string Briefing The briefing of the task transport to be shown to the player.
|
||||||
|
-- @param #boolean Silent If true don't send a message that a new task is available.
|
||||||
-- @return Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT
|
-- @return Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT
|
||||||
-- @usage
|
-- @usage
|
||||||
--
|
--
|
||||||
@@ -705,10 +706,12 @@ do -- TASK_CARGO_DISPATCHER
|
|||||||
-- -- Here we set a TransportDeployZone. We use the WorkplaceTask as the reference, and provide a ZONE object.
|
-- -- Here we set a TransportDeployZone. We use the WorkplaceTask as the reference, and provide a ZONE object.
|
||||||
-- TaskDispatcher:SetTransportDeployZone( WorkplaceTask, ZONE:New( "Workplace" ) )
|
-- TaskDispatcher:SetTransportDeployZone( WorkplaceTask, ZONE:New( "Workplace" ) )
|
||||||
--
|
--
|
||||||
function TASK_CARGO_DISPATCHER:AddTransportTask( TaskPrefix, SetCargo, Briefing )
|
function TASK_CARGO_DISPATCHER:AddTransportTask( TaskPrefix, SetCargo, Briefing, Silent )
|
||||||
|
|
||||||
self.TransportCount = self.TransportCount + 1
|
self.TransportCount = self.TransportCount + 1
|
||||||
|
|
||||||
|
local verbose = Silent or false
|
||||||
|
|
||||||
local TaskName = string.format( ( TaskPrefix or "Transport" ) .. ".%03d", self.TransportCount )
|
local TaskName = string.format( ( TaskPrefix or "Transport" ) .. ".%03d", self.TransportCount )
|
||||||
|
|
||||||
self.Transport[TaskName] = {}
|
self.Transport[TaskName] = {}
|
||||||
@@ -717,7 +720,7 @@ do -- TASK_CARGO_DISPATCHER
|
|||||||
self.Transport[TaskName].Task = nil
|
self.Transport[TaskName].Task = nil
|
||||||
self.Transport[TaskName].TaskPrefix = TaskPrefix
|
self.Transport[TaskName].TaskPrefix = TaskPrefix
|
||||||
|
|
||||||
self:ManageTasks()
|
self:ManageTasks(verbose)
|
||||||
|
|
||||||
return self.Transport[TaskName] and self.Transport[TaskName].Task
|
return self.Transport[TaskName] and self.Transport[TaskName].Task
|
||||||
end
|
end
|
||||||
@@ -785,10 +788,11 @@ do -- TASK_CARGO_DISPATCHER
|
|||||||
|
|
||||||
--- Assigns tasks to the @{Core.Set#SET_GROUP}.
|
--- Assigns tasks to the @{Core.Set#SET_GROUP}.
|
||||||
-- @param #TASK_CARGO_DISPATCHER self
|
-- @param #TASK_CARGO_DISPATCHER self
|
||||||
|
-- @param #boolean Silent Announce new task (nil/false) or not (true).
|
||||||
-- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop.
|
-- @return #boolean Return true if you want the task assigning to continue... false will cancel the loop.
|
||||||
function TASK_CARGO_DISPATCHER:ManageTasks()
|
function TASK_CARGO_DISPATCHER:ManageTasks(Silent)
|
||||||
self:F()
|
self:F()
|
||||||
|
local verbose = Silent and true
|
||||||
local AreaMsg = {}
|
local AreaMsg = {}
|
||||||
local TaskMsg = {}
|
local TaskMsg = {}
|
||||||
local ChangeMsg = {}
|
local ChangeMsg = {}
|
||||||
@@ -897,7 +901,7 @@ do -- TASK_CARGO_DISPATCHER
|
|||||||
local TaskText = TaskReport:Text(", ")
|
local TaskText = TaskReport:Text(", ")
|
||||||
|
|
||||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||||
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" then
|
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" and not verbose then
|
||||||
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
|
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetShortText(), TaskText ), TaskGroup )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
--
|
--
|
||||||
-- **Specific features:**
|
-- **Specific features:**
|
||||||
--
|
--
|
||||||
-- * Creates a task to transport @{Cargo.Cargo} to and between deployment zones.
|
-- * Creates a task to transport #Cargo.Cargo to and between deployment zones.
|
||||||
-- * Derived from the TASK_CARGO class, which is derived from the TASK class.
|
-- * Derived from the TASK_CARGO class, which is derived from the TASK class.
|
||||||
-- * Orchestrate the task flow, so go from Planned to Assigned to Success, Failed or Cancelled.
|
-- * Orchestrate the task flow, so go from Planned to Assigned to Success, Failed or Cancelled.
|
||||||
-- * Co-operation tasking, so a player joins a group of players executing the same task.
|
-- * Co-operation tasking, so a player joins a group of players executing the same task.
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
-- Please read through the @{Tasking.Task_Cargo} process to understand the mechanisms of tasking and cargo tasking and handling.
|
-- Please read through the #Tasking.Task_Cargo process to understand the mechanisms of tasking and cargo tasking and handling.
|
||||||
--
|
--
|
||||||
-- Enjoy!
|
-- Enjoy!
|
||||||
-- FC
|
-- FC
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
do -- TASK_CARGO_TRANSPORT
|
do -- TASK_CARGO_TRANSPORT
|
||||||
|
|
||||||
--- @type TASK_CARGO_TRANSPORT
|
-- @type TASK_CARGO_TRANSPORT
|
||||||
-- @extends Tasking.Task_CARGO#TASK_CARGO
|
-- @extends Tasking.Task_CARGO#TASK_CARGO
|
||||||
|
|
||||||
--- Orchestrates the task for players to transport cargo to or between deployment zones.
|
--- Orchestrates the task for players to transport cargo to or between deployment zones.
|
||||||
@@ -76,7 +76,7 @@ do -- TASK_CARGO_TRANSPORT
|
|||||||
--
|
--
|
||||||
-- ## 1.1) Create a command center.
|
-- ## 1.1) Create a command center.
|
||||||
--
|
--
|
||||||
-- First you need to create a command center using the @{Tasking.CommandCenter#COMMANDCENTER.New}() constructor.
|
-- First you need to create a command center using the Tasking.CommandCenter#COMMANDCENTER.New constructor.
|
||||||
--
|
--
|
||||||
-- local CommandCenter = COMMANDCENTER
|
-- local CommandCenter = COMMANDCENTER
|
||||||
-- :New( HQ, "Lima" ) -- Create the CommandCenter.
|
-- :New( HQ, "Lima" ) -- Create the CommandCenter.
|
||||||
@@ -85,7 +85,7 @@ do -- TASK_CARGO_TRANSPORT
|
|||||||
--
|
--
|
||||||
-- Tasks work in a mission, which groups these tasks to achieve a joint mission goal.
|
-- Tasks work in a mission, which groups these tasks to achieve a joint mission goal.
|
||||||
-- A command center can govern multiple missions.
|
-- A command center can govern multiple missions.
|
||||||
-- Create a new mission, using the @{Tasking.Mission#MISSION.New}() constructor.
|
-- Create a new mission, using the Tasking.Mission#MISSION.New constructor.
|
||||||
--
|
--
|
||||||
-- -- Declare the Mission for the Command Center.
|
-- -- Declare the Mission for the Command Center.
|
||||||
-- local Mission = MISSION
|
-- local Mission = MISSION
|
||||||
@@ -99,7 +99,7 @@ do -- TASK_CARGO_TRANSPORT
|
|||||||
-- ## 1.3) Create the transport cargo task.
|
-- ## 1.3) Create the transport cargo task.
|
||||||
--
|
--
|
||||||
-- So, now that we have a command center and a mission, we now create the transport task.
|
-- So, now that we have a command center and a mission, we now create the transport task.
|
||||||
-- We create the transport task using the @{#TASK_CARGO_TRANSPORT.New}() constructor.
|
-- We create the transport task using the #TASK_CARGO_TRANSPORT.New constructor.
|
||||||
--
|
--
|
||||||
-- Because a transport task will not generate the cargo itself, you'll need to create it first.
|
-- Because a transport task will not generate the cargo itself, you'll need to create it first.
|
||||||
-- The cargo in this case will be the downed pilot!
|
-- The cargo in this case will be the downed pilot!
|
||||||
@@ -118,7 +118,7 @@ do -- TASK_CARGO_TRANSPORT
|
|||||||
-- -- The cargoset "CargoSet" will embed all defined cargo of type "Pilots" (prefix) into its set.
|
-- -- The cargoset "CargoSet" will embed all defined cargo of type "Pilots" (prefix) into its set.
|
||||||
-- local CargoGroup = CARGO_GROUP:New( PilotGroup, "Cargo", "Engineer Team 1", 500 )
|
-- local CargoGroup = CARGO_GROUP:New( PilotGroup, "Cargo", "Engineer Team 1", 500 )
|
||||||
--
|
--
|
||||||
-- What is also needed, is to have a set of @{Core.Group}s defined that contains the clients of the players.
|
-- What is also needed, is to have a set of Core.Groups defined that contains the clients of the players.
|
||||||
--
|
--
|
||||||
-- -- Allocate the Transport, which are the helicopter to retrieve the pilot, that can be manned by players.
|
-- -- Allocate the Transport, which are the helicopter to retrieve the pilot, that can be manned by players.
|
||||||
-- local GroupSet = SET_GROUP:New():FilterPrefixes( "Transport" ):FilterStart()
|
-- local GroupSet = SET_GROUP:New():FilterPrefixes( "Transport" ):FilterStart()
|
||||||
@@ -139,48 +139,48 @@ do -- TASK_CARGO_TRANSPORT
|
|||||||
-- By doing this, cargo transport tasking will become a dynamic experience.
|
-- By doing this, cargo transport tasking will become a dynamic experience.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- # 2) Create a task using the @{Tasking.Task_Cargo_Dispatcher} module.
|
-- # 2) Create a task using the Tasking.Task_Cargo_Dispatcher module.
|
||||||
--
|
--
|
||||||
-- Actually, it is better to **GENERATE** these tasks using the @{Tasking.Task_Cargo_Dispatcher} module.
|
-- Actually, it is better to **GENERATE** these tasks using the Tasking.Task_Cargo_Dispatcher module.
|
||||||
-- Using the dispatcher module, transport tasks can be created much more easy.
|
-- Using the dispatcher module, transport tasks can be created easier.
|
||||||
--
|
--
|
||||||
-- Find below an example how to use the TASK_CARGO_DISPATCHER class:
|
-- Find below an example how to use the TASK_CARGO_DISPATCHER class:
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- -- Find the HQ group.
|
-- -- Find the HQ group.
|
||||||
-- HQ = GROUP:FindByName( "HQ", "Bravo" )
|
-- HQ = GROUP:FindByName( "HQ", "Bravo" )
|
||||||
--
|
--
|
||||||
-- -- Create the command center with the name "Lima".
|
-- -- Create the command center with the name "Lima".
|
||||||
-- CommandCenter = COMMANDCENTER
|
-- CommandCenter = COMMANDCENTER
|
||||||
-- :New( HQ, "Lima" )
|
-- :New( HQ, "Lima" )
|
||||||
--
|
--
|
||||||
-- -- Create the mission, for the command center, with the name "Operation Cargo Fun", a "Tactical" mission, with the mission briefing "Transport Cargo", for the BLUE coalition.
|
-- -- Create the mission, for the command center, with the name "Operation Cargo Fun", a "Tactical" mission, with the mission briefing "Transport Cargo", for the BLUE coalition.
|
||||||
-- Mission = MISSION
|
-- Mission = MISSION
|
||||||
-- :New( CommandCenter, "Operation Cargo Fun", "Tactical", "Transport Cargo", coalition.side.BLUE )
|
-- :New( CommandCenter, "Operation Cargo Fun", "Tactical", "Transport Cargo", coalition.side.BLUE )
|
||||||
--
|
--
|
||||||
-- -- Create the SET of GROUPs containing clients (players) that will transport the cargo.
|
-- -- Create the SET of GROUPs containing clients (players) that will transport the cargo.
|
||||||
-- -- These are have a name that start with "Transport" and are of the "blue" coalition.
|
-- -- These are have a name that start with "Transport" and are of the "blue" coalition.
|
||||||
-- TransportGroups = SET_GROUP:New():FilterCoalitions( "blue" ):FilterPrefixes( "Transport" ):FilterStart()
|
-- TransportGroups = SET_GROUP:New():FilterCoalitions( "blue" ):FilterPrefixes( "Transport" ):FilterStart()
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- -- Here we create the TASK_CARGO_DISPATCHER object! This is where we assign the dispatcher to generate tasks in the Mission for the TransportGroups.
|
-- -- Here we create the TASK_CARGO_DISPATCHER object! This is where we assign the dispatcher to generate tasks in the Mission for the TransportGroups.
|
||||||
-- TaskDispatcher = TASK_CARGO_DISPATCHER:New( Mission, TransportGroups )
|
-- TaskDispatcher = TASK_CARGO_DISPATCHER:New( Mission, TransportGroups )
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- -- Here we declare the SET of CARGOs called "Workmaterials".
|
-- -- Here we declare the SET of CARGOs called "Workmaterials".
|
||||||
-- local CargoSetWorkmaterials = SET_CARGO:New():FilterTypes( "Workmaterials" ):FilterStart()
|
-- local CargoSetWorkmaterials = SET_CARGO:New():FilterTypes( "Workmaterials" ):FilterStart()
|
||||||
--
|
--
|
||||||
-- -- Here we declare (add) CARGO_GROUP objects of various types, that are filtered and added in the CargoSetworkmaterials cargo set.
|
-- -- Here we declare (add) CARGO_GROUP objects of various types, that are filtered and added in the CargoSetworkmaterials cargo set.
|
||||||
-- -- These cargo objects have the type "Workmaterials" which is exactly the type of cargo the CargoSetworkmaterials is filtering on.
|
-- -- These cargo objects have the type "Workmaterials" which is exactly the type of cargo the CargoSetworkmaterials is filtering on.
|
||||||
-- local EngineerCargoGroup = CARGO_GROUP:New( GROUP:FindByName( "Engineers" ), "Workmaterials", "Engineers", 250 )
|
-- local EngineerCargoGroup = CARGO_GROUP:New( GROUP:FindByName( "Engineers" ), "Workmaterials", "Engineers", 250 )
|
||||||
-- local ConcreteCargo = CARGO_SLINGLOAD:New( STATIC:FindByName( "Concrete" ), "Workmaterials", "Concrete", 150, 50 )
|
-- local ConcreteCargo = CARGO_SLINGLOAD:New( STATIC:FindByName( "Concrete" ), "Workmaterials", "Concrete", 150, 50 )
|
||||||
-- local CrateCargo = CARGO_CRATE:New( STATIC:FindByName( "Crate" ), "Workmaterials", "Crate", 150, 50 )
|
-- local CrateCargo = CARGO_CRATE:New( STATIC:FindByName( "Crate" ), "Workmaterials", "Crate", 150, 50 )
|
||||||
-- local EnginesCargo = CARGO_CRATE:New( STATIC:FindByName( "Engines" ), "Workmaterials", "Engines", 150, 50 )
|
-- local EnginesCargo = CARGO_CRATE:New( STATIC:FindByName( "Engines" ), "Workmaterials", "Engines", 150, 50 )
|
||||||
-- local MetalCargo = CARGO_CRATE:New( STATIC:FindByName( "Metal" ), "Workmaterials", "Metal", 150, 50 )
|
-- local MetalCargo = CARGO_CRATE:New( STATIC:FindByName( "Metal" ), "Workmaterials", "Metal", 150, 50 )
|
||||||
--
|
--
|
||||||
-- -- And here we create a new WorkplaceTask, using the :AddTransportTask method of the TaskDispatcher.
|
-- -- And here we create a new WorkplaceTask, using the :AddTransportTask method of the TaskDispatcher.
|
||||||
-- local WorkplaceTask = TaskDispatcher:AddTransportTask( "Build a Workplace", CargoSetWorkmaterials, "Transport the workers, engineers and the equipment near the Workplace." )
|
-- local WorkplaceTask = TaskDispatcher:AddTransportTask( "Build a Workplace", CargoSetWorkmaterials, "Transport the workers, engineers and the equipment near the Workplace." )
|
||||||
-- TaskDispatcher:SetTransportDeployZone( WorkplaceTask, ZONE:New( "Workplace" ) )
|
-- TaskDispatcher:SetTransportDeployZone( WorkplaceTask, ZONE:New( "Workplace" ) )
|
||||||
--
|
--
|
||||||
-- # 3) Handle cargo task events.
|
-- # 3) Handle cargo task events.
|
||||||
--
|
--
|
||||||
@@ -189,7 +189,7 @@ do -- TASK_CARGO_TRANSPORT
|
|||||||
-- In order to properly capture the events and avoid mistakes using the documentation, it is advised that you execute the following actions:
|
-- In order to properly capture the events and avoid mistakes using the documentation, it is advised that you execute the following actions:
|
||||||
--
|
--
|
||||||
-- * **Copy / Paste** the code section into your script.
|
-- * **Copy / Paste** the code section into your script.
|
||||||
-- * **Change** the CLASS literal to the task object name you have in your script.
|
-- * **Change** the "myclass" literal to the task object name you have in your script.
|
||||||
-- * Within the function, you can now **write your own code**!
|
-- * Within the function, you can now **write your own code**!
|
||||||
-- * **IntelliSense** will recognize the type of the variables provided by the function. Note: the From, Event and To variables can be safely ignored,
|
-- * **IntelliSense** will recognize the type of the variables provided by the function. Note: the From, Event and To variables can be safely ignored,
|
||||||
-- but you need to declare them as they are automatically provided by the event handling system of MOOSE.
|
-- but you need to declare them as they are automatically provided by the event handling system of MOOSE.
|
||||||
@@ -210,14 +210,13 @@ do -- TASK_CARGO_TRANSPORT
|
|||||||
-- If you want to code your own event handler, use this code fragment to tailor the event when a player carrier has picked up a cargo object in the CarrierGroup.
|
-- If you want to code your own event handler, use this code fragment to tailor the event when a player carrier has picked up a cargo object in the CarrierGroup.
|
||||||
-- You can use this event handler to post messages to players, or provide status updates etc.
|
-- You can use this event handler to post messages to players, or provide status updates etc.
|
||||||
--
|
--
|
||||||
-- --- CargoPickedUp event handler OnAfter for CLASS.
|
-- --- CargoPickedUp event handler OnAfter for "myclass".
|
||||||
-- -- @param #CLASS self
|
|
||||||
-- -- @param #string From A string that contains the "*from state name*" when the event was triggered.
|
-- -- @param #string From A string that contains the "*from state name*" when the event was triggered.
|
||||||
-- -- @param #string Event A string that contains the "*event name*" when the event was triggered.
|
-- -- @param #string Event A string that contains the "*event name*" when the event was triggered.
|
||||||
-- -- @param #string To A string that contains the "*to state name*" when the event was triggered.
|
-- -- @param #string To A string that contains the "*to state name*" when the event was triggered.
|
||||||
-- -- @param Wrapper.Unit#UNIT TaskUnit The unit (client) of the player that has picked up the cargo.
|
-- -- @param Wrapper.Unit#UNIT TaskUnit The unit (client) of the player that has picked up the cargo.
|
||||||
-- -- @param Cargo.Cargo#CARGO Cargo The cargo object that has been picked up. Note that this can be a CARGO_GROUP, CARGO_CRATE or CARGO_SLINGLOAD object!
|
-- -- @param Cargo.Cargo#CARGO Cargo The cargo object that has been picked up. Note that this can be a CARGO_GROUP, CARGO_CRATE or CARGO_SLINGLOAD object!
|
||||||
-- function CLASS:OnAfterCargoPickedUp( From, Event, To, TaskUnit, Cargo )
|
-- function myclass:OnAfterCargoPickedUp( From, Event, To, TaskUnit, Cargo )
|
||||||
--
|
--
|
||||||
-- -- Write here your own code.
|
-- -- Write here your own code.
|
||||||
--
|
--
|
||||||
@@ -240,15 +239,14 @@ do -- TASK_CARGO_TRANSPORT
|
|||||||
-- You can use this event handler to post messages to players, or provide status updates etc.
|
-- You can use this event handler to post messages to players, or provide status updates etc.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- --- CargoDeployed event handler OnAfter for CLASS.
|
-- --- CargoDeployed event handler OnAfter foR "myclass".
|
||||||
-- -- @param #CLASS self
|
|
||||||
-- -- @param #string From A string that contains the "*from state name*" when the event was triggered.
|
-- -- @param #string From A string that contains the "*from state name*" when the event was triggered.
|
||||||
-- -- @param #string Event A string that contains the "*event name*" when the event was triggered.
|
-- -- @param #string Event A string that contains the "*event name*" when the event was triggered.
|
||||||
-- -- @param #string To A string that contains the "*to state name*" when the event was triggered.
|
-- -- @param #string To A string that contains the "*to state name*" when the event was triggered.
|
||||||
-- -- @param Wrapper.Unit#UNIT TaskUnit The unit (client) of the player that has deployed the cargo.
|
-- -- @param Wrapper.Unit#UNIT TaskUnit The unit (client) of the player that has deployed the cargo.
|
||||||
-- -- @param Cargo.Cargo#CARGO Cargo The cargo object that has been deployed. Note that this can be a CARGO_GROUP, CARGO_CRATE or CARGO_SLINGLOAD object!
|
-- -- @param Cargo.Cargo#CARGO Cargo The cargo object that has been deployed. Note that this can be a CARGO_GROUP, CARGO_CRATE or CARGO_SLINGLOAD object!
|
||||||
-- -- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
-- -- @param Core.Zone#ZONE DeployZone The zone wherein the cargo is deployed. This can be any zone type, like a ZONE, ZONE_GROUP, ZONE_AIRBASE.
|
||||||
-- function CLASS:OnAfterCargoDeployed( From, Event, To, TaskUnit, Cargo, DeployZone )
|
-- function myclass:OnAfterCargoDeployed( From, Event, To, TaskUnit, Cargo, DeployZone )
|
||||||
--
|
--
|
||||||
-- -- Write here your own code.
|
-- -- Write here your own code.
|
||||||
--
|
--
|
||||||
|
|||||||
@@ -497,7 +497,7 @@ ENUMS.ReportingName =
|
|||||||
Mudhen = "F-15E",
|
Mudhen = "F-15E",
|
||||||
Viper = "F-16",
|
Viper = "F-16",
|
||||||
Phantom = "F-4E",
|
Phantom = "F-4E",
|
||||||
Tiger = "F-5", -- was thinking to name this MiG-25 ;)
|
Tiger = "F-5", -- was thinkg to name this MiG-25 ;)
|
||||||
Sabre = "F-86",
|
Sabre = "F-86",
|
||||||
Hornet = "A-18", -- avoiding the slash
|
Hornet = "A-18", -- avoiding the slash
|
||||||
Hawk = "Hawk",
|
Hawk = "Hawk",
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ do
|
|||||||
-- @type FIFO
|
-- @type FIFO
|
||||||
-- @field #string ClassName Name of the class.
|
-- @field #string ClassName Name of the class.
|
||||||
-- @field #string lid Class id string for output to DCS log file.
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
-- @field #string version Version of FiFo
|
-- @field #string version Version of FiFo.
|
||||||
-- @field #number counter
|
-- @field #number counter Counter.
|
||||||
-- @field #number pointer
|
-- @field #number pointer Pointer.
|
||||||
-- @field #table stackbypointer
|
-- @field #table stackbypointer Stack by pointer.
|
||||||
-- @field #table stackbyid
|
-- @field #table stackbyid Stack by ID.
|
||||||
-- @extends Core.Base#BASE
|
-- @extends Core.Base#BASE
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -45,12 +45,12 @@ FIFO = {
|
|||||||
stackbyid = {}
|
stackbyid = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Instantiate a new FIFO Stack
|
--- Instantiate a new FIFO Stack.
|
||||||
-- @param #FIFO self
|
-- @param #FIFO self
|
||||||
-- @return #FIFO self
|
-- @return #FIFO self
|
||||||
function FIFO:New()
|
function FIFO:New()
|
||||||
-- Inherit everything from BASE class.
|
-- Inherit everything from BASE class.
|
||||||
local self=BASE:Inherit(self, BASE:New())
|
local self=BASE:Inherit(self, BASE:New()) --#FIFO
|
||||||
self.pointer = 0
|
self.pointer = 0
|
||||||
self.counter = 0
|
self.counter = 0
|
||||||
self.stackbypointer = {}
|
self.stackbypointer = {}
|
||||||
@@ -62,7 +62,7 @@ function FIFO:New()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Empty FIFO Stack
|
--- Empty FIFO Stack.
|
||||||
-- @param #FIFO self
|
-- @param #FIFO self
|
||||||
-- @return #FIFO self
|
-- @return #FIFO self
|
||||||
function FIFO:Clear()
|
function FIFO:Clear()
|
||||||
@@ -77,7 +77,7 @@ function FIFO:Clear()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- FIFO Push Object to Stack
|
--- FIFO Push Object to Stack.
|
||||||
-- @param #FIFO self
|
-- @param #FIFO self
|
||||||
-- @param #table Object
|
-- @param #table Object
|
||||||
-- @param #string UniqueID (optional) - will default to current pointer + 1. Note - if you intend to use `FIFO:GetIDStackSorted()` keep the UniqueID numerical!
|
-- @param #string UniqueID (optional) - will default to current pointer + 1. Note - if you intend to use `FIFO:GetIDStackSorted()` keep the UniqueID numerical!
|
||||||
@@ -97,7 +97,7 @@ function FIFO:Push(Object,UniqueID)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--- FIFO Pull Object from Stack
|
--- FIFO Pull Object from Stack.
|
||||||
-- @param #FIFO self
|
-- @param #FIFO self
|
||||||
-- @return #table Object or nil if stack is empty
|
-- @return #table Object or nil if stack is empty
|
||||||
function FIFO:Pull()
|
function FIFO:Pull()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-- ### Author: **TAW CougarNL**, *funkyfranky*
|
-- ### Author: **TAW CougarNL**, *funkyfranky*
|
||||||
--
|
--
|
||||||
-- @module Utilities.PROFILER
|
-- @module Utilities.PROFILER
|
||||||
-- @image MOOSE.JPG
|
-- @image Utils_Profiler.jpg
|
||||||
|
|
||||||
--- PROFILER class.
|
--- PROFILER class.
|
||||||
-- @type PROFILER
|
-- @type PROFILER
|
||||||
@@ -24,7 +24,8 @@
|
|||||||
-- @field #number ThreshTtot Total time threshold. Only write output if total function CPU time is more than this value.
|
-- @field #number ThreshTtot Total time threshold. Only write output if total function CPU time is more than this value.
|
||||||
-- @field #string fileNamePrefix Output file name prefix, e.g. "MooseProfiler".
|
-- @field #string fileNamePrefix Output file name prefix, e.g. "MooseProfiler".
|
||||||
-- @field #string fileNameSuffix Output file name prefix, e.g. "txt"
|
-- @field #string fileNameSuffix Output file name prefix, e.g. "txt"
|
||||||
--- *The emperor counsels simplicity. First principles. Of each particular thing, ask: What is it in itself, in its own constitution? What is its causal nature? *
|
|
||||||
|
--- *The emperor counsels simplicity.* *First principles. Of each particular thing, ask: What is it in itself, in its own constitution? What is its causal nature?*
|
||||||
--
|
--
|
||||||
-- ===
|
-- ===
|
||||||
--
|
--
|
||||||
@@ -33,11 +34,24 @@
|
|||||||
-- # The PROFILER Concept
|
-- # The PROFILER Concept
|
||||||
--
|
--
|
||||||
-- Profile your lua code. This tells you, which functions are called very often and which consume most real time.
|
-- Profile your lua code. This tells you, which functions are called very often and which consume most real time.
|
||||||
-- With this information you can optimize the performance of your code.
|
-- With this information you can optimize the perfomance of your code.
|
||||||
--
|
--
|
||||||
-- # Prerequisites
|
-- # Prerequisites
|
||||||
--
|
--
|
||||||
-- The modules **os** and **lfs** need to be de-sanitized.
|
-- The modules **os**, **io** and **lfs** need to be desanizied. Comment out the lines
|
||||||
|
--
|
||||||
|
-- --sanitizeModule('os')
|
||||||
|
-- --sanitizeModule('io')
|
||||||
|
-- --sanitizeModule('lfs')
|
||||||
|
--
|
||||||
|
-- in your *"DCS World OpenBeta/Scripts/MissionScripting.lua"* file.
|
||||||
|
--
|
||||||
|
-- But be aware that these changes can make you system vulnerable to attacks.
|
||||||
|
--
|
||||||
|
-- # Disclaimer
|
||||||
|
--
|
||||||
|
-- **Profiling itself is CPU expensive!** Don't use this when you want to fly or host a mission.
|
||||||
|
--
|
||||||
--
|
--
|
||||||
-- # Start
|
-- # Start
|
||||||
--
|
--
|
||||||
@@ -123,12 +137,12 @@ function PROFILER.Start( Delay, Duration )
|
|||||||
go = false
|
go = false
|
||||||
end
|
end
|
||||||
if not io then
|
if not io then
|
||||||
env.error( "ERROR: Profiler needs io to be de-sanitized!" )
|
env.error("ERROR: Profiler needs io to be desanitized!")
|
||||||
go = false
|
go=false
|
||||||
end
|
end
|
||||||
if not lfs then
|
if not lfs then
|
||||||
env.error( "ERROR: Profiler needs lfs to be de-sanitized!" )
|
env.error("ERROR: Profiler needs lfs to be desanitized!")
|
||||||
go = false
|
go=false
|
||||||
end
|
end
|
||||||
if not go then
|
if not go then
|
||||||
return
|
return
|
||||||
@@ -139,11 +153,11 @@ function PROFILER.Start( Delay, Duration )
|
|||||||
else
|
else
|
||||||
|
|
||||||
-- Set start time.
|
-- Set start time.
|
||||||
PROFILER.TstartGame = timer.getTime()
|
PROFILER.TstartGame=timer.getTime()
|
||||||
PROFILER.TstartOS = os.clock()
|
PROFILER.TstartOS=os.clock()
|
||||||
|
|
||||||
-- Add event handler.
|
-- Add event handler.
|
||||||
world.addEventHandler( PROFILER.eventHandler )
|
world.addEventHandler(PROFILER.eventHandler)
|
||||||
|
|
||||||
-- Info in log.
|
-- Info in log.
|
||||||
env.info( '############################ Profiler Started ############################' )
|
env.info( '############################ Profiler Started ############################' )
|
||||||
@@ -152,18 +166,19 @@ function PROFILER.Start( Delay, Duration )
|
|||||||
else
|
else
|
||||||
env.info( string.format( "- Will be stopped when mission ends" ) )
|
env.info( string.format( "- Will be stopped when mission ends" ) )
|
||||||
end
|
end
|
||||||
env.info( string.format( "- Calls per second threshold %.3f/sec", PROFILER.ThreshCPS ) )
|
env.info(string.format("- Calls per second threshold %.3f/sec", PROFILER.ThreshCPS))
|
||||||
env.info( string.format( "- Total function time threshold %.3f sec", PROFILER.ThreshTtot ) )
|
env.info(string.format("- Total function time threshold %.3f sec", PROFILER.ThreshTtot))
|
||||||
env.info( string.format( "- Output file \"%s\" in your DCS log file folder", PROFILER.getfilename( PROFILER.fileNameSuffix ) ) )
|
env.info(string.format("- Output file \"%s\" in your DCS log file folder", PROFILER.getfilename(PROFILER.fileNameSuffix)))
|
||||||
env.info( string.format( "- Output file \"%s\" in CSV format", PROFILER.getfilename( "csv" ) ) )
|
env.info(string.format("- Output file \"%s\" in CSV format", PROFILER.getfilename("csv")))
|
||||||
env.info( '###############################################################################' )
|
env.info('###############################################################################')
|
||||||
|
|
||||||
|
|
||||||
-- Message on screen
|
-- Message on screen
|
||||||
local duration = Duration or 600
|
local duration=Duration or 600
|
||||||
trigger.action.outText( "### Profiler running ###", duration )
|
trigger.action.outText("### Profiler running ###", duration)
|
||||||
|
|
||||||
-- Set hook.
|
-- Set hook.
|
||||||
debug.sethook( PROFILER.hook, "cr" )
|
debug.sethook(PROFILER.hook, "cr")
|
||||||
|
|
||||||
-- Auto stop profiler.
|
-- Auto stop profiler.
|
||||||
if Duration then
|
if Duration then
|
||||||
@@ -181,20 +196,29 @@ function PROFILER.Stop( Delay )
|
|||||||
if Delay and Delay > 0 then
|
if Delay and Delay > 0 then
|
||||||
|
|
||||||
BASE:ScheduleOnce( Delay, PROFILER.Stop )
|
BASE:ScheduleOnce( Delay, PROFILER.Stop )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function PROFILER.Stop(Delay)
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
|
||||||
|
BASE:ScheduleOnce(Delay, PROFILER.Stop)
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
-- Remove hook.
|
-- Remove hook.
|
||||||
debug.sethook()
|
debug.sethook()
|
||||||
|
|
||||||
|
|
||||||
-- Run time game.
|
-- Run time game.
|
||||||
local runTimeGame = timer.getTime() - PROFILER.TstartGame
|
local runTimeGame=timer.getTime()-PROFILER.TstartGame
|
||||||
|
|
||||||
-- Run time real OS.
|
-- Run time real OS.
|
||||||
local runTimeOS = os.clock() - PROFILER.TstartOS
|
local runTimeOS=os.clock()-PROFILER.TstartOS
|
||||||
|
|
||||||
-- Show info.
|
-- Show info.
|
||||||
PROFILER.showInfo( runTimeGame, runTimeOS )
|
PROFILER.showInfo(runTimeGame, runTimeOS)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -213,34 +237,34 @@ end
|
|||||||
|
|
||||||
--- Debug hook.
|
--- Debug hook.
|
||||||
-- @param #table event Event.
|
-- @param #table event Event.
|
||||||
function PROFILER.hook( event )
|
function PROFILER.hook(event)
|
||||||
|
|
||||||
local f = debug.getinfo( 2, "f" ).func
|
local f=debug.getinfo(2, "f").func
|
||||||
|
|
||||||
if event == 'call' then
|
if event=='call' then
|
||||||
|
|
||||||
if PROFILER.Counters[f] == nil then
|
if PROFILER.Counters[f]==nil then
|
||||||
|
|
||||||
PROFILER.Counters[f] = 1
|
PROFILER.Counters[f]=1
|
||||||
PROFILER.dInfo[f] = debug.getinfo( 2, "Sn" )
|
PROFILER.dInfo[f]=debug.getinfo(2,"Sn")
|
||||||
|
|
||||||
if PROFILER.fTimeTotal[f] == nil then
|
if PROFILER.fTimeTotal[f]==nil then
|
||||||
PROFILER.fTimeTotal[f] = 0
|
PROFILER.fTimeTotal[f]=0
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
PROFILER.Counters[f] = PROFILER.Counters[f] + 1
|
PROFILER.Counters[f] = PROFILER.Counters[f] + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
if PROFILER.fTime[f] == nil then
|
if PROFILER.fTime[f]==nil then
|
||||||
PROFILER.fTime[f] = os.clock()
|
PROFILER.fTime[f]=os.clock()
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif (event == 'return') then
|
elseif (event=='return') then
|
||||||
|
|
||||||
if PROFILER.fTime[f] ~= nil then
|
if PROFILER.fTime[f]~=nil then
|
||||||
PROFILER.fTimeTotal[f] = PROFILER.fTimeTotal[f] + (os.clock() - PROFILER.fTime[f])
|
PROFILER.fTimeTotal[f]=PROFILER.fTimeTotal[f]+(os.clock()-PROFILER.fTime[f])
|
||||||
PROFILER.fTime[f] = nil
|
PROFILER.fTime[f]=nil
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -259,9 +283,9 @@ end
|
|||||||
-- @return #number Function time in seconds.
|
-- @return #number Function time in seconds.
|
||||||
function PROFILER.getData( func )
|
function PROFILER.getData( func )
|
||||||
|
|
||||||
local n = PROFILER.dInfo[func]
|
local n=PROFILER.dInfo[func]
|
||||||
|
|
||||||
if n.what == "C" then
|
if n.what=="C" then
|
||||||
return n.name, "?", "?", PROFILER.fTimeTotal[func]
|
return n.name, "?", "?", PROFILER.fTimeTotal[func]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -282,20 +306,20 @@ end
|
|||||||
function PROFILER.showTable( data, f, runTimeGame )
|
function PROFILER.showTable( data, f, runTimeGame )
|
||||||
|
|
||||||
-- Loop over data.
|
-- Loop over data.
|
||||||
for i = 1, #data do
|
for i=1, #data do
|
||||||
local t = data[i] -- #PROFILER.Data
|
local t=data[i] --#PROFILER.Data
|
||||||
|
|
||||||
-- Calls per second.
|
-- Calls per second.
|
||||||
local cps = t.count / runTimeGame
|
local cps=t.count/runTimeGame
|
||||||
|
|
||||||
local threshCPS = cps >= PROFILER.ThreshCPS
|
local threshCPS=cps>=PROFILER.ThreshCPS
|
||||||
local threshTot = t.tm >= PROFILER.ThreshTtot
|
local threshTot=t.tm>=PROFILER.ThreshTtot
|
||||||
|
|
||||||
if threshCPS and threshTot then
|
if threshCPS and threshTot then
|
||||||
|
|
||||||
-- Output
|
-- Output
|
||||||
local text = string.format( "%30s: %8d calls %8.1f/sec - Time Total %8.3f sec (%.3f %%) %5.3f sec/call %s line %s", t.func, t.count, cps, t.tm, t.tm / runTimeGame * 100, t.tm / t.count, tostring( t.src ), tostring( t.line ) )
|
local text=string.format("%30s: %8d calls %8.1f/sec - Time Total %8.3f sec (%.3f %%) %5.3f sec/call %s line %s", t.func, t.count, cps, t.tm, t.tm/runTimeGame*100, t.tm/t.count, tostring(t.src), tostring(t.line))
|
||||||
PROFILER._flog( f, text )
|
PROFILER._flog(f, text)
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -312,19 +336,19 @@ function PROFILER.printCSV( data, runTimeGame )
|
|||||||
local g = io.open( file, 'w' )
|
local g = io.open( file, 'w' )
|
||||||
|
|
||||||
-- Header.
|
-- Header.
|
||||||
local text = "Function,Total Calls,Calls per Sec,Total Time,Total in %,Sec per Call,Source File;Line Number,"
|
local text="Function,Total Calls,Calls per Sec,Total Time,Total in %,Sec per Call,Source File;Line Number,"
|
||||||
g:write( text .. "\r\n" )
|
g:write(text.."\r\n")
|
||||||
|
|
||||||
-- Loop over data.
|
-- Loop over data.
|
||||||
for i = 1, #data do
|
for i=1, #data do
|
||||||
local t = data[i] -- #PROFILER.Data
|
local t=data[i] --#PROFILER.Data
|
||||||
|
|
||||||
-- Calls per second.
|
-- Calls per second.
|
||||||
local cps = t.count / runTimeGame
|
local cps = t.count / runTimeGame
|
||||||
|
|
||||||
-- Output
|
-- Output
|
||||||
local txt = string.format( "%s,%d,%.1f,%.3f,%.3f,%.3f,%s,%s,", t.func, t.count, cps, t.tm, t.tm / runTimeGame * 100, t.tm / t.count, tostring( t.src ), tostring( t.line ) )
|
local txt=string.format("%s,%d,%.1f,%.3f,%.3f,%.3f,%s,%s,", t.func, t.count, cps, t.tm, t.tm/runTimeGame*100, t.tm/t.count, tostring(t.src), tostring(t.line))
|
||||||
g:write( txt .. "\r\n" )
|
g:write(txt.."\r\n")
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -335,15 +359,15 @@ end
|
|||||||
--- Write info to output file.
|
--- Write info to output file.
|
||||||
-- @param #string ext Extension.
|
-- @param #string ext Extension.
|
||||||
-- @return #string File name.
|
-- @return #string File name.
|
||||||
function PROFILER.getfilename( ext )
|
function PROFILER.getfilename(ext)
|
||||||
|
|
||||||
local dir = lfs.writedir() .. [[Logs\]]
|
local dir=lfs.writedir()..[[Logs\]]
|
||||||
|
|
||||||
ext = ext or PROFILER.fileNameSuffix
|
ext=ext or PROFILER.fileNameSuffix
|
||||||
|
|
||||||
local file = dir .. PROFILER.fileNamePrefix .. "." .. ext
|
local file=dir..PROFILER.fileNamePrefix.."."..ext
|
||||||
|
|
||||||
if not UTILS.FileExists( file ) then
|
if not UTILS.FileExists(file) then
|
||||||
return file
|
return file
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -365,34 +389,39 @@ end
|
|||||||
function PROFILER.showInfo( runTimeGame, runTimeOS )
|
function PROFILER.showInfo( runTimeGame, runTimeOS )
|
||||||
|
|
||||||
-- Output file.
|
-- Output file.
|
||||||
local file = PROFILER.getfilename( PROFILER.fileNameSuffix )
|
local file=PROFILER.getfilename(PROFILER.fileNameSuffix)
|
||||||
local f = io.open( file, 'w' )
|
local f=io.open(file, 'w')
|
||||||
|
|
||||||
-- Gather data.
|
-- Gather data.
|
||||||
local Ttot = 0
|
local Ttot=0
|
||||||
local Calls = 0
|
local Calls=0
|
||||||
|
|
||||||
local t = {}
|
local t={}
|
||||||
|
|
||||||
local tcopy = nil -- #PROFILER.Data
|
local tcopy=nil --#PROFILER.Data
|
||||||
local tserialize = nil -- #PROFILER.Data
|
local tserialize=nil --#PROFILER.Data
|
||||||
local tforgen = nil -- #PROFILER.Data
|
local tforgen=nil --#PROFILER.Data
|
||||||
local tpairs = nil -- #PROFILER.Data
|
local tpairs=nil --#PROFILER.Data
|
||||||
|
|
||||||
for func, count in pairs( PROFILER.Counters ) do
|
|
||||||
|
|
||||||
local s, src, line, tm = PROFILER.getData( func )
|
for func, count in pairs(PROFILER.Counters) do
|
||||||
|
|
||||||
if PROFILER.logUnknown == true then
|
local s,src,line,tm=PROFILER.getData(func)
|
||||||
if s == nil then
|
|
||||||
s = "<Unknown>"
|
if PROFILER.logUnknown==true then
|
||||||
end
|
if s==nil then s="<Unknown>" end
|
||||||
end
|
end
|
||||||
|
|
||||||
if s ~= nil then
|
if s~=nil then
|
||||||
|
|
||||||
-- Profile data.
|
-- Profile data.
|
||||||
local T = { func = s, src = src, line = line, count = count, tm = tm } -- #PROFILER.Data
|
local T=
|
||||||
|
{ func=s,
|
||||||
|
src=src,
|
||||||
|
line=line,
|
||||||
|
count=count,
|
||||||
|
tm=tm,
|
||||||
|
} --#PROFILER.Data
|
||||||
|
|
||||||
-- Collect special cases. Somehow, e.g. "_copy" appears multiple times so we try to gather all data.
|
-- Collect special cases. Somehow, e.g. "_copy" appears multiple times so we try to gather all data.
|
||||||
if s == "_copy" then
|
if s == "_copy" then
|
||||||
@@ -406,32 +435,32 @@ function PROFILER.showInfo( runTimeGame, runTimeOS )
|
|||||||
if tserialize == nil then
|
if tserialize == nil then
|
||||||
tserialize = T
|
tserialize = T
|
||||||
else
|
else
|
||||||
tserialize.count = tserialize.count + T.count
|
tserialize.count=tserialize.count+T.count
|
||||||
tserialize.tm = tserialize.tm + T.tm
|
tserialize.tm=tserialize.tm+T.tm
|
||||||
end
|
end
|
||||||
elseif s == "(for generator)" then
|
elseif s=="(for generator)" then
|
||||||
if tforgen == nil then
|
if tforgen==nil then
|
||||||
tforgen = T
|
tforgen=T
|
||||||
else
|
else
|
||||||
tforgen.count = tforgen.count + T.count
|
tforgen.count=tforgen.count+T.count
|
||||||
tforgen.tm = tforgen.tm + T.tm
|
tforgen.tm=tforgen.tm+T.tm
|
||||||
end
|
end
|
||||||
elseif s == "pairs" then
|
elseif s=="pairs" then
|
||||||
if tpairs == nil then
|
if tpairs==nil then
|
||||||
tpairs = T
|
tpairs=T
|
||||||
else
|
else
|
||||||
tpairs.count = tpairs.count + T.count
|
tpairs.count=tpairs.count+T.count
|
||||||
tpairs.tm = tpairs.tm + T.tm
|
tpairs.tm=tpairs.tm+T.tm
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
table.insert( t, T )
|
table.insert( t, T )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Total function time.
|
-- Total function time.
|
||||||
Ttot = Ttot + tm
|
Ttot=Ttot+tm
|
||||||
|
|
||||||
-- Total number of calls.
|
-- Total number of calls.
|
||||||
Calls = Calls + count
|
Calls=Calls+count
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -442,83 +471,77 @@ function PROFILER.showInfo( runTimeGame, runTimeOS )
|
|||||||
table.insert( t, tcopy )
|
table.insert( t, tcopy )
|
||||||
end
|
end
|
||||||
if tserialize then
|
if tserialize then
|
||||||
table.insert( t, tserialize )
|
table.insert(t, tserialize)
|
||||||
end
|
end
|
||||||
if tforgen then
|
if tforgen then
|
||||||
table.insert( t, tforgen )
|
table.insert( t, tforgen )
|
||||||
end
|
end
|
||||||
if tpairs then
|
if tpairs then
|
||||||
table.insert( t, tpairs )
|
table.insert(t, tpairs)
|
||||||
end
|
end
|
||||||
|
|
||||||
env.info( '############################ Profiler Stopped ############################' )
|
env.info('############################ Profiler Stopped ############################')
|
||||||
env.info( string.format( "* Runtime Game : %s = %d sec", UTILS.SecondsToClock( runTimeGame, true ), runTimeGame ) )
|
env.info(string.format("* Runtime Game : %s = %d sec", UTILS.SecondsToClock(runTimeGame, true), runTimeGame))
|
||||||
env.info( string.format( "* Runtime Real : %s = %d sec", UTILS.SecondsToClock( runTimeOS, true ), runTimeOS ) )
|
env.info(string.format("* Runtime Real : %s = %d sec", UTILS.SecondsToClock(runTimeOS, true), runTimeOS))
|
||||||
env.info( string.format( "* Function time : %s = %.1f sec (%.1f percent of runtime game)", UTILS.SecondsToClock( Ttot, true ), Ttot, Ttot / runTimeGame * 100 ) )
|
env.info(string.format("* Function time : %s = %.1f sec (%.1f percent of runtime game)", UTILS.SecondsToClock(Ttot, true), Ttot, Ttot/runTimeGame*100))
|
||||||
env.info( string.format( "* Total functions : %d", #t ) )
|
env.info(string.format("* Total functions : %d", #t))
|
||||||
env.info( string.format( "* Total func calls : %d", Calls ) )
|
env.info(string.format("* Total func calls : %d", Calls))
|
||||||
env.info( string.format( "* Writing to file : \"%s\"", file ) )
|
env.info(string.format("* Writing to file : \"%s\"", file))
|
||||||
env.info( string.format( "* Writing to file : \"%s\"", PROFILER.getfilename( "csv" ) ) )
|
env.info(string.format("* Writing to file : \"%s\"", PROFILER.getfilename("csv")))
|
||||||
env.info( "##############################################################################" )
|
env.info("##############################################################################")
|
||||||
|
|
||||||
-- Sort by total time.
|
-- Sort by total time.
|
||||||
table.sort( t, function( a, b )
|
table.sort(t, function(a,b) return a.tm>b.tm end)
|
||||||
return a.tm > b.tm
|
|
||||||
end )
|
|
||||||
|
|
||||||
-- Write data.
|
-- Write data.
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER._flog( f, "-------------------------" )
|
PROFILER._flog(f,"-------------------------")
|
||||||
PROFILER._flog( f, "---- Profiler Report ----" )
|
PROFILER._flog(f,"---- Profiler Report ----")
|
||||||
PROFILER._flog( f, "-------------------------" )
|
PROFILER._flog(f,"-------------------------")
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER._flog( f, string.format( "* Runtime Game : %s = %.1f sec", UTILS.SecondsToClock( runTimeGame, true ), runTimeGame ) )
|
PROFILER._flog(f,string.format("* Runtime Game : %s = %.1f sec", UTILS.SecondsToClock(runTimeGame, true), runTimeGame))
|
||||||
PROFILER._flog( f, string.format( "* Runtime Real : %s = %.1f sec", UTILS.SecondsToClock( runTimeOS, true ), runTimeOS ) )
|
PROFILER._flog(f,string.format("* Runtime Real : %s = %.1f sec", UTILS.SecondsToClock(runTimeOS, true), runTimeOS))
|
||||||
PROFILER._flog( f, string.format( "* Function time : %s = %.1f sec (%.1f %% of runtime game)", UTILS.SecondsToClock( Ttot, true ), Ttot, Ttot / runTimeGame * 100 ) )
|
PROFILER._flog(f,string.format("* Function time : %s = %.1f sec (%.1f %% of runtime game)", UTILS.SecondsToClock(Ttot, true), Ttot, Ttot/runTimeGame*100))
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER._flog( f, string.format( "* Total functions = %d", #t ) )
|
PROFILER._flog(f,string.format("* Total functions = %d", #t))
|
||||||
PROFILER._flog( f, string.format( "* Total func calls = %d", Calls ) )
|
PROFILER._flog(f,string.format("* Total func calls = %d", Calls))
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER._flog( f, string.format( "* Calls per second threshold = %.3f/sec", PROFILER.ThreshCPS ) )
|
PROFILER._flog(f,string.format("* Calls per second threshold = %.3f/sec", PROFILER.ThreshCPS))
|
||||||
PROFILER._flog( f, string.format( "* Total func time threshold = %.3f sec", PROFILER.ThreshTtot ) )
|
PROFILER._flog(f,string.format("* Total func time threshold = %.3f sec", PROFILER.ThreshTtot))
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER.showTable( t, f, runTimeGame )
|
PROFILER.showTable(t, f, runTimeGame)
|
||||||
|
|
||||||
-- Sort by number of calls.
|
-- Sort by number of calls.
|
||||||
table.sort( t, function( a, b )
|
table.sort(t, function(a,b) return a.tm/a.count>b.tm/b.count end)
|
||||||
return a.tm / a.count > b.tm / b.count
|
|
||||||
end )
|
|
||||||
|
|
||||||
-- Detailed data.
|
-- Detailed data.
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER._flog( f, "--------------------------------------" )
|
PROFILER._flog(f,"--------------------------------------")
|
||||||
PROFILER._flog( f, "---- Data Sorted by Time per Call ----" )
|
PROFILER._flog(f,"---- Data Sorted by Time per Call ----")
|
||||||
PROFILER._flog( f, "--------------------------------------" )
|
PROFILER._flog(f,"--------------------------------------")
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER.showTable( t, f, runTimeGame )
|
PROFILER.showTable(t, f, runTimeGame)
|
||||||
|
|
||||||
-- Sort by number of calls.
|
-- Sort by number of calls.
|
||||||
table.sort( t, function( a, b )
|
table.sort(t, function(a,b) return a.count>b.count end)
|
||||||
return a.count > b.count
|
|
||||||
end )
|
|
||||||
|
|
||||||
-- Detailed data.
|
-- Detailed data.
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER._flog( f, "************************************************************************************************************************" )
|
PROFILER._flog(f,"************************************************************************************************************************")
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER._flog( f, "------------------------------------" )
|
PROFILER._flog(f,"------------------------------------")
|
||||||
PROFILER._flog( f, "---- Data Sorted by Total Calls ----" )
|
PROFILER._flog(f,"---- Data Sorted by Total Calls ----")
|
||||||
PROFILER._flog( f, "------------------------------------" )
|
PROFILER._flog(f,"------------------------------------")
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog(f,"")
|
||||||
PROFILER.showTable( t, f, runTimeGame )
|
PROFILER.showTable(t, f, runTimeGame)
|
||||||
|
|
||||||
-- Closing.
|
-- Closing.
|
||||||
PROFILER._flog( f, "" )
|
PROFILER._flog( f, "" )
|
||||||
|
|||||||
@@ -494,330 +494,343 @@ routines.ground = {}
|
|||||||
routines.fixedWing = {}
|
routines.fixedWing = {}
|
||||||
routines.heli = {}
|
routines.heli = {}
|
||||||
|
|
||||||
routines.ground.buildWP = function( point, overRideForm, overRideSpeed )
|
routines.ground.buildWP = function(point, overRideForm, overRideSpeed)
|
||||||
|
|
||||||
local wp = {}
|
local wp = {}
|
||||||
wp.x = point.x
|
wp.x = point.x
|
||||||
|
|
||||||
if point.z then
|
if point.z then
|
||||||
wp.y = point.z
|
wp.y = point.z
|
||||||
else
|
else
|
||||||
wp.y = point.y
|
wp.y = point.y
|
||||||
end
|
end
|
||||||
local form, speed
|
local form, speed
|
||||||
|
|
||||||
if point.speed and not overRideSpeed then
|
if point.speed and not overRideSpeed then
|
||||||
wp.speed = point.speed
|
wp.speed = point.speed
|
||||||
elseif type( overRideSpeed ) == 'number' then
|
elseif type(overRideSpeed) == 'number' then
|
||||||
wp.speed = overRideSpeed
|
wp.speed = overRideSpeed
|
||||||
else
|
else
|
||||||
wp.speed = routines.utils.kmphToMps( 20 )
|
wp.speed = routines.utils.kmphToMps(20)
|
||||||
end
|
end
|
||||||
|
|
||||||
if point.form and not overRideForm then
|
if point.form and not overRideForm then
|
||||||
form = point.form
|
form = point.form
|
||||||
else
|
else
|
||||||
form = overRideForm
|
form = overRideForm
|
||||||
end
|
end
|
||||||
|
|
||||||
if not form then
|
if not form then
|
||||||
wp.action = 'Cone'
|
wp.action = 'Cone'
|
||||||
else
|
else
|
||||||
form = string.lower( form )
|
form = string.lower(form)
|
||||||
if form == 'off_road' or form == 'off road' then
|
if form == 'off_road' or form == 'off road' then
|
||||||
wp.action = 'Off Road'
|
wp.action = 'Off Road'
|
||||||
elseif form == 'on_road' or form == 'on road' then
|
elseif form == 'on_road' or form == 'on road' then
|
||||||
wp.action = 'On Road'
|
wp.action = 'On Road'
|
||||||
elseif form == 'rank' or form == 'line_abrest' or form == 'line abrest' or form == 'lineabrest' then
|
elseif form == 'rank' or form == 'line_abrest' or form == 'line abrest' or form == 'lineabrest'then
|
||||||
wp.action = 'Rank'
|
wp.action = 'Rank'
|
||||||
elseif form == 'cone' then
|
elseif form == 'cone' then
|
||||||
wp.action = 'Cone'
|
wp.action = 'Cone'
|
||||||
elseif form == 'diamond' then
|
elseif form == 'diamond' then
|
||||||
wp.action = 'Diamond'
|
wp.action = 'Diamond'
|
||||||
elseif form == 'vee' then
|
elseif form == 'vee' then
|
||||||
wp.action = 'Vee'
|
wp.action = 'Vee'
|
||||||
elseif form == 'echelon_left' or form == 'echelon left' or form == 'echelonl' then
|
elseif form == 'echelon_left' or form == 'echelon left' or form == 'echelonl' then
|
||||||
wp.action = 'EchelonL'
|
wp.action = 'EchelonL'
|
||||||
elseif form == 'echelon_right' or form == 'echelon right' or form == 'echelonr' then
|
elseif form == 'echelon_right' or form == 'echelon right' or form == 'echelonr' then
|
||||||
wp.action = 'EchelonR'
|
wp.action = 'EchelonR'
|
||||||
else
|
else
|
||||||
wp.action = 'Cone' -- if nothing matched
|
wp.action = 'Cone' -- if nothing matched
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
wp.type = 'Turning Point'
|
||||||
|
|
||||||
|
return wp
|
||||||
|
|
||||||
wp.type = 'Turning Point'
|
|
||||||
return wp
|
|
||||||
end
|
end
|
||||||
|
|
||||||
routines.fixedWing.buildWP = function( point, WPtype, speed, alt, altType )
|
routines.fixedWing.buildWP = function(point, WPtype, speed, alt, altType)
|
||||||
|
|
||||||
local wp = {}
|
local wp = {}
|
||||||
wp.x = point.x
|
wp.x = point.x
|
||||||
|
|
||||||
if point.z then
|
if point.z then
|
||||||
wp.y = point.z
|
wp.y = point.z
|
||||||
else
|
else
|
||||||
wp.y = point.y
|
wp.y = point.y
|
||||||
end
|
end
|
||||||
|
|
||||||
if alt and type( alt ) == 'number' then
|
if alt and type(alt) == 'number' then
|
||||||
wp.alt = alt
|
wp.alt = alt
|
||||||
else
|
else
|
||||||
wp.alt = 2000
|
wp.alt = 2000
|
||||||
end
|
end
|
||||||
|
|
||||||
if altType then
|
if altType then
|
||||||
altType = string.lower( altType )
|
altType = string.lower(altType)
|
||||||
if altType == 'radio' or 'agl' then
|
if altType == 'radio' or 'agl' then
|
||||||
wp.alt_type = 'RADIO'
|
wp.alt_type = 'RADIO'
|
||||||
elseif altType == 'baro' or 'asl' then
|
elseif altType == 'baro' or 'asl' then
|
||||||
wp.alt_type = 'BARO'
|
wp.alt_type = 'BARO'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
wp.alt_type = 'RADIO'
|
wp.alt_type = 'RADIO'
|
||||||
end
|
end
|
||||||
|
|
||||||
if point.speed then
|
if point.speed then
|
||||||
speed = point.speed
|
speed = point.speed
|
||||||
end
|
end
|
||||||
|
|
||||||
if point.type then
|
if point.type then
|
||||||
WPtype = point.type
|
WPtype = point.type
|
||||||
end
|
end
|
||||||
|
|
||||||
if not speed then
|
if not speed then
|
||||||
wp.speed = routines.utils.kmphToMps( 500 )
|
wp.speed = routines.utils.kmphToMps(500)
|
||||||
else
|
else
|
||||||
wp.speed = speed
|
wp.speed = speed
|
||||||
end
|
end
|
||||||
|
|
||||||
if not WPtype then
|
if not WPtype then
|
||||||
wp.action = 'Turning Point'
|
wp.action = 'Turning Point'
|
||||||
else
|
else
|
||||||
WPtype = string.lower( WPtype )
|
WPtype = string.lower(WPtype)
|
||||||
if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then
|
if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then
|
||||||
wp.action = 'Fly Over Point'
|
wp.action = 'Fly Over Point'
|
||||||
elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then
|
elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then
|
||||||
wp.action = 'Turning Point'
|
wp.action = 'Turning Point'
|
||||||
else
|
else
|
||||||
wp.action = 'Turning Point'
|
wp.action = 'Turning Point'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
wp.type = 'Turning Point'
|
wp.type = 'Turning Point'
|
||||||
return wp
|
return wp
|
||||||
end
|
end
|
||||||
|
|
||||||
routines.heli.buildWP = function( point, WPtype, speed, alt, altType )
|
routines.heli.buildWP = function(point, WPtype, speed, alt, altType)
|
||||||
|
|
||||||
local wp = {}
|
local wp = {}
|
||||||
wp.x = point.x
|
wp.x = point.x
|
||||||
|
|
||||||
if point.z then
|
if point.z then
|
||||||
wp.y = point.z
|
wp.y = point.z
|
||||||
else
|
else
|
||||||
wp.y = point.y
|
wp.y = point.y
|
||||||
end
|
end
|
||||||
|
|
||||||
if alt and type( alt ) == 'number' then
|
if alt and type(alt) == 'number' then
|
||||||
wp.alt = alt
|
wp.alt = alt
|
||||||
else
|
else
|
||||||
wp.alt = 500
|
wp.alt = 500
|
||||||
end
|
end
|
||||||
|
|
||||||
if altType then
|
if altType then
|
||||||
altType = string.lower( altType )
|
altType = string.lower(altType)
|
||||||
if altType == 'radio' or 'agl' then
|
if altType == 'radio' or 'agl' then
|
||||||
wp.alt_type = 'RADIO'
|
wp.alt_type = 'RADIO'
|
||||||
elseif altType == 'baro' or 'asl' then
|
elseif altType == 'baro' or 'asl' then
|
||||||
wp.alt_type = 'BARO'
|
wp.alt_type = 'BARO'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
wp.alt_type = 'RADIO'
|
wp.alt_type = 'RADIO'
|
||||||
end
|
end
|
||||||
|
|
||||||
if point.speed then
|
if point.speed then
|
||||||
speed = point.speed
|
speed = point.speed
|
||||||
end
|
end
|
||||||
|
|
||||||
if point.type then
|
if point.type then
|
||||||
WPtype = point.type
|
WPtype = point.type
|
||||||
end
|
end
|
||||||
|
|
||||||
if not speed then
|
if not speed then
|
||||||
wp.speed = routines.utils.kmphToMps( 200 )
|
wp.speed = routines.utils.kmphToMps(200)
|
||||||
else
|
else
|
||||||
wp.speed = speed
|
wp.speed = speed
|
||||||
end
|
end
|
||||||
|
|
||||||
if not WPtype then
|
if not WPtype then
|
||||||
wp.action = 'Turning Point'
|
wp.action = 'Turning Point'
|
||||||
else
|
else
|
||||||
WPtype = string.lower( WPtype )
|
WPtype = string.lower(WPtype)
|
||||||
if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then
|
if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then
|
||||||
wp.action = 'Fly Over Point'
|
wp.action = 'Fly Over Point'
|
||||||
elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then
|
elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then
|
||||||
wp.action = 'Turning Point'
|
wp.action = 'Turning Point'
|
||||||
else
|
else
|
||||||
wp.action = 'Turning Point'
|
wp.action = 'Turning Point'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
wp.type = 'Turning Point'
|
wp.type = 'Turning Point'
|
||||||
return wp
|
return wp
|
||||||
end
|
end
|
||||||
|
|
||||||
routines.groupToRandomPoint = function( vars )
|
routines.groupToRandomPoint = function(vars)
|
||||||
local group = vars.group -- Required
|
local group = vars.group --Required
|
||||||
local point = vars.point -- required
|
local point = vars.point --required
|
||||||
local radius = vars.radius or 0
|
local radius = vars.radius or 0
|
||||||
local innerRadius = vars.innerRadius
|
local innerRadius = vars.innerRadius
|
||||||
local form = vars.form or 'Cone'
|
local form = vars.form or 'Cone'
|
||||||
local heading = vars.heading or math.random() * 2 * math.pi
|
local heading = vars.heading or math.random()*2*math.pi
|
||||||
local headingDegrees = vars.headingDegrees
|
local headingDegrees = vars.headingDegrees
|
||||||
local speed = vars.speed or routines.utils.kmphToMps( 20 )
|
local speed = vars.speed or routines.utils.kmphToMps(20)
|
||||||
|
|
||||||
local useRoads
|
|
||||||
if not vars.disableRoads then
|
|
||||||
useRoads = true
|
|
||||||
else
|
|
||||||
useRoads = false
|
|
||||||
end
|
|
||||||
|
|
||||||
local path = {}
|
local useRoads
|
||||||
|
if not vars.disableRoads then
|
||||||
|
useRoads = true
|
||||||
|
else
|
||||||
|
useRoads = false
|
||||||
|
end
|
||||||
|
|
||||||
if headingDegrees then
|
local path = {}
|
||||||
heading = headingDegrees * math.pi / 180
|
|
||||||
end
|
|
||||||
|
|
||||||
if heading >= 2 * math.pi then
|
if headingDegrees then
|
||||||
heading = heading - 2 * math.pi
|
heading = headingDegrees*math.pi/180
|
||||||
end
|
end
|
||||||
|
|
||||||
local rndCoord = routines.getRandPointInCircle( point, radius, innerRadius )
|
if heading >= 2*math.pi then
|
||||||
|
heading = heading - 2*math.pi
|
||||||
|
end
|
||||||
|
|
||||||
local offset = {}
|
local rndCoord = routines.getRandPointInCircle(point, radius, innerRadius)
|
||||||
local posStart = routines.getLeadPos( group )
|
|
||||||
|
|
||||||
offset.x = routines.utils.round( math.sin( heading - (math.pi / 2) ) * 50 + rndCoord.x, 3 )
|
local offset = {}
|
||||||
offset.z = routines.utils.round( math.cos( heading + (math.pi / 2) ) * 50 + rndCoord.y, 3 )
|
local posStart = routines.getLeadPos(group)
|
||||||
path[#path + 1] = routines.ground.buildWP( posStart, form, speed )
|
|
||||||
|
|
||||||
if useRoads == true and ((point.x - posStart.x) ^ 2 + (point.z - posStart.z) ^ 2) ^ 0.5 > radius * 1.3 then
|
offset.x = routines.utils.round(math.sin(heading - (math.pi/2)) * 50 + rndCoord.x, 3)
|
||||||
path[#path + 1] = routines.ground.buildWP( { ['x'] = posStart.x + 11, ['z'] = posStart.z + 11 }, 'off_road', speed )
|
offset.z = routines.utils.round(math.cos(heading + (math.pi/2)) * 50 + rndCoord.y, 3)
|
||||||
path[#path + 1] = routines.ground.buildWP( posStart, 'on_road', speed )
|
path[#path + 1] = routines.ground.buildWP(posStart, form, speed)
|
||||||
path[#path + 1] = routines.ground.buildWP( offset, 'on_road', speed )
|
|
||||||
else
|
|
||||||
path[#path + 1] = routines.ground.buildWP( { ['x'] = posStart.x + 25, ['z'] = posStart.z + 25 }, form, speed )
|
|
||||||
end
|
|
||||||
|
|
||||||
path[#path + 1] = routines.ground.buildWP( offset, form, speed )
|
|
||||||
path[#path + 1] = routines.ground.buildWP( rndCoord, form, speed )
|
|
||||||
|
|
||||||
routines.goRoute( group, path )
|
if useRoads == true and ((point.x - posStart.x)^2 + (point.z - posStart.z)^2)^0.5 > radius * 1.3 then
|
||||||
|
path[#path + 1] = routines.ground.buildWP({['x'] = posStart.x + 11, ['z'] = posStart.z + 11}, 'off_road', speed)
|
||||||
|
path[#path + 1] = routines.ground.buildWP(posStart, 'on_road', speed)
|
||||||
|
path[#path + 1] = routines.ground.buildWP(offset, 'on_road', speed)
|
||||||
|
else
|
||||||
|
path[#path + 1] = routines.ground.buildWP({['x'] = posStart.x + 25, ['z'] = posStart.z + 25}, form, speed)
|
||||||
|
end
|
||||||
|
|
||||||
|
path[#path + 1] = routines.ground.buildWP(offset, form, speed)
|
||||||
|
path[#path + 1] = routines.ground.buildWP(rndCoord, form, speed)
|
||||||
|
|
||||||
|
routines.goRoute(group, path)
|
||||||
|
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
routines.groupRandomDistSelf = function( gpData, dist, form, heading, speed )
|
routines.groupRandomDistSelf = function(gpData, dist, form, heading, speed)
|
||||||
local pos = routines.getLeadPos( gpData )
|
local pos = routines.getLeadPos(gpData)
|
||||||
local fakeZone = {}
|
local fakeZone = {}
|
||||||
fakeZone.radius = dist or math.random( 300, 1000 )
|
fakeZone.radius = dist or math.random(300, 1000)
|
||||||
fakeZone.point = { x = pos.x, y, pos.y, z = pos.z }
|
fakeZone.point = {x = pos.x, y = pos.y, z = pos.z}
|
||||||
routines.groupToRandomZone( gpData, fakeZone, form, heading, speed )
|
routines.groupToRandomZone(gpData, fakeZone, form, heading, speed)
|
||||||
|
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
routines.groupToRandomZone = function( gpData, zone, form, heading, speed )
|
routines.groupToRandomZone = function(gpData, zone, form, heading, speed)
|
||||||
if type( gpData ) == 'string' then
|
if type(gpData) == 'string' then
|
||||||
gpData = Group.getByName( gpData )
|
gpData = Group.getByName(gpData)
|
||||||
end
|
end
|
||||||
|
|
||||||
if type( zone ) == 'string' then
|
if type(zone) == 'string' then
|
||||||
zone = trigger.misc.getZone( zone )
|
zone = trigger.misc.getZone(zone)
|
||||||
elseif type( zone ) == 'table' and not zone.radius then
|
elseif type(zone) == 'table' and not zone.radius then
|
||||||
zone = trigger.misc.getZone( zone[math.random( 1, #zone )] )
|
zone = trigger.misc.getZone(zone[math.random(1, #zone)])
|
||||||
end
|
end
|
||||||
|
|
||||||
if speed then
|
if speed then
|
||||||
speed = routines.utils.kmphToMps( speed )
|
speed = routines.utils.kmphToMps(speed)
|
||||||
end
|
end
|
||||||
|
|
||||||
local vars = {}
|
local vars = {}
|
||||||
vars.group = gpData
|
vars.group = gpData
|
||||||
vars.radius = zone.radius
|
vars.radius = zone.radius
|
||||||
vars.form = form
|
vars.form = form
|
||||||
vars.headingDegrees = heading
|
vars.headingDegrees = heading
|
||||||
vars.speed = speed
|
vars.speed = speed
|
||||||
vars.point = routines.utils.zoneToVec3( zone )
|
vars.point = routines.utils.zoneToVec3(zone)
|
||||||
|
|
||||||
routines.groupToRandomPoint( vars )
|
routines.groupToRandomPoint(vars)
|
||||||
|
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
routines.isTerrainValid = function( coord, terrainTypes ) -- vec2/3 and enum or table of acceptable terrain types
|
routines.isTerrainValid = function(coord, terrainTypes) -- vec2/3 and enum or table of acceptable terrain types
|
||||||
if coord.z then
|
if coord.z then
|
||||||
coord.y = coord.z
|
coord.y = coord.z
|
||||||
end
|
end
|
||||||
local typeConverted = {}
|
local typeConverted = {}
|
||||||
|
|
||||||
if type( terrainTypes ) == 'string' then -- if its a string it does this check
|
if type(terrainTypes) == 'string' then -- if its a string it does this check
|
||||||
for constId, constData in pairs( land.SurfaceType ) do
|
for constId, constData in pairs(land.SurfaceType) do
|
||||||
if string.lower( constId ) == string.lower( terrainTypes ) or string.lower( constData ) == string.lower( terrainTypes ) then
|
if string.lower(constId) == string.lower(terrainTypes) or string.lower(constData) == string.lower(terrainTypes) then
|
||||||
table.insert( typeConverted, constId )
|
table.insert(typeConverted, constId)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif type( terrainTypes ) == 'table' then -- if its a table it does this check
|
elseif type(terrainTypes) == 'table' then -- if its a table it does this check
|
||||||
for typeId, typeData in pairs( terrainTypes ) do
|
for typeId, typeData in pairs(terrainTypes) do
|
||||||
for constId, constData in pairs( land.SurfaceType ) do
|
for constId, constData in pairs(land.SurfaceType) do
|
||||||
if string.lower( constId ) == string.lower( typeData ) or string.lower( constData ) == string.lower( typeId ) then
|
if string.lower(constId) == string.lower(typeData) or string.lower(constData) == string.lower(typeId) then
|
||||||
table.insert( typeConverted, constId )
|
table.insert(typeConverted, constId)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for validIndex, validData in pairs( typeConverted ) do
|
for validIndex, validData in pairs(typeConverted) do
|
||||||
if land.getSurfaceType( coord ) == land.SurfaceType[validData] then
|
if land.getSurfaceType(coord) == land.SurfaceType[validData] then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
routines.groupToPoint = function( gpData, point, form, heading, speed, useRoads )
|
routines.groupToPoint = function(gpData, point, form, heading, speed, useRoads)
|
||||||
if type( point ) == 'string' then
|
if type(point) == 'string' then
|
||||||
point = trigger.misc.getZone( point )
|
point = trigger.misc.getZone(point)
|
||||||
end
|
end
|
||||||
if speed then
|
if speed then
|
||||||
speed = routines.utils.kmphToMps( speed )
|
speed = routines.utils.kmphToMps(speed)
|
||||||
end
|
end
|
||||||
|
|
||||||
local vars = {}
|
local vars = {}
|
||||||
vars.group = gpData
|
vars.group = gpData
|
||||||
vars.form = form
|
vars.form = form
|
||||||
vars.headingDegrees = heading
|
vars.headingDegrees = heading
|
||||||
vars.speed = speed
|
vars.speed = speed
|
||||||
vars.disableRoads = useRoads
|
vars.disableRoads = useRoads
|
||||||
vars.point = routines.utils.zoneToVec3( point )
|
vars.point = routines.utils.zoneToVec3(point)
|
||||||
routines.groupToRandomPoint( vars )
|
routines.groupToRandomPoint(vars)
|
||||||
|
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
routines.getLeadPos = function( group )
|
|
||||||
if type( group ) == 'string' then -- group name
|
|
||||||
group = Group.getByName( group )
|
|
||||||
end
|
|
||||||
|
|
||||||
local units = group:getUnits()
|
routines.getLeadPos = function(group)
|
||||||
|
if type(group) == 'string' then -- group name
|
||||||
|
group = Group.getByName(group)
|
||||||
|
end
|
||||||
|
|
||||||
local leader = units[1]
|
local units = group:getUnits()
|
||||||
if not leader then -- SHOULD be good, but if there is a bug, this code future-proofs it then.
|
|
||||||
local lowestInd = math.huge
|
local leader = units[1]
|
||||||
for ind, unit in pairs( units ) do
|
if not leader then -- SHOULD be good, but if there is a bug, this code future-proofs it then.
|
||||||
if ind < lowestInd then
|
local lowestInd = math.huge
|
||||||
lowestInd = ind
|
for ind, unit in pairs(units) do
|
||||||
leader = unit
|
if ind < lowestInd then
|
||||||
end
|
lowestInd = ind
|
||||||
end
|
leader = unit
|
||||||
end
|
end
|
||||||
if leader and Unit.isExist( leader ) then -- maybe a little too paranoid now...
|
end
|
||||||
return leader:getPosition().p
|
end
|
||||||
end
|
if leader and Unit.isExist(leader) then -- maybe a little too paranoid now...
|
||||||
|
return leader:getPosition().p
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[ vars for routines.getMGRSString:
|
--[[ vars for routines.getMGRSString:
|
||||||
|
|||||||
@@ -127,7 +127,10 @@ end
|
|||||||
--
|
--
|
||||||
-- * (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
|
-- * (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
|
||||||
--
|
--
|
||||||
function STTS.getSpeechTime( length, speed, isGoogle )
|
-- @param #number length can also be passed as #string
|
||||||
|
-- @param #number speed Defaults to 1.0
|
||||||
|
-- @param #boolean isGoogle We're using Google TTS
|
||||||
|
function STTS.getSpeechTime(length,speed,isGoogle)
|
||||||
|
|
||||||
local maxRateRatio = 3
|
local maxRateRatio = 3
|
||||||
|
|
||||||
@@ -153,7 +156,7 @@ function STTS.getSpeechTime( length, speed, isGoogle )
|
|||||||
length = string.len( length )
|
length = string.len( length )
|
||||||
end
|
end
|
||||||
|
|
||||||
return math.ceil( length / cps )
|
return length/cps --math.ceil(length/cps)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Text to speech function.
|
--- Text to speech function.
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
--- **Utilities** - Socket.
|
||||||
|
--
|
||||||
|
-- **Main Features:**
|
||||||
|
--
|
||||||
|
-- * Creates UDP Sockets
|
||||||
|
-- * Send messages to Discord
|
||||||
|
-- * Compatible with [FunkMan](https://github.com/funkyfranky/FunkMan)
|
||||||
|
-- * Compatible with [DCSServerBot](https://github.com/Special-K-s-Flightsim-Bots/DCSServerBot)
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- ### Author: **funkyfranky**
|
||||||
|
-- @module Utilities.Socket
|
||||||
|
-- @image Utilities_Socket.png
|
||||||
|
|
||||||
|
|
||||||
|
--- SOCKET class.
|
||||||
|
-- @type SOCKET
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #number verbose Verbosity level.
|
||||||
|
-- @field #string lid Class id string for output to DCS log file.
|
||||||
|
-- @field #table socket The socket.
|
||||||
|
-- @field #number port The port.
|
||||||
|
-- @field #string host The host.
|
||||||
|
-- @field #table json JSON.
|
||||||
|
-- @extends Core.Fsm#FSM
|
||||||
|
|
||||||
|
--- **At times I feel like a socket that remembers its tooth.** -- Saul Bellow
|
||||||
|
--
|
||||||
|
-- ===
|
||||||
|
--
|
||||||
|
-- # The SOCKET Concept
|
||||||
|
--
|
||||||
|
-- Create a UDP socket server. It enables you to send messages to discord servers via discord bots.
|
||||||
|
--
|
||||||
|
-- **Note** that you have to **de-sanitize** `require` and `package` in your `MissionScripting.lua` file, which is in your `DCS/Scripts` folder.
|
||||||
|
--
|
||||||
|
--
|
||||||
|
-- @field #SOCKET
|
||||||
|
SOCKET = {
|
||||||
|
ClassName = "SOCKET",
|
||||||
|
verbose = 0,
|
||||||
|
lid = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Data type. This is the keyword the socket listener uses.
|
||||||
|
-- @field #string TEXT Plain text.
|
||||||
|
-- @field #string BOMBRESULT Range bombing.
|
||||||
|
-- @field #string STRAFERESULT Range strafeing result.
|
||||||
|
-- @field #string LSOGRADE Airboss LSO grade.
|
||||||
|
SOCKET.DataType={
|
||||||
|
TEXT="moose_text",
|
||||||
|
BOMBRESULT="moose_bomb_result",
|
||||||
|
STRAFERESULT="moose_strafe_result",
|
||||||
|
LSOGRADE="moose_lso_grade",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
--- SOCKET class version.
|
||||||
|
-- @field #string version
|
||||||
|
SOCKET.version="0.1.0"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- TODO list
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- TODO: A lot!
|
||||||
|
-- TODO: Messages as spoiler.
|
||||||
|
-- TODO: Send images?
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
-- Constructor
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Create a new SOCKET object.
|
||||||
|
-- @param #SOCKET self
|
||||||
|
-- @param #number Port UDP port. Default `10042`.
|
||||||
|
-- @param #string Host Host. Default `"127.0.0.1"`.
|
||||||
|
-- @return #SOCKET self
|
||||||
|
function SOCKET:New(Port, Host)
|
||||||
|
|
||||||
|
-- Inherit everything from FSM class.
|
||||||
|
local self=BASE:Inherit(self, FSM:New()) --#SOCKET
|
||||||
|
|
||||||
|
package.path = package.path..";.\\LuaSocket\\?.lua;"
|
||||||
|
package.cpath = package.cpath..";.\\LuaSocket\\?.dll;"
|
||||||
|
|
||||||
|
self.socket = require("socket")
|
||||||
|
|
||||||
|
self.port=Port or 10042
|
||||||
|
self.host=Host or "127.0.0.1"
|
||||||
|
|
||||||
|
self.json=loadfile("Scripts\\JSON.lua")()
|
||||||
|
|
||||||
|
self.UDPSendSocket=self.socket.udp()
|
||||||
|
self.UDPSendSocket:settimeout(0)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set port.
|
||||||
|
-- @param #SOCKET self
|
||||||
|
-- @param #number Port Port. Default 10042.
|
||||||
|
-- @return #SOCKET self
|
||||||
|
function SOCKET:SetPort(Port)
|
||||||
|
self.port=Port or 10042
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set host.
|
||||||
|
-- @param #SOCKET self
|
||||||
|
-- @param #string Host Host. Default `"127.0.0.1"`.
|
||||||
|
-- @return #SOCKET self
|
||||||
|
function SOCKET:SetHost(Host)
|
||||||
|
self.host=Host or "127.0.0.1"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Send a table.
|
||||||
|
-- @param #SOCKET self
|
||||||
|
-- @param #table Table Table to send.
|
||||||
|
-- @return #SOCKET self
|
||||||
|
function SOCKET:SendTable(Table)
|
||||||
|
|
||||||
|
local json= self.json:encode(Table)
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T("Json table:")
|
||||||
|
self:T(json)
|
||||||
|
|
||||||
|
-- Send data.
|
||||||
|
self.socket.try(self.UDPSendSocket:sendto(json, self.host, self.port))
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Send a text message.
|
||||||
|
-- @param #SOCKET self
|
||||||
|
-- @param #string Text Test message.
|
||||||
|
-- @return #SOCKET self
|
||||||
|
function SOCKET:SendText(Text)
|
||||||
|
|
||||||
|
local message={}
|
||||||
|
|
||||||
|
message.command = SOCKET.DataType.TEXT
|
||||||
|
message.text = Text
|
||||||
|
|
||||||
|
self:SendTable(message)
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -1155,7 +1155,7 @@ function UTILS.VecHdg(a)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Calculate "heading" of a 2D vector in the X-Y plane.
|
--- Calculate "heading" of a 2D vector in the X-Y plane.
|
||||||
-- @param DCS#Vec2 a Vector in "D with x, y components.
|
-- @param DCS#Vec2 a Vector in 2D with x, y components.
|
||||||
-- @return #number Heading in degrees in [0,360).
|
-- @return #number Heading in degrees in [0,360).
|
||||||
function UTILS.Vec2Hdg(a)
|
function UTILS.Vec2Hdg(a)
|
||||||
local h=math.deg(math.atan2(a.y, a.x))
|
local h=math.deg(math.atan2(a.y, a.x))
|
||||||
@@ -1724,17 +1724,17 @@ end
|
|||||||
--- Get OS time. Needs os to be desanitized!
|
--- Get OS time. Needs os to be desanitized!
|
||||||
-- @return #number Os time in seconds.
|
-- @return #number Os time in seconds.
|
||||||
function UTILS.GetOSTime()
|
function UTILS.GetOSTime()
|
||||||
if os then
|
if os then
|
||||||
local ts = 0
|
local ts = 0
|
||||||
local t = os.date("*t")
|
local t = os.date("*t")
|
||||||
local s = t.sec
|
local s = t.sec
|
||||||
local m = t.min * 60
|
local m = t.min * 60
|
||||||
local h = t.hour * 3600
|
local h = t.hour * 3600
|
||||||
ts = s+m+h
|
ts = s+m+h
|
||||||
return ts
|
return ts
|
||||||
else
|
else
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Shuffle a table accoring to Fisher Yeates algorithm
|
--- Shuffle a table accoring to Fisher Yeates algorithm
|
||||||
@@ -1849,6 +1849,11 @@ function UTILS.IsLoadingDoorOpen( unit_name )
|
|||||||
return true -- no doors on this one ;)
|
return true -- no doors on this one ;)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if type_name == "Bronco-OV-10A" then
|
||||||
|
BASE:T(unit_name .. " front door(s) are open")
|
||||||
|
return true -- no doors on this one ;)
|
||||||
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
end -- nil
|
end -- nil
|
||||||
@@ -1878,7 +1883,7 @@ function UTILS.GenerateVHFrequencies()
|
|||||||
-- known and sorted map-wise NDBs in kHz
|
-- known and sorted map-wise NDBs in kHz
|
||||||
local _skipFrequencies = {
|
local _skipFrequencies = {
|
||||||
214,274,291.5,295,297.5,
|
214,274,291.5,295,297.5,
|
||||||
300.5,304,307,309.5,311,312,312.5,316,
|
300.5,304,305,307,309.5,311,312,312.5,316,
|
||||||
320,324,328,329,330,332,336,337,
|
320,324,328,329,330,332,336,337,
|
||||||
342,343,348,351,352,353,358,
|
342,343,348,351,352,353,358,
|
||||||
363,365,368,372.5,374,
|
363,365,368,372.5,374,
|
||||||
@@ -2301,7 +2306,7 @@ end
|
|||||||
-- @param #string Filename The name of the file.
|
-- @param #string Filename The name of the file.
|
||||||
-- @param #boolean Spawn If set to false, do not re-spawn the groups loaded in location and reduce to size.
|
-- @param #boolean Spawn If set to false, do not re-spawn the groups loaded in location and reduce to size.
|
||||||
-- @return Core.Set#SET_GROUP Set of GROUP objects.
|
-- @return Core.Set#SET_GROUP Set of GROUP objects.
|
||||||
-- Returns nil when file cannot be read. Returns a table of data entries if Spawn is false: `{ groupname=groupname, size=size, coordinate=coordinate }`
|
-- Returns nil when file cannot be read. Returns a table of data entries if Spawn is false: `{ groupname=groupname, size=size, coordinate=coordinate, template=template }`
|
||||||
function UTILS.LoadSetOfGroups(Path,Filename,Spawn)
|
function UTILS.LoadSetOfGroups(Path,Filename,Spawn)
|
||||||
local spawn = true
|
local spawn = true
|
||||||
if Spawn == false then spawn = false end
|
if Spawn == false then spawn = false end
|
||||||
@@ -2324,10 +2329,10 @@ function UTILS.LoadSetOfGroups(Path,Filename,Spawn)
|
|||||||
local posz = tonumber(dataset[6])
|
local posz = tonumber(dataset[6])
|
||||||
local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz})
|
local coordinate = COORDINATE:NewFromVec3({x=posx, y=posy, z=posz})
|
||||||
local group=nil
|
local group=nil
|
||||||
local data = { groupname=groupname, size=size, coordinate=coordinate }
|
local data = { groupname=groupname, size=size, coordinate=coordinate, template=template }
|
||||||
table.insert(datatable,data)
|
table.insert(datatable,data)
|
||||||
if spawn then
|
if spawn then
|
||||||
local group = SPAWN:New(groupname)
|
local group = SPAWN:New(template)
|
||||||
:InitDelayOff()
|
:InitDelayOff()
|
||||||
:OnSpawnGroup(
|
:OnSpawnGroup(
|
||||||
function(spwndgrp)
|
function(spwndgrp)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,17 @@
|
|||||||
|
|
||||||
--- The CLIENT class
|
--- The CLIENT class
|
||||||
-- @type CLIENT
|
-- @type CLIENT
|
||||||
|
-- @field #string ClassName Name of the class.
|
||||||
|
-- @field #string ClientName Name of the client.
|
||||||
|
-- @field #string ClientBriefing Briefing.
|
||||||
|
-- @field #function ClientCallBack Callback function.
|
||||||
|
-- @field #table ClientParameters Parameters of the callback function.
|
||||||
|
-- @field #number ClientGroupID Group ID of the client.
|
||||||
|
-- @field #string ClientGroupName Group name.
|
||||||
|
-- @field #boolean ClientAlive Client alive.
|
||||||
|
-- @field #boolean ClientAlive2 Client alive 2.
|
||||||
|
-- @field #table Players Player table.
|
||||||
|
-- @field Core.Point#COORDINATE SpawnCoord Spawn coordinate from the template.
|
||||||
-- @extends Wrapper.Unit#UNIT
|
-- @extends Wrapper.Unit#UNIT
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -671,7 +671,7 @@ end
|
|||||||
--- Activate ICLS system of the CONTROLLABLE. The controllable should be an aircraft carrier!
|
--- Activate ICLS system of the CONTROLLABLE. The controllable should be an aircraft carrier!
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number Channel ICLS channel.
|
-- @param #number Channel ICLS channel.
|
||||||
-- @param #number UnitID The ID of the unit the ICLS system is attached to. Useful if more units are in one group.
|
-- @param #number UnitID The DCS UNIT ID of the unit the ICLS system is attached to. Useful if more units are in one group.
|
||||||
-- @param #string Callsign Morse code identification callsign.
|
-- @param #string Callsign Morse code identification callsign.
|
||||||
-- @param #number Delay (Optional) Delay in seconds before the ICLS is deactivated.
|
-- @param #number Delay (Optional) Delay in seconds before the ICLS is deactivated.
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
@@ -725,6 +725,34 @@ function CONTROLLABLE:CommandActivateLink4(Frequency, UnitID, Callsign, Delay)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Activate LINK4 system of the CONTROLLABLE. The controllable should be an aircraft carrier!
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number Frequency Link4 Frequency in MHz, e.g. 336
|
||||||
|
-- @param #number UnitID The DCS UNIT ID of the unit the LINK4 system is attached to. Useful if more units are in one group.
|
||||||
|
-- @param #string Callsign Morse code identification callsign.
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds before the LINK4 is deactivated.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:CommandActivateLink4(Frequency, UnitID, Callsign, Delay)
|
||||||
|
|
||||||
|
-- Command to activate Link4 system.
|
||||||
|
local CommandActivateLink4= {
|
||||||
|
id = "ActivateLink4",
|
||||||
|
params= {
|
||||||
|
["frequency "] = Frequency*1000,
|
||||||
|
["unitId"] = UnitID,
|
||||||
|
["name"] = Callsign,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
SCHEDULER:New(nil, self.CommandActivateLink4, {self}, Delay)
|
||||||
|
else
|
||||||
|
self:SetCommand(CommandActivateLink4)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Deactivate the active beacon of the CONTROLLABLE.
|
--- Deactivate the active beacon of the CONTROLLABLE.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number Delay (Optional) Delay in seconds before the beacon is deactivated.
|
-- @param #number Delay (Optional) Delay in seconds before the beacon is deactivated.
|
||||||
@@ -734,8 +762,10 @@ function CONTROLLABLE:CommandDeactivateBeacon( Delay )
|
|||||||
-- Command to deactivate
|
-- Command to deactivate
|
||||||
local CommandDeactivateBeacon = { id = 'DeactivateBeacon', params = {} }
|
local CommandDeactivateBeacon = { id = 'DeactivateBeacon', params = {} }
|
||||||
|
|
||||||
if Delay and Delay > 0 then
|
local CommandDeactivateBeacon={id='DeactivateBeacon', params={}}
|
||||||
SCHEDULER:New( nil, self.CommandDeactivateBeacon, { self }, Delay )
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
SCHEDULER:New(nil, self.CommandDeactivateBeacon, {self}, Delay)
|
||||||
else
|
else
|
||||||
self:SetCommand( CommandDeactivateBeacon )
|
self:SetCommand( CommandDeactivateBeacon )
|
||||||
end
|
end
|
||||||
@@ -743,6 +773,24 @@ function CONTROLLABLE:CommandDeactivateBeacon( Delay )
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Deactivate the active Link4 of the CONTROLLABLE.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param #number Delay (Optional) Delay in seconds before the Link4 is deactivated.
|
||||||
|
-- @return #CONTROLLABLE self
|
||||||
|
function CONTROLLABLE:CommandDeactivateLink4(Delay)
|
||||||
|
|
||||||
|
-- Command to deactivate
|
||||||
|
local CommandDeactivateLink4={id='DeactivateLink4', params={}}
|
||||||
|
|
||||||
|
if Delay and Delay>0 then
|
||||||
|
SCHEDULER:New(nil, self.CommandDeactivateLink4, {self}, Delay)
|
||||||
|
else
|
||||||
|
self:SetCommand(CommandDeactivateLink4)
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Deactivate the ICLS of the CONTROLLABLE.
|
--- Deactivate the ICLS of the CONTROLLABLE.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number Delay (Optional) Delay in seconds before the ICLS is deactivated.
|
-- @param #number Delay (Optional) Delay in seconds before the ICLS is deactivated.
|
||||||
@@ -1424,7 +1472,7 @@ function CONTROLLABLE:TaskEscort( FollowControllable, Vec3, LastWaypointIndex, E
|
|||||||
DCSTask = {
|
DCSTask = {
|
||||||
id = 'Escort',
|
id = 'Escort',
|
||||||
params = {
|
params = {
|
||||||
groupId = FollowControllable:GetID(),
|
groupId = FollowControllable and FollowControllable:GetID() or nil,
|
||||||
pos = Vec3,
|
pos = Vec3,
|
||||||
lastWptIndexFlag = LastWaypointIndex and true or false,
|
lastWptIndexFlag = LastWaypointIndex and true or false,
|
||||||
lastWptIndex = LastWaypointIndex,
|
lastWptIndex = LastWaypointIndex,
|
||||||
@@ -1453,11 +1501,11 @@ function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType, Alti
|
|||||||
id = 'FireAtPoint',
|
id = 'FireAtPoint',
|
||||||
params = {
|
params = {
|
||||||
point = Vec2,
|
point = Vec2,
|
||||||
x=Vec2.x,
|
x = Vec2.x,
|
||||||
y=Vec2.y,
|
y = Vec2.y,
|
||||||
zoneRadius = Radius,
|
zoneRadius = Radius,
|
||||||
radius = Radius,
|
radius = Radius,
|
||||||
expendQty = 100, -- dummy value
|
expendQty = 1, -- dummy value
|
||||||
expendQtyEnabled = false,
|
expendQtyEnabled = false,
|
||||||
alt_type = ASL and 0 or 1,
|
alt_type = ASL and 0 or 1,
|
||||||
},
|
},
|
||||||
@@ -1476,7 +1524,8 @@ function CONTROLLABLE:TaskFireAtPoint( Vec2, Radius, AmmoCount, WeaponType, Alti
|
|||||||
DCSTask.params.weaponType = WeaponType
|
DCSTask.params.weaponType = WeaponType
|
||||||
end
|
end
|
||||||
|
|
||||||
-- self:I(DCSTask)
|
--env.info("FF fireatpoint")
|
||||||
|
--BASE:I(DCSTask)
|
||||||
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
@@ -1569,6 +1618,28 @@ function CONTROLLABLE:EnRouteTaskEngageTargetsInZone( Vec2, Radius, TargetTypes,
|
|||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- (AIR) Enroute anti-ship task.
|
||||||
|
-- @param #CONTROLLABLE self
|
||||||
|
-- @param DCS#AttributeNameArray TargetTypes Array of target categories allowed to engage. Default `{"Ships"}`.
|
||||||
|
-- @param #number Priority (Optional) All en-route tasks have the priority parameter. This is a number (less value - higher priority) that determines actions related to what task will be performed first. Default 0.
|
||||||
|
-- @return DCS#Task The DCS task structure.
|
||||||
|
function CONTROLLABLE:EnRouteTaskAntiShip(TargetTypes, Priority)
|
||||||
|
|
||||||
|
local DCSTask = {
|
||||||
|
id = 'EngageTargets',
|
||||||
|
key = "AntiShip",
|
||||||
|
--auto = false,
|
||||||
|
--enabled = true,
|
||||||
|
params = {
|
||||||
|
targetTypes = TargetTypes or {"Ships"},
|
||||||
|
priority = Priority or 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DCSTask
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets.
|
--- (AIR) Engaging a controllable. The task does not assign the target controllable to the unit/controllable to attack now; it just allows the unit/controllable to engage the target controllable as well as other assigned targets.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked.
|
-- @param Wrapper.Controllable#CONTROLLABLE AttackGroup The Controllable to be attacked.
|
||||||
@@ -1835,7 +1906,7 @@ end
|
|||||||
|
|
||||||
do -- Patrol methods
|
do -- Patrol methods
|
||||||
|
|
||||||
--- (GROUND) Patrol iteratively using the waypoints the for the (parent) group.
|
--- (GROUND) Patrol iteratively using the waypoints of the (parent) group.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @return #CONTROLLABLE
|
-- @return #CONTROLLABLE
|
||||||
function CONTROLLABLE:PatrolRoute()
|
function CONTROLLABLE:PatrolRoute()
|
||||||
@@ -1866,12 +1937,13 @@ do -- Patrol methods
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local Waypoint = Waypoints[1]
|
local Waypoint = Waypoints[1]
|
||||||
local Speed = Waypoint.speed or (20 / 3.6)
|
local Speed = Waypoint.speed or (20 / 3.6)
|
||||||
local From = FromCoord:WaypointGround( Speed )
|
local From = FromCoord:WaypointGround( Speed )
|
||||||
|
|
||||||
if IsSub then
|
if IsSub then
|
||||||
From = FromCoord:WaypointNaval( Speed, Waypoint.alt )
|
From = FromCoord:WaypointNaval( Speed, Waypoint.alt )
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert( Waypoints, 1, From )
|
table.insert( Waypoints, 1, From )
|
||||||
@@ -2023,22 +2095,21 @@ do -- Patrol methods
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Return a Mission task to follow a given route defined by Points.
|
|
||||||
|
--- Return a "Misson" task to follow a given route defined by Points.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #table Points A table of route points.
|
-- @param #table Points A table of route points.
|
||||||
-- @return DCS#Task
|
-- @return DCS#Task DCS mission task. Has entries `.id="Mission"`, `params`, were params has entries `airborne` and `route`, which is a table of `points`.
|
||||||
function CONTROLLABLE:TaskRoute( Points )
|
function CONTROLLABLE:TaskRoute( Points )
|
||||||
self:F2( Points )
|
|
||||||
|
|
||||||
local DCSTask = {
|
local DCSTask = {
|
||||||
id = 'Mission',
|
id = 'Mission',
|
||||||
params = {
|
params = {
|
||||||
airborne = self:IsAir(),
|
airborne = self:IsAir(), -- This is important to make aircraft land without respawning them (which was a long standing DCS issue).
|
||||||
route = {points = Points},
|
route = {points = Points},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
self:T3( { DCSTask } )
|
|
||||||
return DCSTask
|
return DCSTask
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3746,10 +3817,10 @@ end
|
|||||||
|
|
||||||
--- (GROUND) Relocate controllable to a random point within a given radius; use e.g.for evasive actions; Note that not all ground controllables can actually drive, also the alarm state of the controllable might stop it from moving.
|
--- (GROUND) Relocate controllable to a random point within a given radius; use e.g.for evasive actions; Note that not all ground controllables can actually drive, also the alarm state of the controllable might stop it from moving.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number speed Speed of the controllable, default 20
|
-- @param #number speed Speed of the controllable, default 20
|
||||||
-- @param #number radius Radius of the relocation zone, default 500
|
-- @param #number radius Radius of the relocation zone, default 500
|
||||||
-- @param #boolean onroad If true, route on road (less problems with AI way finding), default true
|
-- @param #boolean onroad If true, route on road (less problems with AI way finding), default true
|
||||||
-- @param #boolean shortcut If true and onroad is set, take a shorter route - if available - off road, default false
|
-- @param #boolean shortcut If true and onroad is set, take a shorter route - if available - off road, default false
|
||||||
-- @param #string formation Formation string as in the mission editor, e.g. "Vee", "Diamond", "Line abreast", etc. Defaults to "Off Road"
|
-- @param #string formation Formation string as in the mission editor, e.g. "Vee", "Diamond", "Line abreast", etc. Defaults to "Off Road"
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
function CONTROLLABLE:RelocateGroundRandomInRadius( speed, radius, onroad, shortcut, formation )
|
function CONTROLLABLE:RelocateGroundRandomInRadius( speed, radius, onroad, shortcut, formation )
|
||||||
@@ -3800,7 +3871,7 @@ end
|
|||||||
--- Returns if the unit is a submarine.
|
--- Returns if the unit is a submarine.
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
-- @return #boolean Submarines attributes result.
|
-- @return #boolean Submarines attributes result.
|
||||||
function POSITIONABLE:IsSubmarine()
|
function CONTROLLABLE:IsSubmarine()
|
||||||
self:F2()
|
self:F2()
|
||||||
|
|
||||||
local DCSUnit = self:GetDCSObject()
|
local DCSUnit = self:GetDCSObject()
|
||||||
@@ -3817,9 +3888,10 @@ function POSITIONABLE:IsSubmarine()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Sets the controlled group to go at the specified speed in meters per second.
|
--- Sets the controlled group to go at the specified speed in meters per second.
|
||||||
-- @param #CONTROLLABLE self
|
-- @param #CONTROLLABLE self
|
||||||
-- @param #number Speed Speed in meters per second.
|
-- @param #number Speed Speed in meters per second
|
||||||
-- @param #boolean Keep (Optional) When set to true, will maintain the speed on passing waypoints. If not present or false, the controlled group will return to the speed as defined by their route.
|
-- @param #boolean Keep (Optional) When set to true, will maintain the speed on passing waypoints. If not present or false, the controlled group will return to the speed as defined by their route.
|
||||||
-- @return #CONTROLLABLE self
|
-- @return #CONTROLLABLE self
|
||||||
function CONTROLLABLE:SetSpeed(Speed, Keep)
|
function CONTROLLABLE:SetSpeed(Speed, Keep)
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ GROUPTEMPLATE.Takeoff = {
|
|||||||
-- @field #string GROUND_APC Infantry carriers, in particular Amoured Personell Carrier. This can be used to transport other assets.
|
-- @field #string GROUND_APC Infantry carriers, in particular Amoured Personell Carrier. This can be used to transport other assets.
|
||||||
-- @field #string GROUND_TRUCK Unarmed ground vehicles, which has the DCS "Truck" attribute.
|
-- @field #string GROUND_TRUCK Unarmed ground vehicles, which has the DCS "Truck" attribute.
|
||||||
-- @field #string GROUND_INFANTRY Ground infantry assets.
|
-- @field #string GROUND_INFANTRY Ground infantry assets.
|
||||||
|
-- @field #string GROUND_IFV Ground Infantry Fighting Vehicle.
|
||||||
-- @field #string GROUND_ARTILLERY Artillery assets.
|
-- @field #string GROUND_ARTILLERY Artillery assets.
|
||||||
-- @field #string GROUND_TANK Tanks (modern or old).
|
-- @field #string GROUND_TANK Tanks (modern or old).
|
||||||
-- @field #string GROUND_TRAIN Trains. Not that trains are **not** yet properly implemented in DCS and cannot be used currently.
|
-- @field #string GROUND_TRAIN Trains. Not that trains are **not** yet properly implemented in DCS and cannot be used currently.
|
||||||
@@ -213,6 +214,7 @@ GROUP.Attribute = {
|
|||||||
GROUND_APC="Ground_APC",
|
GROUND_APC="Ground_APC",
|
||||||
GROUND_TRUCK="Ground_Truck",
|
GROUND_TRUCK="Ground_Truck",
|
||||||
GROUND_INFANTRY="Ground_Infantry",
|
GROUND_INFANTRY="Ground_Infantry",
|
||||||
|
GROUND_IFV="Ground_IFV",
|
||||||
GROUND_ARTILLERY="Ground_Artillery",
|
GROUND_ARTILLERY="Ground_Artillery",
|
||||||
GROUND_TANK="Ground_Tank",
|
GROUND_TANK="Ground_Tank",
|
||||||
GROUND_TRAIN="Ground_Train",
|
GROUND_TRAIN="Ground_Train",
|
||||||
@@ -529,26 +531,32 @@ function GROUP:HasAttribute(attribute, all)
|
|||||||
-- Get all units of the group.
|
-- Get all units of the group.
|
||||||
local _units=self:GetUnits()
|
local _units=self:GetUnits()
|
||||||
|
|
||||||
local _allhave=true
|
if _units then
|
||||||
local _onehas=false
|
|
||||||
|
|
||||||
for _,_unit in pairs(_units) do
|
local _allhave=true
|
||||||
local _unit=_unit --Wrapper.Unit#UNIT
|
local _onehas=false
|
||||||
if _unit then
|
|
||||||
local _hastit=_unit:HasAttribute(attribute)
|
for _,_unit in pairs(_units) do
|
||||||
if _hastit==true then
|
local _unit=_unit --Wrapper.Unit#UNIT
|
||||||
_onehas=true
|
if _unit then
|
||||||
else
|
local _hastit=_unit:HasAttribute(attribute)
|
||||||
_allhave=false
|
if _hastit==true then
|
||||||
|
_onehas=true
|
||||||
|
else
|
||||||
|
_allhave=false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if all==true then
|
||||||
|
return _allhave
|
||||||
|
else
|
||||||
|
return _onehas
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if all==true then
|
return nil
|
||||||
return _allhave
|
|
||||||
else
|
|
||||||
return _onehas
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the maximum speed of the group.
|
--- Returns the maximum speed of the group.
|
||||||
@@ -563,16 +571,19 @@ function GROUP:GetSpeedMax()
|
|||||||
|
|
||||||
local Units=self:GetUnits()
|
local Units=self:GetUnits()
|
||||||
|
|
||||||
local speedmax=0
|
local speedmax=nil
|
||||||
|
|
||||||
for _,unit in pairs(Units) do
|
for _,unit in pairs(Units) do
|
||||||
local unit=unit --Wrapper.Unit#UNIT
|
local unit=unit --Wrapper.Unit#UNIT
|
||||||
|
|
||||||
local speed=unit:GetSpeedMax()
|
local speed=unit:GetSpeedMax()
|
||||||
if speedmax==0 then
|
|
||||||
speedmax=speed
|
if speedmax==nil or speed<speedmax then
|
||||||
elseif speed<speedmax then
|
|
||||||
speedmax=speed
|
speedmax=speed
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--env.info(string.format("FF unit %s: speed=%.1f, speedmax=%.1f", unit:GetName(), speed, speedmax))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return speedmax
|
return speedmax
|
||||||
@@ -658,6 +669,12 @@ function GROUP:GetPlayerUnits()
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Check if an (air) group is a client or player slot. Information is retrieved from the group template.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @return #boolean If true, group is associated with a client or player slot.
|
||||||
|
function GROUP:IsPlayer()
|
||||||
|
return self:GetUnit(1):IsPlayer()
|
||||||
|
end
|
||||||
|
|
||||||
--- Returns the UNIT wrapper class with number UnitNumber.
|
--- Returns the UNIT wrapper class with number UnitNumber.
|
||||||
-- If the underlying DCS Unit does not exist, the method will return nil. .
|
-- If the underlying DCS Unit does not exist, the method will return nil. .
|
||||||
@@ -670,40 +687,28 @@ function GROUP:GetUnit( UnitNumber )
|
|||||||
|
|
||||||
if DCSGroup then
|
if DCSGroup then
|
||||||
|
|
||||||
local DCSUnit = DCSGroup:getUnit( UnitNumber )
|
local UnitFound = nil
|
||||||
|
-- 2.7.1 dead event bug, return the first alive unit instead
|
||||||
|
local units = DCSGroup:getUnits() or {}
|
||||||
|
|
||||||
local UnitFound = UNIT:Find(DCSUnit)
|
for _,_unit in pairs(units) do
|
||||||
|
|
||||||
return UnitFound
|
local UnitFound = UNIT:Find(_unit)
|
||||||
end
|
|
||||||
|
|
||||||
return nil
|
if UnitFound then
|
||||||
end
|
|
||||||
|
|
||||||
--- Check if an (air) group is a client or player slot. Information is retrieved from the group template.
|
return UnitFound
|
||||||
-- @param #GROUP self
|
|
||||||
-- @return #boolean If true, group is associated with a client or player slot.
|
|
||||||
function GROUP:IsPlayer()
|
|
||||||
|
|
||||||
-- Get group.
|
end
|
||||||
-- local group=self:GetGroup()
|
|
||||||
|
|
||||||
-- Units of template group.
|
|
||||||
local units=self:GetTemplate().units
|
|
||||||
|
|
||||||
-- Get numbers.
|
|
||||||
for _,unit in pairs(units) do
|
|
||||||
|
|
||||||
-- Check if unit name matach and skill is Client or Player.
|
|
||||||
if unit.name==self:GetName() and (unit.skill=="Client" or unit.skill=="Player") then
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return nil
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns the DCS Unit with number UnitNumber.
|
--- Returns the DCS Unit with number UnitNumber.
|
||||||
-- If the underlying DCS Unit does not exist, the method will return nil. .
|
-- If the underlying DCS Unit does not exist, the method will return nil. .
|
||||||
-- @param #GROUP self
|
-- @param #GROUP self
|
||||||
@@ -1056,7 +1061,8 @@ end
|
|||||||
-- @return Core.Point#COORDINATE The COORDINATE of the GROUP.
|
-- @return Core.Point#COORDINATE The COORDINATE of the GROUP.
|
||||||
function GROUP:GetCoordinate()
|
function GROUP:GetCoordinate()
|
||||||
|
|
||||||
local Units = self:GetUnits() or {}
|
|
||||||
|
local Units = self:GetUnits() or {}
|
||||||
|
|
||||||
for _,_unit in pairs(Units) do
|
for _,_unit in pairs(Units) do
|
||||||
local FirstUnit = _unit -- Wrapper.Unit#UNIT
|
local FirstUnit = _unit -- Wrapper.Unit#UNIT
|
||||||
@@ -1204,6 +1210,7 @@ end
|
|||||||
-- @return #number Number of rockets left.
|
-- @return #number Number of rockets left.
|
||||||
-- @return #number Number of bombs left.
|
-- @return #number Number of bombs left.
|
||||||
-- @return #number Number of missiles left.
|
-- @return #number Number of missiles left.
|
||||||
|
-- @return #number Number of artillery shells left (with explosive mass, included in shells; shells can also be machine gun ammo)
|
||||||
function GROUP:GetAmmunition()
|
function GROUP:GetAmmunition()
|
||||||
self:F( self.ControllableName )
|
self:F( self.ControllableName )
|
||||||
|
|
||||||
@@ -1214,6 +1221,7 @@ function GROUP:GetAmmunition()
|
|||||||
local Nrockets=0
|
local Nrockets=0
|
||||||
local Nmissiles=0
|
local Nmissiles=0
|
||||||
local Nbombs=0
|
local Nbombs=0
|
||||||
|
local Narti=0
|
||||||
|
|
||||||
if DCSControllable then
|
if DCSControllable then
|
||||||
|
|
||||||
@@ -1222,19 +1230,19 @@ function GROUP:GetAmmunition()
|
|||||||
local Unit = UnitData -- Wrapper.Unit#UNIT
|
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||||
|
|
||||||
-- Get ammo of the unit
|
-- Get ammo of the unit
|
||||||
local ntot, nshells, nrockets, nbombs, nmissiles = Unit:GetAmmunition()
|
local ntot, nshells, nrockets, nbombs, nmissiles, narti = Unit:GetAmmunition()
|
||||||
|
|
||||||
Ntot=Ntot+ntot
|
Ntot=Ntot+ntot
|
||||||
Nshells=Nshells+nshells
|
Nshells=Nshells+nshells
|
||||||
Nrockets=Nrockets+nrockets
|
Nrockets=Nrockets+nrockets
|
||||||
Nmissiles=Nmissiles+nmissiles
|
Nmissiles=Nmissiles+nmissiles
|
||||||
Nbombs=Nbombs+nbombs
|
Nbombs=Nbombs+nbombs
|
||||||
|
Narti=Narti+narti
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return Ntot, Nshells, Nrockets, Nbombs, Nmissiles
|
return Ntot, Nshells, Nrockets, Nbombs, Nmissiles, Narti
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -2372,14 +2380,15 @@ function GROUP:GetAttribute()
|
|||||||
--- Ground ---
|
--- Ground ---
|
||||||
--------------
|
--------------
|
||||||
-- Ground
|
-- Ground
|
||||||
local apc=self:HasAttribute("Infantry carriers")
|
local apc=self:HasAttribute("APC")
|
||||||
local truck=self:HasAttribute("Trucks") and self:GetCategory()==Group.Category.GROUND
|
local truck=self:HasAttribute("Trucks") and self:GetCategory()==Group.Category.GROUND
|
||||||
local infantry=self:HasAttribute("Infantry")
|
local infantry=self:HasAttribute("Infantry")
|
||||||
local artillery=self:HasAttribute("Artillery")
|
local artillery=self:HasAttribute("Artillery")
|
||||||
local tank=self:HasAttribute("Old Tanks") or self:HasAttribute("Modern Tanks")
|
local tank=self:HasAttribute("Old Tanks") or self:HasAttribute("Modern Tanks")
|
||||||
local aaa=self:HasAttribute("AAA")
|
local aaa=self:HasAttribute("AAA") and (not self:HasAttribute("SAM elements"))
|
||||||
local ewr=self:HasAttribute("EWR")
|
local ewr=self:HasAttribute("EWR")
|
||||||
local sam=self:HasAttribute("SAM elements") and (not self:HasAttribute("AAA"))
|
local ifv=self:HasAttribute("IFV")
|
||||||
|
local sam=self:HasAttribute("SAM elements") or self:HasAttribute("Optical Tracker")
|
||||||
-- Train
|
-- Train
|
||||||
local train=self:GetCategory()==Group.Category.TRAIN
|
local train=self:GetCategory()==Group.Category.TRAIN
|
||||||
|
|
||||||
@@ -2422,6 +2431,8 @@ function GROUP:GetAttribute()
|
|||||||
attribute=GROUP.Attribute.GROUND_ARTILLERY
|
attribute=GROUP.Attribute.GROUND_ARTILLERY
|
||||||
elseif tank then
|
elseif tank then
|
||||||
attribute=GROUP.Attribute.GROUND_TANK
|
attribute=GROUP.Attribute.GROUND_TANK
|
||||||
|
elseif ifv then
|
||||||
|
attribute=GROUP.Attribute.GROUND_IFV
|
||||||
elseif apc then
|
elseif apc then
|
||||||
attribute=GROUP.Attribute.GROUND_APC
|
attribute=GROUP.Attribute.GROUND_APC
|
||||||
elseif infantry then
|
elseif infantry then
|
||||||
@@ -2716,94 +2727,85 @@ function GROUP:GetHighestThreat()
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--do -- Smoke
|
--- Get TTS friendly, optionally customized callsign mainly for **player groups**. A customized callsign is taken from the #GROUP name, after an optional '#' sign, e.g. "Aerial 1-1#Ghostrider" resulting in "Ghostrider 9", or,
|
||||||
|
-- if that isn't available, from the playername, as set in the mission editor main screen under Logbook, after an optional '|' sign (actually, more of a personal call sign), e.g. "Apple|Moose" results in "Moose 9 1". Options see below.
|
||||||
|
-- @param #GROUP self
|
||||||
|
-- @param #boolean ShortCallsign Return a shortened customized callsign, i.e. "Ghostrider 9" and not "Ghostrider 9 1"
|
||||||
|
-- @param #boolean Keepnumber (Player only) Return customized callsign, incl optional numbers at the end, e.g. "Aerial 1-1#Ghostrider 109" results in "Ghostrider 109", if you want to e.g. use historical US Navy Callsigns
|
||||||
|
-- @param #table CallsignTranslations Table to translate between DCS standard callsigns and bespoke ones. Does not apply if using customized
|
||||||
|
-- callsigns from playername or group name.
|
||||||
|
-- @return #string Callsign
|
||||||
|
-- @usage
|
||||||
|
-- -- Set Custom CAP Flight Callsigns for use with TTS
|
||||||
|
-- mygroup:GetCustomCallSign(true,false,{
|
||||||
|
-- Devil = 'Bengal',
|
||||||
|
-- Snake = 'Winder',
|
||||||
|
-- Colt = 'Camelot',
|
||||||
|
-- Enfield = 'Victory',
|
||||||
|
-- Uzi = 'Evil Eye'
|
||||||
|
-- })
|
||||||
--
|
--
|
||||||
----- Signal a flare at the position of the GROUP.
|
-- results in this outcome if the group has Callsign "Enfield 9 1" on the 1st #UNIT of the group:
|
||||||
---- @param #GROUP self
|
|
||||||
---- @param Utilities.Utils#FLARECOLOR FlareColor
|
|
||||||
--function GROUP:Flare( FlareColor )
|
|
||||||
-- self:F2()
|
|
||||||
-- trigger.action.signalFlare( self:GetVec3(), FlareColor , 0 )
|
|
||||||
--end
|
|
||||||
--
|
--
|
||||||
----- Signal a white flare at the position of the GROUP.
|
-- 'Victory 9'
|
||||||
---- @param #GROUP self
|
|
||||||
--function GROUP:FlareWhite()
|
|
||||||
-- self:F2()
|
|
||||||
-- trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.White , 0 )
|
|
||||||
--end
|
|
||||||
--
|
|
||||||
----- Signal a yellow flare at the position of the GROUP.
|
|
||||||
---- @param #GROUP self
|
|
||||||
--function GROUP:FlareYellow()
|
|
||||||
-- self:F2()
|
|
||||||
-- trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Yellow , 0 )
|
|
||||||
--end
|
|
||||||
--
|
|
||||||
----- Signal a green flare at the position of the GROUP.
|
|
||||||
---- @param #GROUP self
|
|
||||||
--function GROUP:FlareGreen()
|
|
||||||
-- self:F2()
|
|
||||||
-- trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Green , 0 )
|
|
||||||
--end
|
|
||||||
--
|
|
||||||
----- Signal a red flare at the position of the GROUP.
|
|
||||||
---- @param #GROUP self
|
|
||||||
--function GROUP:FlareRed()
|
|
||||||
-- self:F2()
|
|
||||||
-- local Vec3 = self:GetVec3()
|
|
||||||
-- if Vec3 then
|
|
||||||
-- trigger.action.signalFlare( Vec3, trigger.flareColor.Red, 0 )
|
|
||||||
-- end
|
|
||||||
--end
|
|
||||||
--
|
|
||||||
----- Smoke the GROUP.
|
|
||||||
---- @param #GROUP self
|
|
||||||
--function GROUP:Smoke( SmokeColor, Range )
|
|
||||||
-- self:F2()
|
|
||||||
-- if Range then
|
|
||||||
-- trigger.action.smoke( self:GetRandomVec3( Range ), SmokeColor )
|
|
||||||
-- else
|
|
||||||
-- trigger.action.smoke( self:GetVec3(), SmokeColor )
|
|
||||||
-- end
|
|
||||||
--
|
|
||||||
--end
|
|
||||||
--
|
|
||||||
----- Smoke the GROUP Green.
|
|
||||||
---- @param #GROUP self
|
|
||||||
--function GROUP:SmokeGreen()
|
|
||||||
-- self:F2()
|
|
||||||
-- trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Green )
|
|
||||||
--end
|
|
||||||
--
|
|
||||||
----- Smoke the GROUP Red.
|
|
||||||
---- @param #GROUP self
|
|
||||||
--function GROUP:SmokeRed()
|
|
||||||
-- self:F2()
|
|
||||||
-- trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Red )
|
|
||||||
--end
|
|
||||||
--
|
|
||||||
----- Smoke the GROUP White.
|
|
||||||
---- @param #GROUP self
|
|
||||||
--function GROUP:SmokeWhite()
|
|
||||||
-- self:F2()
|
|
||||||
-- trigger.action.smoke( self:GetVec3(), trigger.smokeColor.White )
|
|
||||||
--end
|
|
||||||
--
|
|
||||||
----- Smoke the GROUP Orange.
|
|
||||||
---- @param #GROUP self
|
|
||||||
--function GROUP:SmokeOrange()
|
|
||||||
-- self:F2()
|
|
||||||
-- trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Orange )
|
|
||||||
--end
|
|
||||||
--
|
|
||||||
----- Smoke the GROUP Blue.
|
|
||||||
---- @param #GROUP self
|
|
||||||
--function GROUP:SmokeBlue()
|
|
||||||
-- self:F2()
|
|
||||||
-- trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Blue )
|
|
||||||
--end
|
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
--
|
function GROUP:GetCustomCallSign(ShortCallsign,Keepnumber,CallsignTranslations)
|
||||||
--end
|
--self:I("GetCustomCallSign")
|
||||||
|
|
||||||
|
local callsign = "Ghost 1"
|
||||||
|
if self:IsAlive() then
|
||||||
|
local IsPlayer = self:IsPlayer()
|
||||||
|
local shortcallsign = self:GetCallsign() or "unknown91" -- e.g.Uzi91, but we want Uzi 9 1
|
||||||
|
local callsignroot = string.match(shortcallsign, '(%a+)') -- Uzi
|
||||||
|
--self:I("CallSign = " .. callsignroot)
|
||||||
|
local groupname = self:GetName()
|
||||||
|
local callnumber = string.match(shortcallsign, "(%d+)$" ) or "91" -- 91
|
||||||
|
local callnumbermajor = string.char(string.byte(callnumber,1)) -- 9
|
||||||
|
local callnumberminor = string.char(string.byte(callnumber,2)) -- 1
|
||||||
|
local personalized = false
|
||||||
|
if IsPlayer and string.find(groupname,"#") then
|
||||||
|
-- personalized flight name in group naming
|
||||||
|
if Keepnumber then
|
||||||
|
shortcallsign = string.match(groupname,"#(.+)") -- Ghostrider 219
|
||||||
|
else
|
||||||
|
shortcallsign = string.match(groupname,"#%s*([%a]+)") -- Ghostrider
|
||||||
|
end
|
||||||
|
personalized = true
|
||||||
|
elseif IsPlayer and string.find(self:GetPlayerName(),"|") then
|
||||||
|
-- personalized flight name in group naming
|
||||||
|
shortcallsign = string.match(self:GetPlayerName(),"|%s*([%a]+)") -- Ghostrider
|
||||||
|
personalized = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if (not personalized) and CallsignTranslations and CallsignTranslations[callsignroot] then
|
||||||
|
callsignroot = CallsignTranslations[callsignroot]
|
||||||
|
end
|
||||||
|
|
||||||
|
if personalized then
|
||||||
|
-- player personalized callsign
|
||||||
|
-- remove trailing/leading spaces
|
||||||
|
shortcallsign=string.gsub(shortcallsign,"^%s*","")
|
||||||
|
shortcallsign=string.gsub(shortcallsign,"%s*$","")
|
||||||
|
if Keepnumber then
|
||||||
|
return shortcallsign -- Ghostrider 219
|
||||||
|
elseif ShortCallsign then
|
||||||
|
callsign = shortcallsign.." "..callnumbermajor -- Ghostrider 9
|
||||||
|
else
|
||||||
|
callsign = shortcallsign.." "..callnumbermajor.." "..callnumberminor -- Ghostrider 9 1
|
||||||
|
end
|
||||||
|
return callsign
|
||||||
|
end
|
||||||
|
|
||||||
|
-- AI or not personalized
|
||||||
|
if ShortCallsign then
|
||||||
|
callsign = callsignroot.." "..callnumbermajor -- Uzi/Victory 9
|
||||||
|
else
|
||||||
|
callsign = callsignroot.." "..callnumbermajor.." "..callnumberminor -- Uzi/Victory 9 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--self:I("Generated Callsign = " .. callsign)
|
||||||
|
end
|
||||||
|
|
||||||
|
return callsign
|
||||||
|
end
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ IDENTIFIABLE = {
|
|||||||
|
|
||||||
local _CategoryName = {
|
local _CategoryName = {
|
||||||
[Unit.Category.AIRPLANE] = "Airplane",
|
[Unit.Category.AIRPLANE] = "Airplane",
|
||||||
[Unit.Category.HELICOPTER] = "Helicoper",
|
[Unit.Category.HELICOPTER] = "Helicopter",
|
||||||
[Unit.Category.GROUND_UNIT] = "Ground Identifiable",
|
[Unit.Category.GROUND_UNIT] = "Ground Identifiable",
|
||||||
[Unit.Category.SHIP] = "Ship",
|
[Unit.Category.SHIP] = "Ship",
|
||||||
[Unit.Category.STRUCTURE] = "Structure",
|
[Unit.Category.STRUCTURE] = "Structure",
|
||||||
@@ -56,8 +56,7 @@ end
|
|||||||
-- If the Identifiable is not alive, nil is returned.
|
-- If the Identifiable is not alive, nil is returned.
|
||||||
-- If the Identifiable is alive, true is returned.
|
-- If the Identifiable is alive, true is returned.
|
||||||
-- @param #IDENTIFIABLE self
|
-- @param #IDENTIFIABLE self
|
||||||
-- @return #boolean true if Identifiable is alive.
|
-- @return #boolean true if Identifiable is alive or `#nil` if the Identifiable is not existing or is not alive.
|
||||||
-- @return #nil if the Identifiable is not existing or is not alive.
|
|
||||||
function IDENTIFIABLE:IsAlive()
|
function IDENTIFIABLE:IsAlive()
|
||||||
self:F3( self.IdentifiableName )
|
self:F3( self.IdentifiableName )
|
||||||
|
|
||||||
@@ -77,11 +76,8 @@ end
|
|||||||
--- Returns DCS Identifiable object name.
|
--- Returns DCS Identifiable object name.
|
||||||
-- The function provides access to non-activated objects too.
|
-- The function provides access to non-activated objects too.
|
||||||
-- @param #IDENTIFIABLE self
|
-- @param #IDENTIFIABLE self
|
||||||
-- @return #string The name of the DCS Identifiable.
|
-- @return #string The name of the DCS Identifiable or `#nil`.
|
||||||
-- @return #nil The DCS Identifiable is not existing or alive.
|
|
||||||
function IDENTIFIABLE:GetName()
|
function IDENTIFIABLE:GetName()
|
||||||
self:F2( self.IdentifiableName )
|
|
||||||
|
|
||||||
local IdentifiableName = self.IdentifiableName
|
local IdentifiableName = self.IdentifiableName
|
||||||
return IdentifiableName
|
return IdentifiableName
|
||||||
end
|
end
|
||||||
@@ -148,8 +144,7 @@ end
|
|||||||
|
|
||||||
--- Returns coalition of the Identifiable.
|
--- Returns coalition of the Identifiable.
|
||||||
-- @param #IDENTIFIABLE self
|
-- @param #IDENTIFIABLE self
|
||||||
-- @return DCS#coalition.side The side of the coalition.
|
-- @return DCS#coalition.side The side of the coalition or `#nil` The DCS Identifiable is not existing or alive.
|
||||||
-- @return #nil The DCS Identifiable is not existing or alive.
|
|
||||||
function IDENTIFIABLE:GetCoalition()
|
function IDENTIFIABLE:GetCoalition()
|
||||||
self:F2( self.IdentifiableName )
|
self:F2( self.IdentifiableName )
|
||||||
|
|
||||||
@@ -190,8 +185,7 @@ end
|
|||||||
|
|
||||||
--- Returns country of the Identifiable.
|
--- Returns country of the Identifiable.
|
||||||
-- @param #IDENTIFIABLE self
|
-- @param #IDENTIFIABLE self
|
||||||
-- @return DCS#country.id The country identifier.
|
-- @return DCS#country.id The country identifier or `#nil` The DCS Identifiable is not existing or alive.
|
||||||
-- @return #nil The DCS Identifiable is not existing or alive.
|
|
||||||
function IDENTIFIABLE:GetCountry()
|
function IDENTIFIABLE:GetCountry()
|
||||||
self:F2( self.IdentifiableName )
|
self:F2( self.IdentifiableName )
|
||||||
|
|
||||||
@@ -222,8 +216,7 @@ end
|
|||||||
|
|
||||||
--- Returns Identifiable descriptor. Descriptor type depends on Identifiable category.
|
--- Returns Identifiable descriptor. Descriptor type depends on Identifiable category.
|
||||||
-- @param #IDENTIFIABLE self
|
-- @param #IDENTIFIABLE self
|
||||||
-- @return DCS#Object.Desc The Identifiable descriptor.
|
-- @return DCS#Object.Desc The Identifiable descriptor or `#nil` The DCS Identifiable is not existing or alive.
|
||||||
-- @return #nil The DCS Identifiable is not existing or alive.
|
|
||||||
function IDENTIFIABLE:GetDesc()
|
function IDENTIFIABLE:GetDesc()
|
||||||
self:F2( self.IdentifiableName )
|
self:F2( self.IdentifiableName )
|
||||||
|
|
||||||
@@ -242,8 +235,7 @@ end
|
|||||||
--- Check if the Object has the attribute.
|
--- Check if the Object has the attribute.
|
||||||
-- @param #IDENTIFIABLE self
|
-- @param #IDENTIFIABLE self
|
||||||
-- @param #string AttributeName The attribute name.
|
-- @param #string AttributeName The attribute name.
|
||||||
-- @return #boolean true if the attribute exists.
|
-- @return #boolean true if the attribute exists or `#nil` The DCS Identifiable is not existing or alive.
|
||||||
-- @return #nil The DCS Identifiable is not existing or alive.
|
|
||||||
function IDENTIFIABLE:HasAttribute( AttributeName )
|
function IDENTIFIABLE:HasAttribute( AttributeName )
|
||||||
self:F2( self.IdentifiableName )
|
self:F2( self.IdentifiableName )
|
||||||
|
|
||||||
@@ -266,8 +258,10 @@ function IDENTIFIABLE:GetCallsign()
|
|||||||
return ''
|
return ''
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Gets the threat level.
|
||||||
|
-- @param #IDENTIFIABLE self
|
||||||
|
-- @return #number Threat level.
|
||||||
|
-- @return #string Type.
|
||||||
function IDENTIFIABLE:GetThreatLevel()
|
function IDENTIFIABLE:GetThreatLevel()
|
||||||
|
|
||||||
return 0, "Scenery"
|
return 0, "Scenery"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
--
|
--
|
||||||
-- ### Author: **funkyfranky**
|
-- ### Author: **funkyfranky**
|
||||||
-- @module Wrapper.Marker
|
-- @module Wrapper.Marker
|
||||||
-- @image Wrapper_Marker.png
|
-- @image MOOSE_Core.JPG
|
||||||
|
|
||||||
--- Marker class.
|
--- Marker class.
|
||||||
-- @type MARKER
|
-- @type MARKER
|
||||||
@@ -150,7 +150,7 @@ _MARKERID = 0
|
|||||||
|
|
||||||
--- Marker class version.
|
--- Marker class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
MARKER.version = "0.1.0"
|
MARKER.version="0.1.1"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -175,7 +175,9 @@ function MARKER:New( Coordinate, Text )
|
|||||||
-- Inherit everything from FSM class.
|
-- Inherit everything from FSM class.
|
||||||
local self = BASE:Inherit( self, FSM:New() ) -- #MARKER
|
local self = BASE:Inherit( self, FSM:New() ) -- #MARKER
|
||||||
|
|
||||||
self.coordinate = Coordinate
|
local self=BASE:Inherit(self, FSM:New()) -- #MARKER
|
||||||
|
|
||||||
|
self.coordinate=UTILS.DeepCopy(Coordinate)
|
||||||
|
|
||||||
self.text = Text
|
self.text = Text
|
||||||
|
|
||||||
@@ -315,6 +317,16 @@ function MARKER:ReadOnly()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Marker is readonly. Text cannot be changed and marker cannot be removed.
|
||||||
|
-- @param #MARKER self
|
||||||
|
-- @return #MARKER self
|
||||||
|
function MARKER:ReadWrite()
|
||||||
|
|
||||||
|
self.readonly=false
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
--- Set message that is displayed on screen if the marker is added.
|
--- Set message that is displayed on screen if the marker is added.
|
||||||
-- @param #MARKER self
|
-- @param #MARKER self
|
||||||
-- @param #string Text Message displayed when the marker is added.
|
-- @param #string Text Message displayed when the marker is added.
|
||||||
@@ -580,7 +592,7 @@ end
|
|||||||
|
|
||||||
--- Set text that is displayed in the marker panel. Note this does not show the marker.
|
--- Set text that is displayed in the marker panel. Note this does not show the marker.
|
||||||
-- @param #MARKER self
|
-- @param #MARKER self
|
||||||
-- @param #string Text Marker text. Default is an empty sting "".
|
-- @param #string Text Marker text. Default is an empty string "".
|
||||||
-- @return #MARKER self
|
-- @return #MARKER self
|
||||||
function MARKER:SetText( Text )
|
function MARKER:SetText( Text )
|
||||||
self.text = Text and tostring( Text ) or ""
|
self.text = Text and tostring( Text ) or ""
|
||||||
@@ -637,7 +649,9 @@ function MARKER:OnEventMarkRemoved( EventData )
|
|||||||
|
|
||||||
local MarkID = EventData.MarkID
|
local MarkID = EventData.MarkID
|
||||||
|
|
||||||
self:T3( self.lid .. string.format( "Captured event MarkAdded for Mark ID=%s", tostring( MarkID ) ) )
|
local MarkID=EventData.MarkID
|
||||||
|
|
||||||
|
self:T3(self.lid..string.format("Captured event MarkRemoved for Mark ID=%s", tostring(MarkID)))
|
||||||
|
|
||||||
if MarkID == self.mid then
|
if MarkID == self.mid then
|
||||||
|
|
||||||
@@ -664,16 +678,22 @@ function MARKER:OnEventMarkChange( EventData )
|
|||||||
|
|
||||||
if MarkID == self.mid then
|
if MarkID == self.mid then
|
||||||
|
|
||||||
self:Changed( EventData )
|
local MarkID=EventData.MarkID
|
||||||
|
|
||||||
self:TextChanged( tostring( EventData.MarkText ) )
|
self:T3(self.lid..string.format("Captured event MarkChange for Mark ID=%s", tostring(MarkID)))
|
||||||
|
|
||||||
|
if MarkID==self.mid then
|
||||||
|
|
||||||
|
self.text=tostring(EventData.MarkText)
|
||||||
|
|
||||||
|
self:Changed(EventData)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- FSM Event Functions
|
-- FSM Event Functions
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -381,10 +381,10 @@ function POSITIONABLE:GetCoordinate()
|
|||||||
-- Get the current position.
|
-- Get the current position.
|
||||||
local PositionableVec3 = self:GetVec3()
|
local PositionableVec3 = self:GetVec3()
|
||||||
|
|
||||||
local coord = COORDINATE:NewFromVec3( PositionableVec3 )
|
local coord=COORDINATE:NewFromVec3(PositionableVec3)
|
||||||
local heading = self:GetHeading()
|
local heading = self:GetHeading()
|
||||||
coord.Heading = heading
|
coord.Heading = heading
|
||||||
-- Return a new coordinate object.
|
-- Return a new coordiante object.
|
||||||
return coord
|
return coord
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -703,11 +703,11 @@ function POSITIONABLE:IsSubmarine()
|
|||||||
|
|
||||||
if DCSUnit then
|
if DCSUnit then
|
||||||
local UnitDescriptor = DCSUnit:getDesc()
|
local UnitDescriptor = DCSUnit:getDesc()
|
||||||
if UnitDescriptor.attributes["Submarines"] == true then
|
if UnitDescriptor.attributes["Submarines"] == true then
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self:E( { "Cannot check IsSubmarine", Positionable = self, Alive = self:IsAlive() } )
|
self:E( { "Cannot check IsSubmarine", Positionable = self, Alive = self:IsAlive() } )
|
||||||
@@ -779,11 +779,11 @@ function POSITIONABLE:GetRelativeVelocity( Positionable )
|
|||||||
return UTILS.VecNorm( vtot )
|
return UTILS.VecNorm( vtot )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Returns the POSITIONABLE height above sea level in meters.
|
--- Returns the POSITIONABLE height above sea level in meters.
|
||||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||||
-- @return DCS#Vec3 The height of the POSITIONABLE in meters.
|
-- @return DCS#Vec3 Height of the positionable in meters (or nil, if the object does not exist).
|
||||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
function POSITIONABLE:GetHeight() --R2.1
|
||||||
function POSITIONABLE:GetHeight()
|
|
||||||
self:F2( self.PositionableName )
|
self:F2( self.PositionableName )
|
||||||
|
|
||||||
local DCSPositionable = self:GetDCSObject()
|
local DCSPositionable = self:GetDCSObject()
|
||||||
@@ -1232,6 +1232,33 @@ function POSITIONABLE:MessageToGroup( Message, Duration, MessageGroup, Name )
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Send a message to a @{Wrapper.Unit}.
|
||||||
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
|
-- @param #POSITIONABLE self
|
||||||
|
-- @param #string Message The message text
|
||||||
|
-- @param DCS#Duration Duration The duration of the message.
|
||||||
|
-- @param Wrapper.Unit#UNIT MessageUnit The UNIT object receiving the message.
|
||||||
|
-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable.
|
||||||
|
function POSITIONABLE:MessageToUnit( Message, Duration, MessageUnit, Name )
|
||||||
|
self:F2( { Message, Duration } )
|
||||||
|
|
||||||
|
local DCSObject = self:GetDCSObject()
|
||||||
|
if DCSObject then
|
||||||
|
if DCSObject:isExist() then
|
||||||
|
if MessageUnit:IsAlive() then
|
||||||
|
self:GetMessage( Message, Duration, Name ):ToUnit( MessageUnit )
|
||||||
|
else
|
||||||
|
BASE:E( { "Message not sent to Unit; Unit is not alive...", Message = Message, MessageUnit = MessageUnit } )
|
||||||
|
end
|
||||||
|
else
|
||||||
|
BASE:E( { "Message not sent to Unit; Positionable is not alive ...", Message = Message, Positionable = self, MessageUnit = MessageUnit } )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Send a message of a message type to a @{Wrapper.Group}.
|
--- Send a message of a message type to a @{Wrapper.Group}.
|
||||||
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
@@ -1298,6 +1325,30 @@ function POSITIONABLE:MessageToSetUnit( Message, Duration, MessageSetUnit, Name
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Send a message to a @{Core.Set#SET_UNIT}.
|
||||||
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
|
-- @param #POSITIONABLE self
|
||||||
|
-- @param #string Message The message text
|
||||||
|
-- @param DCS#Duration Duration The duration of the message.
|
||||||
|
-- @param Core.Set#SET_UNIT MessageSetUnit The SET_UNIT collection receiving the message.
|
||||||
|
-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable.
|
||||||
|
function POSITIONABLE:MessageToSetUnit( Message, Duration, MessageSetUnit, Name )
|
||||||
|
self:F2( { Message, Duration } )
|
||||||
|
|
||||||
|
local DCSObject = self:GetDCSObject()
|
||||||
|
if DCSObject then
|
||||||
|
if DCSObject:isExist() then
|
||||||
|
MessageSetUnit:ForEachUnit(
|
||||||
|
function( MessageGroup )
|
||||||
|
self:GetMessage( Message, Duration, Name ):ToUnit( MessageGroup )
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Send a message to the players in the @{Wrapper.Group}.
|
--- Send a message to the players in the @{Wrapper.Group}.
|
||||||
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
@@ -1480,17 +1531,15 @@ do -- Cargo
|
|||||||
return ItemCount
|
return ItemCount
|
||||||
end
|
end
|
||||||
|
|
||||||
-- --- Get Cargo Bay Free Volume in m3.
|
--- Get the number of infantry soldiers that can be embarked into an aircraft (airplane or helicopter).
|
||||||
-- -- @param #POSITIONABLE self
|
-- Returns `nil` for ground or ship units.
|
||||||
-- -- @return #number CargoBayFreeVolume
|
-- @param #POSITIONABLE self
|
||||||
-- function POSITIONABLE:GetCargoBayFreeVolume()
|
-- @return #number Descent number of soldiers that fit into the unit. Returns `#nil` for ground and ship units.
|
||||||
-- local CargoVolume = 0
|
function POSITIONABLE:GetTroopCapacity()
|
||||||
-- for CargoName, Cargo in pairs( self.__.Cargo ) do
|
local DCSunit=self:GetDCSObject() --DCS#Unit
|
||||||
-- CargoVolume = CargoVolume + Cargo:GetVolume()
|
local capacity=DCSunit:getDescentCapacity()
|
||||||
-- end
|
return capacity
|
||||||
-- return self.__.CargoBayVolumeLimit - CargoVolume
|
end
|
||||||
-- end
|
|
||||||
--
|
|
||||||
|
|
||||||
--- Get Cargo Bay Free Weight in kg.
|
--- Get Cargo Bay Free Weight in kg.
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
@@ -1509,55 +1558,97 @@ do -- Cargo
|
|||||||
return self.__.CargoBayWeightLimit - CargoWeight
|
return self.__.CargoBayWeightLimit - CargoWeight
|
||||||
end
|
end
|
||||||
|
|
||||||
-- --- Get Cargo Bay Volume Limit in m3.
|
|
||||||
-- -- @param #POSITIONABLE self
|
|
||||||
-- -- @param #number VolumeLimit
|
|
||||||
-- function POSITIONABLE:SetCargoBayVolumeLimit( VolumeLimit )
|
|
||||||
-- self.__.CargoBayVolumeLimit = VolumeLimit
|
|
||||||
-- end
|
|
||||||
|
|
||||||
--- Set Cargo Bay Weight Limit in kg.
|
--- Set Cargo Bay Weight Limit in kg.
|
||||||
-- @param #POSITIONABLE self
|
-- @param #POSITIONABLE self
|
||||||
-- @param #number WeightLimit
|
-- @param #number WeightLimit (Optional) Weight limit in kg. If not given, the value is taken from the descriptors or hard coded.
|
||||||
function POSITIONABLE:SetCargoBayWeightLimit( WeightLimit )
|
function POSITIONABLE:SetCargoBayWeightLimit( WeightLimit )
|
||||||
|
|
||||||
if WeightLimit then
|
if WeightLimit then
|
||||||
|
---
|
||||||
|
-- User defined value
|
||||||
|
---
|
||||||
self.__.CargoBayWeightLimit = WeightLimit
|
self.__.CargoBayWeightLimit = WeightLimit
|
||||||
elseif self.__.CargoBayWeightLimit ~= nil then
|
elseif self.__.CargoBayWeightLimit ~= nil then
|
||||||
-- Value already set ==> Do nothing!
|
-- Value already set ==> Do nothing!
|
||||||
else
|
else
|
||||||
-- If WeightLimit is not provided, we will calculate it depending on the type of unit.
|
---
|
||||||
|
-- Weightlimit is not provided, we will calculate it depending on the type of unit.
|
||||||
|
---
|
||||||
|
|
||||||
|
-- Descriptors that contain the type name and for aircraft also weights.
|
||||||
|
local Desc = self:GetDesc()
|
||||||
|
self:F({Desc=Desc})
|
||||||
|
|
||||||
|
-- Unit type name.
|
||||||
|
local TypeName=Desc.typeName or "Unknown Type"
|
||||||
|
|
||||||
-- When an airplane or helicopter, we calculate the WeightLimit based on the descriptor.
|
-- When an airplane or helicopter, we calculate the WeightLimit based on the descriptor.
|
||||||
if self:IsAir() then
|
if self:IsAir() then
|
||||||
local Desc = self:GetDesc()
|
|
||||||
self:F( { Desc = Desc } )
|
|
||||||
|
|
||||||
|
-- Max takeoff weight if DCS descriptors have unrealstic values.
|
||||||
local Weights = {
|
local Weights = {
|
||||||
["C-17A"] = 35000, -- 77519 cannot be used, because it loads way too many APCs and infantry.
|
-- C-17A
|
||||||
["C-130"] = 22000 -- The real value cannot be used, because it loads way too many APCs and infantry.
|
-- Wiki says: max=265,352, empty=128,140, payload=77,516 (134 troops, 1 M1 Abrams tank, 2 M2 Bradley or 3 Stryker)
|
||||||
|
-- DCS says: max=265,350, empty=125,645, fuel=132,405 ==> Cargo Bay=7300 kg with a full fuel load (lot of fuel!) and 73300 with half a fuel load.
|
||||||
|
--["C-17A"] = 35000, --77519 cannot be used, because it loads way too much apcs and infantry.
|
||||||
|
-- C-130:
|
||||||
|
-- DCS says: max=79,380, empty=36,400, fuel=10,415 kg ==> Cargo Bay=32,565 kg with fuel load.
|
||||||
|
-- Wiki says: max=70,307, empty=34,382, payload=19,000 kg (92 passengers, 2-3 Humvees or 2 M113s), max takeoff weight 70,037 kg.
|
||||||
|
-- Here we say two M113s should be transported. Each one weights 11,253 kg according to DCS. So the cargo weight should be 23,000 kg with a full load of fuel.
|
||||||
|
-- This results in a max takeoff weight of 69,815 kg (23,000+10,415+36,400), which is very close to the Wiki value of 70,037 kg.
|
||||||
|
["C-130"] = 70000,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.__.CargoBayWeightLimit = Weights[Desc.typeName] or (Desc.massMax - (Desc.massEmpty + Desc.fuelMassMax))
|
-- Max (takeoff) weight (empty+fuel+cargo weight).
|
||||||
|
local massMax= Desc.massMax or 0
|
||||||
|
|
||||||
|
-- Adjust value if set above.
|
||||||
|
local maxTakeoff=Weights[TypeName]
|
||||||
|
if maxTakeoff then
|
||||||
|
massMax=maxTakeoff
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Empty weight.
|
||||||
|
local massEmpty=Desc.massEmpty or 0
|
||||||
|
|
||||||
|
-- Fuel. The descriptor provides the max fuel mass in kg. This needs to be multiplied by the relative fuel amount to calculate the actual fuel mass on board.
|
||||||
|
local massFuelMax=Desc.fuelMassMax or 0
|
||||||
|
local relFuel=math.min(self:GetFuel() or 1.0, 1.0) -- We take 1.0 as max in case of external fuel tanks.
|
||||||
|
local massFuel=massFuelMax*relFuel
|
||||||
|
|
||||||
|
-- Number of soldiers according to DCS function
|
||||||
|
--local troopcapacity=self:GetTroopCapacity() or 0
|
||||||
|
|
||||||
|
-- Calculate max cargo weight, which is the max (takeoff) weight minus the empty weight minus the actual fuel weight.
|
||||||
|
local CargoWeight=massMax-(massEmpty+massFuel)
|
||||||
|
|
||||||
|
-- Debug info.
|
||||||
|
self:T(string.format("Setting Cargo bay weight limit [%s]=%d kg (Mass max=%d, empty=%d, fuelMax=%d kg (rel=%.3f), fuel=%d kg", TypeName, CargoWeight, massMax, massEmpty, massFuelMax, relFuel, massFuel))
|
||||||
|
--self:T(string.format("Descent Troop Capacity=%d ==> %d kg (for 95 kg soldier)", troopcapacity, troopcapacity*95))
|
||||||
|
|
||||||
|
-- Set value.
|
||||||
|
self.__.CargoBayWeightLimit = CargoWeight
|
||||||
|
|
||||||
elseif self:IsShip() then
|
elseif self:IsShip() then
|
||||||
local Desc = self:GetDesc()
|
|
||||||
self:F( { Desc = Desc } )
|
|
||||||
|
|
||||||
|
-- Hard coded cargo weights in kg.
|
||||||
local Weights = {
|
local Weights = {
|
||||||
["Type_071"] = 245000,
|
["Type_071"] = 245000,
|
||||||
["LHA_Tarawa"] = 500000,
|
["LHA_Tarawa"] = 500000,
|
||||||
["Ropucha-class"] = 150000,
|
["Ropucha-class"] = 150000,
|
||||||
["Dry-cargo ship-1"] = 70000,
|
["Dry-cargo ship-1"] = 70000,
|
||||||
["Dry-cargo ship-2"] = 70000,
|
["Dry-cargo ship-2"] = 70000,
|
||||||
["Higgins_boat"] = 3700, -- Higgins Boat can load 3700 kg of general cargo or 36 men (source wikipedia).
|
["Higgins_boat"] = 3700, -- Higgins Boat can load 3700 kg of general cargo or 36 men (source wikipedia).
|
||||||
["USS_Samuel_Chase"] = 25000, -- Let's say 25 tons for now. Wiki says 33 Higgins boats, which would be 264 tons (can't be right!) and/or 578 troops.
|
["USS_Samuel_Chase"] = 25000, -- Let's say 25 tons for now. Wiki says 33 Higgins boats, which would be 264 tons (can't be right!) and/or 578 troops.
|
||||||
["LST_Mk2"] = 2100000 -- Can carry 2100 tons according to wiki source!
|
["LST_Mk2"] = 2100000, -- Can carry 2100 tons according to wiki source!
|
||||||
|
["speedboat"] = 500, -- 500 kg ~ 5 persons
|
||||||
|
["Seawise_Giant"] =261000000, -- Gross tonnage is 261,000 tonns.
|
||||||
}
|
}
|
||||||
self.__.CargoBayWeightLimit = (Weights[Desc.typeName] or 50000)
|
self.__.CargoBayWeightLimit = ( Weights[TypeName] or 50000 )
|
||||||
|
|
||||||
else
|
else
|
||||||
local Desc = self:GetDesc()
|
|
||||||
|
|
||||||
|
-- Hard coded number of soldiers.
|
||||||
local Weights = {
|
local Weights = {
|
||||||
["AAV7"] = 25,
|
["AAV7"] = 25,
|
||||||
["Bedford_MWD"] = 8, -- new by kappa
|
["Bedford_MWD"] = 8, -- new by kappa
|
||||||
@@ -1593,7 +1684,7 @@ do -- Cargo
|
|||||||
["KrAZ6322"] = 12,
|
["KrAZ6322"] = 12,
|
||||||
["M 818"] = 12,
|
["M 818"] = 12,
|
||||||
["Tigr_233036"] = 6,
|
["Tigr_233036"] = 6,
|
||||||
["TPZ"] = 10,
|
["TPZ"] = 10, -- Fuchs
|
||||||
["UAZ-469"] = 4, -- new by kappa
|
["UAZ-469"] = 4, -- new by kappa
|
||||||
["Ural-375"] = 12,
|
["Ural-375"] = 12,
|
||||||
["Ural-4320-31"] = 14,
|
["Ural-4320-31"] = 14,
|
||||||
@@ -1607,12 +1698,28 @@ do -- Cargo
|
|||||||
["HL_DSHK"] = 6,
|
["HL_DSHK"] = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
local CargoBayWeightLimit = (Weights[Desc.typeName] or 0) * 95
|
-- Assuming that each passenger weighs 95 kg on average.
|
||||||
|
local CargoBayWeightLimit = ( Weights[TypeName] or 0 ) * 95
|
||||||
|
|
||||||
self.__.CargoBayWeightLimit = CargoBayWeightLimit
|
self.__.CargoBayWeightLimit = CargoBayWeightLimit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:F( { CargoBayWeightLimit = self.__.CargoBayWeightLimit } )
|
|
||||||
|
self:F({CargoBayWeightLimit = self.__.CargoBayWeightLimit})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Get Cargo Bay Weight Limit in kg.
|
||||||
|
-- @param #POSITIONABLE self
|
||||||
|
-- @return #number Max cargo weight in kg.
|
||||||
|
function POSITIONABLE:GetCargoBayWeightLimit()
|
||||||
|
|
||||||
|
if self.__.CargoBayWeightLimit==nil then
|
||||||
|
self:SetCargoBayWeightLimit()
|
||||||
|
end
|
||||||
|
|
||||||
|
return self.__.CargoBayWeightLimit
|
||||||
|
end
|
||||||
|
|
||||||
end --- Cargo
|
end --- Cargo
|
||||||
|
|
||||||
--- Signal a flare at the position of the POSITIONABLE.
|
--- Signal a flare at the position of the POSITIONABLE.
|
||||||
|
|||||||
@@ -57,3 +57,40 @@ end
|
|||||||
function SCENERY:GetThreatLevel()
|
function SCENERY:GetThreatLevel()
|
||||||
return 0, "Scenery"
|
return 0, "Scenery"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Find a SCENERY object by it's name/id.
|
||||||
|
--@param #SCENERY self
|
||||||
|
--@param #string name The name/id of the scenery object as taken from the ME. Ex. '595785449'
|
||||||
|
--@return #SCENERY Scenery Object or nil if not found.
|
||||||
|
function SCENERY:FindByName(name)
|
||||||
|
local findAirbase = function ()
|
||||||
|
local airbases = AIRBASE.GetAllAirbases()
|
||||||
|
for index,airbase in pairs(airbases) do
|
||||||
|
local surftype = airbase:GetCoordinate():GetSurfaceType()
|
||||||
|
if surftype ~= land.SurfaceType.SHALLOW_WATER and surftype ~= land.SurfaceType.WATER then
|
||||||
|
return airbase:GetCoordinate()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local sceneryScan = function (scancoord)
|
||||||
|
if scancoord ~= nil then
|
||||||
|
local _,_,sceneryfound,_,_,scenerylist = scancoord:ScanObjects(200, false, false, true)
|
||||||
|
if sceneryfound == true then
|
||||||
|
scenerylist[1].id_ = name
|
||||||
|
SCENERY.SceneryObject = SCENERY:Register(scenerylist[1].id_, scenerylist[1])
|
||||||
|
return SCENERY.SceneryObject
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if SCENERY.SceneryObject then
|
||||||
|
SCENERY.SceneryObject.SceneryObject.id_ = name
|
||||||
|
SCENERY.SceneryObject.SceneryName = name
|
||||||
|
return SCENERY:Register(SCENERY.SceneryObject.SceneryObject.id_, SCENERY.SceneryObject.SceneryObject)
|
||||||
|
else
|
||||||
|
return sceneryScan(findAirbase())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
--- @type UNIT
|
--- @type UNIT
|
||||||
-- @field #string ClassName Name of the class.
|
-- @field #string ClassName Name of the class.
|
||||||
-- @field #string UnitName Name of the unit.
|
-- @field #string UnitName Name of the unit.
|
||||||
|
-- @field #string GroupName Name of the group the unit belongs to.
|
||||||
-- @extends Wrapper.Controllable#CONTROLLABLE
|
-- @extends Wrapper.Controllable#CONTROLLABLE
|
||||||
|
|
||||||
--- For each DCS Unit object alive within a running mission, a UNIT wrapper object (instance) will be created within the _@{DATABASE} object.
|
--- For each DCS Unit object alive within a running mission, a UNIT wrapper object (instance) will be created within the _@{DATABASE} object.
|
||||||
@@ -86,11 +87,11 @@
|
|||||||
-- * Use the @{#UNIT.IsLOS}() method to check if the given unit is within line of sight.
|
-- * Use the @{#UNIT.IsLOS}() method to check if the given unit is within line of sight.
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- @field #UNIT UNIT
|
-- @field #UNIT
|
||||||
UNIT = {
|
UNIT = {
|
||||||
ClassName="UNIT",
|
ClassName="UNIT",
|
||||||
UnitName=nil,
|
UnitName=nil,
|
||||||
GroupName=nil,
|
GroupName=nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -697,6 +698,7 @@ end
|
|||||||
-- @return #number Number of rockets left.
|
-- @return #number Number of rockets left.
|
||||||
-- @return #number Number of bombs left.
|
-- @return #number Number of bombs left.
|
||||||
-- @return #number Number of missiles left.
|
-- @return #number Number of missiles left.
|
||||||
|
-- @return #number Number of artillery shells left (with explosive mass, included in shells; shells can also be machine gun ammo)
|
||||||
function UNIT:GetAmmunition()
|
function UNIT:GetAmmunition()
|
||||||
|
|
||||||
-- Init counter.
|
-- Init counter.
|
||||||
@@ -705,6 +707,7 @@ function UNIT:GetAmmunition()
|
|||||||
local nrockets=0
|
local nrockets=0
|
||||||
local nmissiles=0
|
local nmissiles=0
|
||||||
local nbombs=0
|
local nbombs=0
|
||||||
|
local narti=0
|
||||||
|
|
||||||
local unit=self
|
local unit=self
|
||||||
|
|
||||||
@@ -742,6 +745,10 @@ function UNIT:GetAmmunition()
|
|||||||
-- Add up all shells.
|
-- Add up all shells.
|
||||||
nshells=nshells+Nammo
|
nshells=nshells+Nammo
|
||||||
|
|
||||||
|
if ammotable[w].desc.warhead and ammotable[w].desc.warhead.explosiveMass and ammotable[w].desc.warhead.explosiveMass > 0 then
|
||||||
|
narti=narti+Nammo
|
||||||
|
end
|
||||||
|
|
||||||
elseif Category==Weapon.Category.ROCKET then
|
elseif Category==Weapon.Category.ROCKET then
|
||||||
|
|
||||||
-- Add up all rockets.
|
-- Add up all rockets.
|
||||||
@@ -778,7 +785,7 @@ function UNIT:GetAmmunition()
|
|||||||
-- Total amount of ammunition.
|
-- Total amount of ammunition.
|
||||||
nammo=nshells+nrockets+nmissiles+nbombs
|
nammo=nshells+nrockets+nmissiles+nbombs
|
||||||
|
|
||||||
return nammo, nshells, nrockets, nbombs, nmissiles
|
return nammo, nshells, nrockets, nbombs, nmissiles, narti
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Returns the unit sensors.
|
--- Returns the unit sensors.
|
||||||
@@ -829,7 +836,9 @@ function UNIT:HasSEAD()
|
|||||||
|
|
||||||
local HasSEAD = false
|
local HasSEAD = false
|
||||||
if UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] == true or
|
if UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND1_FOR_ARM"] == true or
|
||||||
UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] == true then
|
UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] and UnitSEADAttributes["RADAR_BAND2_FOR_ARM"] == true or
|
||||||
|
UnitSEADAttributes["Optical Tracker"] and UnitSEADAttributes["Optical Tracker"] == true
|
||||||
|
then
|
||||||
HasSEAD = true
|
HasSEAD = true
|
||||||
end
|
end
|
||||||
return HasSEAD
|
return HasSEAD
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ Utilities/Profiler.lua
|
|||||||
Utilities/Templates.lua
|
Utilities/Templates.lua
|
||||||
Utilities/STTS.lua
|
Utilities/STTS.lua
|
||||||
Utilities/FiFo.lua
|
Utilities/FiFo.lua
|
||||||
|
Utilities/Socket.lua
|
||||||
|
|
||||||
Core/Base.lua
|
Core/Base.lua
|
||||||
Core/Beacon.lua
|
Core/Beacon.lua
|
||||||
@@ -29,6 +30,10 @@ Core/SpawnStatic.lua
|
|||||||
Core/Timer.lua
|
Core/Timer.lua
|
||||||
Core/Goal.lua
|
Core/Goal.lua
|
||||||
Core/Spot.lua
|
Core/Spot.lua
|
||||||
|
Core/MarkerOps_Base.lua
|
||||||
|
Core/Astar.lua
|
||||||
|
Core/Condition.lua
|
||||||
|
Core/TextAndSound.lua
|
||||||
|
|
||||||
Wrapper/Object.lua
|
Wrapper/Object.lua
|
||||||
Wrapper/Identifiable.lua
|
Wrapper/Identifiable.lua
|
||||||
|
|||||||
Reference in New Issue
Block a user