Merge branch 'FF/Develop' into FF/Fox2

This commit is contained in:
Frank
2019-09-13 19:43:17 +02:00
43 changed files with 2059 additions and 1079 deletions
+11 -11
View File
@@ -433,7 +433,7 @@ function AI_A2A:onafterStatus()
self:F({DistanceFromHomeBase=DistanceFromHomeBase}) self:F({DistanceFromHomeBase=DistanceFromHomeBase})
if DistanceFromHomeBase > self.DisengageRadius then if DistanceFromHomeBase > self.DisengageRadius then
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" ) self:I( self.Controllable:GetName() .. " is too far from home base, RTB!" )
self:Hold( 300 ) self:Hold( 300 )
RTB = false RTB = false
end end
@@ -453,10 +453,10 @@ function AI_A2A:onafterStatus()
self:F({Fuel=Fuel, PatrolFuelThresholdPercentage=self.PatrolFuelThresholdPercentage}) self:F({Fuel=Fuel, PatrolFuelThresholdPercentage=self.PatrolFuelThresholdPercentage})
if Fuel < self.PatrolFuelThresholdPercentage then if Fuel < self.PatrolFuelThresholdPercentage then
if self.TankerName then if self.TankerName then
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" ) self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
self:Refuel() self:Refuel()
else else
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" ) self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
local OldAIControllable = self.Controllable local OldAIControllable = self.Controllable
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed ) local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
@@ -475,7 +475,7 @@ function AI_A2A:onafterStatus()
local InitialLife = self.Controllable:GetLife0() local InitialLife = self.Controllable:GetLife0()
self:F( { Damage = Damage, InitialLife = InitialLife, DamageThreshold = self.PatrolDamageThreshold } ) self:F( { Damage = Damage, InitialLife = InitialLife, DamageThreshold = self.PatrolDamageThreshold } )
if ( Damage / InitialLife ) < self.PatrolDamageThreshold then if ( Damage / InitialLife ) < self.PatrolDamageThreshold then
self:E( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" ) self:I( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" )
self:Damaged() self:Damaged()
RTB = true RTB = true
self:SetStatusOff() self:SetStatusOff()
@@ -493,7 +493,7 @@ function AI_A2A:onafterStatus()
if Damage ~= InitialLife then if Damage ~= InitialLife then
self:Damaged() self:Damaged()
else else
self:E( self.Controllable:GetName() .. " control lost! " ) self:I( self.Controllable:GetName() .. " control lost! " )
self:LostControl() self:LostControl()
end end
else else
@@ -549,7 +549,7 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
if AIGroup and AIGroup:IsAlive() then if AIGroup and AIGroup:IsAlive() then
self:E( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" ) self:I( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
self:ClearTargetDistance() self:ClearTargetDistance()
AIGroup:ClearTasks() AIGroup:ClearTasks()
@@ -567,7 +567,7 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
local ToAirbaseCoord = CurrentCoord:Translate( 5000, ToAirbaseAngle ) local ToAirbaseCoord = CurrentCoord:Translate( 5000, ToAirbaseAngle )
if Distance < 5000 then if Distance < 5000 then
self:E( "RTB and near the airbase!" ) self:I( "RTB and near the airbase!" )
self:Home() self:Home()
return return
end end
@@ -608,7 +608,7 @@ end
function AI_A2A:onafterHome( AIGroup, From, Event, To ) function AI_A2A:onafterHome( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } ) self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" ) self:I( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then if AIGroup and AIGroup:IsAlive() then
end end
@@ -622,7 +622,7 @@ end
function AI_A2A:onafterHold( AIGroup, From, Event, To, HoldTime ) function AI_A2A:onafterHold( AIGroup, From, Event, To, HoldTime )
self:F( { AIGroup, From, Event, To } ) self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" ) self:I( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then if AIGroup and AIGroup:IsAlive() then
local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed ) local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
@@ -654,7 +654,7 @@ end
function AI_A2A:onafterRefuel( AIGroup, From, Event, To ) function AI_A2A:onafterRefuel( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } ) self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Refuelling! ( " .. self:GetState() .. " )" ) self:I( "Group " .. self.Controllable:GetName() .. " ... Refuelling! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then if AIGroup and AIGroup:IsAlive() then
local Tanker = GROUP:FindByName( self.TankerName ) local Tanker = GROUP:FindByName( self.TankerName )
@@ -711,7 +711,7 @@ end
function AI_A2A:OnCrash( EventData ) function AI_A2A:OnCrash( EventData )
if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then
self:E( self.Controllable:GetUnits() ) self:I( self.Controllable:GetUnits() )
if #self.Controllable:GetUnits() == 1 then if #self.Controllable:GetUnits() == 1 then
self:__Crash( 1, EventData ) self:__Crash( 1, EventData )
end end
@@ -278,6 +278,8 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
-- @param #AI_A2A_CAP self -- @param #AI_A2A_CAP self
-- @param #number Delay The delay in seconds. -- @param #number Delay The delay in seconds.
self:AddTransition( { "Patrolling", "Engaging" }, "Refuel", "Refuelling" )
return self return self
end end
@@ -279,6 +279,8 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
-- @param #AI_A2A_GCI self -- @param #AI_A2A_GCI self
-- @param #number Delay The delay in seconds. -- @param #number Delay The delay in seconds.
self:AddTransition( { "Patrolling", "Engaging" }, "Refuel", "Refuelling" )
return self return self
end end
+16 -3
View File
@@ -62,12 +62,14 @@ end
-- @param #string To The To State string. -- @param #string To The To State string.
function AI_A2G_BAI:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit ) function AI_A2G_BAI:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit )
self:F( { DefenderGroup, From, Event, To, AttackSetUnit} ) self:I( { DefenderGroup, From, Event, To, AttackSetUnit} )
local DefenderGroupName = DefenderGroup:GetName() local DefenderGroupName = DefenderGroup:GetName()
local AttackCount = AttackSetUnit:Count() local AttackCount = AttackSetUnit:Count()
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
if AttackCount > 0 then if AttackCount > 0 then
if DefenderGroup:IsAlive() then if DefenderGroup:IsAlive() then
@@ -129,7 +131,7 @@ function AI_A2G_BAI:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit
end end
if #AttackUnitTasks == 0 then if #AttackUnitTasks == 0 then
self:E( DefenderGroupName .. ": No targets found -> Going RTB") self:I( DefenderGroupName .. ": No targets found -> Going RTB")
self:Return() self:Return()
self:__RTB( self.TaskDelay ) self:__RTB( self.TaskDelay )
else else
@@ -146,8 +148,19 @@ function AI_A2G_BAI:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit
DefenderGroup:Route( EngageRoute, self.TaskDelay ) DefenderGroup:Route( EngageRoute, self.TaskDelay )
end end
else else
self:E( DefenderGroupName .. ": No targets found -> Going RTB") self:I( DefenderGroupName .. ": No targets found -> Going RTB")
self:Return() self:Return()
self:__RTB( self.TaskDelay ) self:__RTB( self.TaskDelay )
end end
end end
--- @param Wrapper.Group#GROUP AIEngage
function AI_A2G_BAI.Resume( AIEngage, Fsm )
AIEngage:F( { "AI_A2G_BAI.Resume:", AIEngage:GetName() } )
if AIEngage:IsAlive() then
Fsm:__Reset( Fsm.TaskDelay )
Fsm:__EngageRoute( Fsm.TaskDelay, Fsm.AttackSetUnit )
end
end
+14 -2
View File
@@ -66,6 +66,8 @@ function AI_A2G_CAS:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit
local DefenderGroupName = DefenderGroup:GetName() local DefenderGroupName = DefenderGroup:GetName()
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
local AttackCount = AttackSetUnit:Count() local AttackCount = AttackSetUnit:Count()
if AttackCount > 0 then if AttackCount > 0 then
@@ -124,7 +126,7 @@ function AI_A2G_CAS:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit
if #AttackUnitTasks == 0 then if #AttackUnitTasks == 0 then
self:E( DefenderGroupName .. ": No targets found -> Going RTB") self:I( DefenderGroupName .. ": No targets found -> Going RTB")
self:Return() self:Return()
self:__RTB( self.TaskDelay ) self:__RTB( self.TaskDelay )
else else
@@ -142,9 +144,19 @@ function AI_A2G_CAS:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit
DefenderGroup:Route( EngageRoute, self.TaskDelay ) DefenderGroup:Route( EngageRoute, self.TaskDelay )
end end
else else
self:E( DefenderGroupName .. ": No targets found -> Going RTB") self:I( DefenderGroupName .. ": No targets found -> Going RTB")
self:Return() self:Return()
self:__RTB( self.TaskDelay ) self:__RTB( self.TaskDelay )
end end
end end
--- @param Wrapper.Group#GROUP AIEngage
function AI_A2G_CAS.Resume( AIEngage, Fsm )
AIEngage:F( { "AI_A2G_CAS.Resume:", AIEngage:GetName() } )
if AIEngage:IsAlive() then
Fsm:__Reset( Fsm.TaskDelay )
Fsm:__EngageRoute( Fsm.TaskDelay, Fsm.AttackSetUnit )
end
end
+291 -136
View File
@@ -1133,7 +1133,7 @@ do -- AI_A2G_DISPATCHER
self.TakeoffScheduleID = self:ScheduleRepeat( 10, 10, 0, nil, self.ResourceTakeoff, self ) self.TakeoffScheduleID = self:ScheduleRepeat( 10, 10, 0, nil, self.ResourceTakeoff, self )
self:__Start( 1 ) self:__Start( 1 )
return self return self
end end
@@ -3496,91 +3496,123 @@ do -- AI_A2G_DISPATCHER
local AI_A2G_PATROL = { SEAD = AI_A2G_SEAD, BAI = AI_A2G_BAI, CAS = AI_A2G_CAS } local AI_A2G_PATROL = { SEAD = AI_A2G_SEAD, BAI = AI_A2G_BAI, CAS = AI_A2G_CAS }
local Fsm = AI_A2G_PATROL[DefenseTaskType]:New( DefenderGroup, Patrol.EngageMinSpeed, Patrol.EngageMaxSpeed, Patrol.EngageFloorAltitude, Patrol.EngageCeilingAltitude, Patrol.Zone, Patrol.PatrolFloorAltitude, Patrol.PatrolCeilingAltitude, Patrol.PatrolMinSpeed, Patrol.PatrolMaxSpeed, Patrol.AltType ) local AI_A2G_Fsm = AI_A2G_PATROL[DefenseTaskType]:New( DefenderGroup, Patrol.EngageMinSpeed, Patrol.EngageMaxSpeed, Patrol.EngageFloorAltitude, Patrol.EngageCeilingAltitude, Patrol.Zone, Patrol.PatrolFloorAltitude, Patrol.PatrolCeilingAltitude, Patrol.PatrolMinSpeed, Patrol.PatrolMaxSpeed, Patrol.AltType )
Fsm:SetDispatcher( self ) AI_A2G_Fsm:SetDispatcher( self )
Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) AI_A2G_Fsm:SetHomeAirbase( DefenderSquadron.Airbase )
Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 ) AI_A2G_Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 )
Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold ) AI_A2G_Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold )
Fsm:SetDisengageRadius( self.DisengageRadius ) AI_A2G_Fsm:SetDisengageRadius( self.DisengageRadius )
Fsm:SetTanker( DefenderSquadron.TankerName or self.DefenderDefault.TankerName ) AI_A2G_Fsm:SetTanker( DefenderSquadron.TankerName or self.DefenderDefault.TankerName )
Fsm:Start() AI_A2G_Fsm:Start()
self:SetDefenderTask( SquadronName, DefenderGroup, DefenseTaskType, Fsm, nil, DefenderGrouping ) self:SetDefenderTask( SquadronName, DefenderGroup, DefenseTaskType, AI_A2G_Fsm, nil, DefenderGrouping )
function Fsm:onafterTakeoff( Defender, From, Event, To ) function AI_A2G_Fsm:onafterTakeoff( DefenderGroup, From, Event, To )
self:F({"Defender Birth", Defender:GetName()}) self:F({"Defender Takeoff", DefenderGroup:GetName()})
--self:GetParent(self).onafterBirth( self, Defender, From, Event, To ) --self:GetParent(self).onafterBirth( self, Defender, From, Event, To )
local DefenderName = Defender:GetCallsign() local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
if Squadron then if Squadron then
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " airborne." ) Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " airborne.", "Wheels_up.wav", 3, "A2G/", DefenderGroup )
Fsm:Patrol() -- Engage on the TargetSetUnit AI_A2G_Fsm:Patrol() -- Engage on the TargetSetUnit
end end
end end
function Fsm:onafterPatrolRoute( Defender, From, Event, To ) function AI_A2G_Fsm:onafterPatrolRoute( DefenderGroup, From, Event, To )
self:F({"Defender PatrolRoute", Defender:GetName()}) self:F({"Defender PatrolRoute", DefenderGroup:GetName()})
self:GetParent(self).onafterPatrolRoute( self, Defender, From, Event, To ) self:GetParent(self).onafterPatrolRoute( self, DefenderGroup, From, Event, To )
local DefenderName = Defender:GetCallsign() local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
if Squadron then if Squadron then
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " patrolling." ) Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " patrolling.", "Patrolling.wav", 3, "A2G/", DefenderGroup )
end end
Dispatcher:ClearDefenderTaskTarget( Defender ) Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
end end
function Fsm:onafterRTB( Defender, From, Event, To ) function AI_A2G_Fsm:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit )
self:F({"Defender RTB", Defender:GetName()}) self:F({"Engage Route", DefenderGroup:GetName()})
self:GetParent(self).onafterRTB( self, Defender, From, Event, To )
local DefenderName = Defender:GetCallsign() self:GetParent(self).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) local DefenderName = DefenderGroup:GetCallsign()
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " returning." ) local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
if Squadron then
local FirstUnit = AttackSetUnit:GetFirst()
local Coordinate = FirstUnit:GetCoordinate() -- Core.Point#COORDINATE
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " on route to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), "Moving_on_to_ground_target.wav", 3, "A2G/", DefenderGroup )
end
end
Dispatcher:ClearDefenderTaskTarget( Defender ) function AI_A2G_Fsm:OnAfterEngage( DefenderGroup, From, Event, To, AttackSetUnit )
self:F({"Engage Route", DefenderGroup:GetName()})
--self:GetParent(self).onafterBirth( self, Defender, From, Event, To )
local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
local FirstUnit = AttackSetUnit:GetFirst()
if FirstUnit then
local Coordinate = FirstUnit:GetCoordinate()
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " engaging ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), "Engaging_ground_target.wav", 3, "A2G/", DefenderGroup )
end
end
function AI_A2G_Fsm:onafterRTB( DefenderGroup, From, Event, To )
self:F({"Defender RTB", DefenderGroup:GetName()})
self:GetParent(self).onafterRTB( self, DefenderGroup, From, Event, To )
local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " returning.", "Returning_to_base.wav", 3, "A2G/", DefenderGroup )
Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
end end
--- @param #AI_A2G_DISPATCHER self --- @param #AI_A2G_DISPATCHER self
function Fsm:onafterLostControl( Defender, From, Event, To ) function AI_A2G_Fsm:onafterLostControl( DefenderGroup, From, Event, To )
self:F({"Defender LostControl", Defender:GetName()}) self:F({"Defender LostControl", DefenderGroup:GetName()})
self:GetParent(self).onafterHome( self, Defender, From, Event, To ) self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
local DefenderName = Defender:GetCallsign() local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " lost control." ) Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " lost control." )
if Defender:IsAboveRunway() then if DefenderGroup:IsAboveRunway() then
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
Defender:Destroy() DefenderGroup:Destroy()
end end
end end
--- @param #AI_A2G_DISPATCHER self --- @param #AI_A2G_DISPATCHER self
function Fsm:onafterHome( Defender, From, Event, To, Action ) function AI_A2G_Fsm:onafterHome( DefenderGroup, From, Event, To, Action )
self:F({"Defender Home", Defender:GetName()}) self:F({"Defender Home", DefenderGroup:GetName()})
self:GetParent(self).onafterHome( self, Defender, From, Event, To ) self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
local DefenderName = Defender:GetCallsign() local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " landing." ) Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " landing.", "Landing_at_base.wav", 3, "A2G/", DefenderGroup )
if Action and Action == "Destroy" then if Action and Action == "Destroy" then
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
Defender:Destroy() DefenderGroup:Destroy()
end end
if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2G_DISPATCHER.Landing.NearAirbase then if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2G_DISPATCHER.Landing.NearAirbase then
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
Defender:Destroy() DefenderGroup:Destroy()
Dispatcher:ResourcePark( Squadron, Defender ) Dispatcher:ResourcePark( Squadron, DefenderGroup )
end end
end end
end end
@@ -3605,112 +3637,112 @@ do -- AI_A2G_DISPATCHER
local AI_A2G = { SEAD = AI_A2G_SEAD, BAI = AI_A2G_BAI, CAS = AI_A2G_CAS } local AI_A2G = { SEAD = AI_A2G_SEAD, BAI = AI_A2G_BAI, CAS = AI_A2G_CAS }
local Fsm = AI_A2G[DefenseTaskType]:New( DefenderGroup, Defense.EngageMinSpeed, Defense.EngageMaxSpeed, Defense.EngageFloorAltitude, Defense.EngageCeilingAltitude ) -- AI.AI_A2G_ENGAGE local AI_A2G_Fsm = AI_A2G[DefenseTaskType]:New( DefenderGroup, Defense.EngageMinSpeed, Defense.EngageMaxSpeed, Defense.EngageFloorAltitude, Defense.EngageCeilingAltitude ) -- AI.AI_A2G_ENGAGE
Fsm:SetDispatcher( self ) AI_A2G_Fsm:SetDispatcher( self )
Fsm:SetHomeAirbase( DefenderSquadron.Airbase ) AI_A2G_Fsm:SetHomeAirbase( DefenderSquadron.Airbase )
Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 ) AI_A2G_Fsm:SetFuelThreshold( DefenderSquadron.FuelThreshold or self.DefenderDefault.FuelThreshold, 60 )
Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold ) AI_A2G_Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold )
Fsm:SetDisengageRadius( self.DisengageRadius ) AI_A2G_Fsm:SetDisengageRadius( self.DisengageRadius )
Fsm:Start() AI_A2G_Fsm:Start()
self:SetDefenderTask( SquadronName, DefenderGroup, DefenseTaskType, Fsm, AttackerDetection, DefenderGrouping ) self:SetDefenderTask( SquadronName, DefenderGroup, DefenseTaskType, AI_A2G_Fsm, AttackerDetection, DefenderGrouping )
function Fsm:onafterTakeoff( Defender, From, Event, To ) function AI_A2G_Fsm:onafterTakeoff( DefenderGroup, From, Event, To )
self:F({"Defender Birth", Defender:GetName()}) self:F({"Defender Birth", DefenderGroup:GetName()})
--self:GetParent(self).onafterBirth( self, Defender, From, Event, To ) --self:GetParent(self).onafterBirth( self, Defender, From, Event, To )
local DefenderName = Defender:GetCallsign() local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
local DefenderTarget = Dispatcher:GetDefenderTaskTarget( Defender ) local DefenderTarget = Dispatcher:GetDefenderTaskTarget( DefenderGroup )
self:F( { DefenderTarget = DefenderTarget } ) self:F( { DefenderTarget = DefenderTarget } )
if DefenderTarget then if DefenderTarget then
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " airborne. Engaging!" ) Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " airborne. Engaging!", "Wheels_up.wav", 3, "A2G/", DefenderGroup )
Fsm:EngageRoute( DefenderTarget.Set ) -- Engage on the TargetSetUnit AI_A2G_Fsm:EngageRoute( DefenderTarget.Set ) -- Engage on the TargetSetUnit
end end
end end
function Fsm:onafterEngageRoute( Defender, From, Event, To, AttackSetUnit ) function AI_A2G_Fsm:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit )
self:F({"Engage Route", Defender:GetName()}) self:F({"Engage Route", DefenderGroup:GetName()})
self:GetParent(self).onafterEngageRoute( self, Defender, From, Event, To, AttackSetUnit )
local DefenderName = Defender:GetCallsign() local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
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
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " on route to ground target at " .. Coordinate:ToStringA2G( Defender ) ) Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " on route to ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), "Moving_on_to_ground_target.wav", 3, "A2G/", DefenderGroup )
end end
self:GetParent(self).onafterEngageRoute( self, DefenderGroup, From, Event, To, AttackSetUnit )
end end
function Fsm:OnAfterEngage( Defender, From, Event, To, AttackSetUnit ) function AI_A2G_Fsm:OnAfterEngage( DefenderGroup, From, Event, To, AttackSetUnit )
self:F({"Engage Route", Defender:GetName()}) self:F({"Engage Route", DefenderGroup:GetName()})
--self:GetParent(self).onafterBirth( self, Defender, From, Event, To ) --self:GetParent(self).onafterBirth( self, Defender, From, Event, To )
local DefenderName = Defender:GetCallsign() local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
local FirstUnit = AttackSetUnit:GetFirst() local FirstUnit = AttackSetUnit:GetFirst()
if FirstUnit then if FirstUnit then
local Coordinate = FirstUnit:GetCoordinate() local Coordinate = FirstUnit:GetCoordinate()
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " engaging ground target at " .. Coordinate:ToStringA2G( Defender ) ) Dispatcher:MessageToPlayers( Squadron, "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " engaging ground target at " .. Coordinate:ToStringA2G( DefenderGroup ), "Engaging_ground_target.wav", 3, "A2G/", DefenderGroup )
end end
end end
function Fsm:onafterRTB( Defender, From, Event, To ) function AI_A2G_Fsm:onafterRTB( DefenderGroup, From, Event, To )
self:F({"Defender RTB", Defender:GetName()}) self:F({"Defender RTB", DefenderGroup:GetName()})
local DefenderName = Defender:GetCallsign() local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " returning." ) Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " returning.", "Returning_to_base.wav", 3, "A2G/", DefenderGroup )
self:GetParent(self).onafterRTB( self, Defender, From, Event, To ) self:GetParent(self).onafterRTB( self, DefenderGroup, From, Event, To )
Dispatcher:ClearDefenderTaskTarget( Defender ) Dispatcher:ClearDefenderTaskTarget( DefenderGroup )
end end
--- @param #AI_A2G_DISPATCHER self --- @param #AI_A2G_DISPATCHER self
function Fsm:onafterLostControl( Defender, From, Event, To ) function AI_A2G_Fsm:onafterLostControl( DefenderGroup, From, Event, To )
self:F({"Defender LostControl", Defender:GetName()}) self:F({"Defender LostControl", DefenderGroup:GetName()})
self:GetParent(self).onafterHome( self, Defender, From, Event, To ) self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
local DefenderName = Defender:GetCallsign() local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER local Dispatcher = AI_A2G_Fsm:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
--Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " lost control." ) --Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " lost control." )
if Defender:IsAboveRunway() then if DefenderGroup:IsAboveRunway() then
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
Defender:Destroy() DefenderGroup:Destroy()
end end
end end
--- @param #AI_A2G_DISPATCHER self --- @param #AI_A2G_DISPATCHER self
function Fsm:onafterHome( Defender, From, Event, To, Action ) function AI_A2G_Fsm:onafterHome( DefenderGroup, From, Event, To, Action )
self:F({"Defender Home", Defender:GetName()}) self:F({"Defender Home", DefenderGroup:GetName()})
self:GetParent(self).onafterHome( self, Defender, From, Event, To ) self:GetParent(self).onafterHome( self, DefenderGroup, From, Event, To )
local DefenderName = Defender:GetCallsign() local DefenderName = DefenderGroup:GetCallsign()
local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER local Dispatcher = self:GetDispatcher() -- #AI_A2G_DISPATCHER
local Squadron = Dispatcher:GetSquadronFromDefender( Defender ) local Squadron = Dispatcher:GetSquadronFromDefender( DefenderGroup )
Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " landing." ) Dispatcher:MessageToPlayers( "Squadron " .. Squadron.Name .. ", " .. DefenderName .. " landing.", "Landing_at_base.wav", 3, "A2G/", DefenderGroup )
if Action and Action == "Destroy" then if Action and Action == "Destroy" then
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
Defender:Destroy() DefenderGroup:Destroy()
end end
if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2G_DISPATCHER.Landing.NearAirbase then if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2G_DISPATCHER.Landing.NearAirbase then
Dispatcher:RemoveDefenderFromSquadron( Squadron, Defender ) Dispatcher:RemoveDefenderFromSquadron( Squadron, DefenderGroup )
Defender:Destroy() DefenderGroup:Destroy()
Dispatcher:ResourcePark( Squadron, Defender ) Dispatcher:ResourcePark( Squadron, DefenderGroup )
end end
end end
end end
@@ -4024,6 +4056,29 @@ do -- AI_A2G_DISPATCHER
end end
--- Determine the distance as the keys of reference of the detected items.
-- @param #AI_A2G_DISPATCHER self
function AI_A2G_DISPATCHER:Keys( DetectedItem )
self:F( { DetectedItem = DetectedItem } )
local AttackCoordinate = self.Detection:GetDetectedItemCoordinate( DetectedItem )
local ShortestDistance = 999999999
for DefenseCoordinateName, DefenseCoordinate in pairs( self.DefenseCoordinates ) do
local DefenseCoordinate = DefenseCoordinate -- Core.Point#COORDINATE
local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate )
if EvaluateDistance <= ShortestDistance then
ShortestDistance = EvaluateDistance
end
end
return ShortestDistance
end
--- Assigns A2G AI Tasks in relation to the detected items. --- Assigns A2G AI Tasks in relation to the detected items.
-- @param #AI_A2G_DISPATCHER self -- @param #AI_A2G_DISPATCHER self
function AI_A2G_DISPATCHER:Order( DetectedItem ) function AI_A2G_DISPATCHER:Order( DetectedItem )
@@ -4043,6 +4098,107 @@ do -- AI_A2G_DISPATCHER
return ShortestDistance return ShortestDistance
end end
--- Shows the tactical display.
-- @param #AI_A2G_DISPATCHER self
function AI_A2G_DISPATCHER:ShowTacticalDisplay( Detection )
local AreaMsg = {}
local TaskMsg = {}
local ChangeMsg = {}
local TaskReport = REPORT:New()
local DefenseTotal = 0
local Report = REPORT:New( "\nTactical Overview" )
local DefenderGroupCount = 0
local DefendersTotal = 0
-- Now that all obsolete tasks are removed, loop through the detected targets.
--for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do
for DetectedItemID, DetectedItem in UTILS.spairs( Detection:GetDetectedItems(), function( t, a, b ) return self:Order(t[a]) < self:Order(t[b]) end ) do
if not self.Detection:IsDetectedItemLocked( DetectedItem ) == true then
local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem
local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT
local DetectedCount = DetectedSet:Count()
local DetectedZone = DetectedItem.Zone
self:F( { "Target ID", DetectedItem.ItemID } )
self:F( { DefenseLimit = self.DefenseLimit, DefenseTotal = DefenseTotal } )
DetectedSet:Flush( self )
local DetectedID = DetectedItem.ID
local DetectionIndex = DetectedItem.Index
local DetectedItemChanged = DetectedItem.Changed
-- Show tactical situation
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 ) ) )
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
local Defender = Defender -- Wrapper.Group#GROUP
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
if Defender:IsAlive() then
DefenderGroupCount = DefenderGroupCount + 1
local Fuel = Defender:GetFuelMin() * 100
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
Defender:GetName(),
DefenderTask.Type,
DefenderTask.Fsm:GetState(),
Defender:GetSize(),
Fuel,
Damage,
Defender:HasTask() == true and "Executing" or "Idle" ) )
end
end
end
end
end
Report:Add( "\n - No Targets:")
local TaskCount = 0
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
TaskCount = TaskCount + 1
local Defender = Defender -- Wrapper.Group#GROUP
if not DefenderTask.Target then
if Defender:IsAlive() then
local DefenderHasTask = Defender:HasTask()
local Fuel = Defender:GetFuelMin() * 100
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
DefenderGroupCount = DefenderGroupCount + 1
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
Defender:GetName(),
DefenderTask.Type,
DefenderTask.Fsm:GetState(),
Defender:GetSize(),
Fuel,
Damage,
Defender:HasTask() == true and "Executing" or "Idle" ) )
end
end
end
Report:Add( string.format( "\n - %d Tasks - %d Defender Groups", TaskCount, DefenderGroupCount ) )
Report:Add( string.format( "\n - %d Queued Aircraft Launches", #self.DefenseQueue ) )
for DefenseQueueID, DefenseQueueItem in pairs( self.DefenseQueue ) do
local DefenseQueueItem = DefenseQueueItem -- #AI_A2G_DISPATCHER.DefenseQueueItem
Report:Add( string.format( " - %s - %s", DefenseQueueItem.SquadronName, DefenseQueueItem.DefenderSquadron.TakeoffTime, DefenseQueueItem.DefenderSquadron.TakeoffInterval) )
end
Report:Add( string.format( "\n - Squadron Resources: ", #self.DefenseQueue ) )
for DefenderSquadronName, DefenderSquadron in pairs( self.DefenderSquadrons ) do
Report:Add( string.format( " - %s - %d", DefenderSquadronName, DefenderSquadron.ResourceCount and DefenderSquadron.ResourceCount or "n/a" ) )
end
self:F( Report:Text( "\n" ) )
trigger.action.outText( Report:Text( "\n" ), 25 )
end
--- Assigns A2G AI Tasks in relation to the detected items. --- Assigns A2G AI Tasks in relation to the detected items.
-- @param #AI_A2G_DISPATCHER self -- @param #AI_A2G_DISPATCHER self
@@ -4102,7 +4258,7 @@ do -- AI_A2G_DISPATCHER
-- Now that all obsolete tasks are removed, loop through the detected targets. -- Now that all obsolete tasks are removed, loop through the detected targets.
--for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do --for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do
for DetectedItemID, DetectedItem in UTILS.spairs( Detection:GetDetectedItems(), function( t, a, b ) return self:Order(t[a]) < self:Order(t[b]) end ) do for DetectedDistance, DetectedItem in UTILS.kpairs( Detection:GetDetectedItems(), function( t ) return self:Keys( t ) end, function( t, a, b ) return self:Order(t[a]) < self:Order(t[b]) end ) do
if not self.Detection:IsDetectedItemLocked( DetectedItem ) == true then if not self.Detection:IsDetectedItemLocked( DetectedItem ) == true then
local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem
@@ -4124,44 +4280,43 @@ do -- AI_A2G_DISPATCHER
-- Calculate if for this DetectedItem if a defense needs to be initiated. -- Calculate if for this DetectedItem if a defense needs to be initiated.
-- This calculation is based on the distance between the defense point and the attackers, and the defensiveness parameter. -- This calculation is based on the distance between the defense point and the attackers, and the defensiveness parameter.
-- The attackers closest to the defense coordinates will be handled first, or course! -- The attackers closest to the defense coordinates will be handled first, or course!
local EngageCoordinate = nil local EngageDefenses = nil
for DefenseCoordinateName, DefenseCoordinate in pairs( self.DefenseCoordinates ) do
local DefenseCoordinate = DefenseCoordinate -- Core.Point#COORDINATE
local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate )
if EvaluateDistance <= self.DefenseRadius then self:F( { DetectedDistance = DetectedDistance, DefenseRadius = self.DefenseRadius } )
if DetectedDistance <= self.DefenseRadius then
local DistanceProbability = ( self.DefenseRadius / EvaluateDistance * self.DefenseReactivity )
self:F( { DetectedApproach = self._DefenseApproach } )
if self._DefenseApproach == AI_A2G_DISPATCHER.DefenseApproach.Distance then
EngageDefenses = true
self:F( { EngageDefenses = EngageDefenses } )
end
if self._DefenseApproach == AI_A2G_DISPATCHER.DefenseApproach.Random then
local DistanceProbability = ( self.DefenseRadius / DetectedDistance * self.DefenseReactivity )
local DefenseProbability = math.random() local DefenseProbability = math.random()
self:F( { DistanceProbability = DistanceProbability, DefenseProbability = DefenseProbability } ) self:F( { DistanceProbability = DistanceProbability, DefenseProbability = DefenseProbability } )
if self._DefenseApproach == AI_A2G_DISPATCHER.DefenseApproach.Random then if DefenseProbability <= DistanceProbability / ( 300 / 30 ) then
EngageDefenses = true
if DefenseProbability <= DistanceProbability / ( 300 / 30 ) then
EngageCoordinate = DefenseCoordinate
break
end
end
if self._DefenseApproach == AI_A2G_DISPATCHER.DefenseApproach.Distance then
EngageCoordinate = DefenseCoordinate
break
end end
end end
end end
self:F( { EngageDefenses = EngageDefenses, DefenseLimit = self.DefenseLimit, DefenseTotal = DefenseTotal } )
-- There needs to be an EngageCoordinate. -- There needs to be an EngageCoordinate.
-- If self.DefenseLimit is set (thus limit the amount of defenses to one zone), then only start a new defense if the maximum has not been reached. -- If self.DefenseLimit is set (thus limit the amount of defenses to one zone), then only start a new defense if the maximum has not been reached.
-- If self.DefenseLimit has not been set, there is an unlimited amount of zones to be defended. -- If self.DefenseLimit has not been set, there is an unlimited amount of zones to be defended.
if ( EngageCoordinate and ( self.DefenseLimit and DefenseTotal < self.DefenseLimit ) or not self.DefenseLimit ) then if ( EngageDefenses and ( self.DefenseLimit and DefenseTotal < self.DefenseLimit ) or not self.DefenseLimit ) then
do do
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_SEAD( DetectedItem ) -- Returns a SET_UNIT with the SEAD targets to be engaged... local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_SEAD( DetectedItem ) -- Returns a SET_UNIT with the SEAD targets to be engaged...
if DefendersMissing > 0 then if DefendersMissing > 0 then
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "SEAD", EngageCoordinate ) self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "SEAD" )
end end
end end
@@ -4169,7 +4324,7 @@ do -- AI_A2G_DISPATCHER
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_CAS( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged... local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_CAS( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
if DefendersMissing > 0 then if DefendersMissing > 0 then
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "CAS", EngageCoordinate ) self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "CAS" )
end end
end end
@@ -4177,7 +4332,7 @@ do -- AI_A2G_DISPATCHER
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_BAI( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged... local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_BAI( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
if DefendersMissing > 0 then if DefendersMissing > 0 then
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } ) self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "BAI", EngageCoordinate ) self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "BAI" )
end end
end end
end end
@@ -4191,7 +4346,7 @@ do -- AI_A2G_DISPATCHER
for DefenseQueueID, DefenseQueueItem in pairs( self.DefenseQueue ) do for DefenseQueueID, DefenseQueueItem in pairs( self.DefenseQueue ) do
local DefenseQueueItem = DefenseQueueItem -- #AI_A2G_DISPATCHER.DefenseQueueItem local DefenseQueueItem = DefenseQueueItem -- #AI_A2G_DISPATCHER.DefenseQueueItem
if DefenseQueueItem.AttackerDetection.Index == DetectedItem.Index then if DefenseQueueItem.AttackerDetection and DefenseQueueItem.AttackerDetection.Index and DefenseQueueItem.AttackerDetection.Index == DetectedItem.Index then
DefenseTotal = DefenseTotal + 1 DefenseTotal = DefenseTotal + 1
end end
end end
+7 -13
View File
@@ -304,6 +304,8 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor
-- @param #AI_A2G_ENGAGE self -- @param #AI_A2G_ENGAGE self
-- @param #number Delay The delay in seconds. -- @param #number Delay The delay in seconds.
self:AddTransition( { "Patrolling", "Engaging" }, "Refuel", "Refuelling" )
return self return self
end end
@@ -389,17 +391,6 @@ function AI_A2G_ENGAGE:onafterAbort( AIGroup, From, Event, To )
end end
--- @param #AI_A2G_ENGAGE self
-- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup managed by the FSM.
-- @param #string From The From State string.
-- @param #string Event The Event string.
-- @param #string To The To State string.
function AI_A2G_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit )
self:F( { DefenderGroup, From, Event, To, AttackSetUnit} )
end
--- @param #AI_A2G_ENGAGE self --- @param #AI_A2G_ENGAGE self
-- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM. -- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM.
-- @param #string From The From State string. -- @param #string From The From State string.
@@ -446,6 +437,8 @@ function AI_A2G_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
local DefenderGroupName = DefenderGroup:GetName() local DefenderGroupName = DefenderGroup:GetName()
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
local AttackCount = AttackSetUnit:Count() local AttackCount = AttackSetUnit:Count()
if AttackCount > 0 then if AttackCount > 0 then
@@ -513,8 +506,9 @@ function AI_A2G_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
end end
else else
self:E( DefenderGroupName .. ": No targets found -> Going RTB") self:I( DefenderGroupName .. ": No targets found -> Going RTB")
self:Return() self:Return()
self:__RTB( self.TaskDelay ) self:__RTB( self.TaskDelay )
end end
end end
+13 -5
View File
@@ -286,9 +286,18 @@ function AI_A2G_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
local FromWP = CurrentCoord:WaypointAir(
self.PatrolAltType or "RADIO",
POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint,
ToTargetSpeed,
true
)
PatrolRoute[#PatrolRoute+1] = FromWP
--- Create a route point of type air. --- Create a route point of type air.
local ToPatrolRoutePoint = ToTargetCoord:WaypointAir( local ToWP = ToTargetCoord:WaypointAir(
self.PatrolAltType, self.PatrolAltType,
POINT_VEC3.RoutePointType.TurningPoint, POINT_VEC3.RoutePointType.TurningPoint,
POINT_VEC3.RoutePointAction.TurningPoint, POINT_VEC3.RoutePointAction.TurningPoint,
@@ -296,8 +305,7 @@ function AI_A2G_PATROL:onafterPatrolRoute( AIPatrol, From, Event, To )
true true
) )
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint PatrolRoute[#PatrolRoute+1] = ToWP
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
local Tasks = {} local Tasks = {}
Tasks[#Tasks+1] = AIPatrol:TaskFunction( "AI_A2G_PATROL.___PatrolRoute", self ) Tasks[#Tasks+1] = AIPatrol:TaskFunction( "AI_A2G_PATROL.___PatrolRoute", self )
@@ -316,8 +324,8 @@ function AI_A2G_PATROL.Resume( AIPatrol, Fsm )
AIPatrol:F( { "AI_A2G_PATROL.Resume:", AIPatrol:GetName() } ) AIPatrol:F( { "AI_A2G_PATROL.Resume:", AIPatrol:GetName() } )
if AIPatrol:IsAlive() then if AIPatrol:IsAlive() then
Fsm:__Reset( self.TaskDelay ) Fsm:__Reset( Fsm.TaskDelay )
Fsm:__PatrolRoute( self.TaskDelay ) Fsm:__PatrolRoute( Fsm.TaskDelay )
end end
end end
+14 -2
View File
@@ -117,6 +117,8 @@ function AI_A2G_SEAD:onafterEngage( DefenderGroup, From, Event, To, AttackSetUni
local DefenderGroupName = DefenderGroup:GetName() local DefenderGroupName = DefenderGroup:GetName()
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
local AttackCount = AttackSetUnit:Count() local AttackCount = AttackSetUnit:Count()
if AttackCount > 0 then if AttackCount > 0 then
@@ -181,7 +183,7 @@ function AI_A2G_SEAD:onafterEngage( DefenderGroup, From, Event, To, AttackSetUni
end end
if #AttackUnitTasks == 0 then if #AttackUnitTasks == 0 then
self:E( DefenderGroupName .. ": No targets found -> Going RTB") self:I( DefenderGroupName .. ": No targets found -> Going RTB")
self:Return() self:Return()
self:__RTB( self.TaskDelay ) self:__RTB( self.TaskDelay )
else else
@@ -200,9 +202,19 @@ function AI_A2G_SEAD:onafterEngage( DefenderGroup, From, Event, To, AttackSetUni
DefenderGroup:Route( EngageRoute, self.TaskDelay ) DefenderGroup:Route( EngageRoute, self.TaskDelay )
end end
else else
self:E( DefenderGroupName .. ": No targets found -> Going RTB") self:I( DefenderGroupName .. ": No targets found -> Going RTB")
self:Return() self:Return()
self:__RTB( self.TaskDelay ) self:__RTB( self.TaskDelay )
end end
end end
--- @param Wrapper.Group#GROUP AIEngage
function AI_A2G_SEAD.Resume( AIEngage, Fsm )
AIEngage:F( { "AI_A2G_SEAD.Resume:", AIEngage:GetName() } )
if AIEngage:IsAlive() then
Fsm:__Reset( Fsm.TaskDelay )
Fsm:__EngageRoute( Fsm.TaskDelay, Fsm.AttackSetUnit )
end
end
+13 -11
View File
@@ -446,7 +446,7 @@ function AI_AIR:onafterStatus()
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() ) local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
if DistanceFromHomeBase > self.DisengageRadius then if DistanceFromHomeBase > self.DisengageRadius then
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" ) self:I( self.Controllable:GetName() .. " is too far from home base, RTB!" )
self:Hold( 300 ) self:Hold( 300 )
RTB = false RTB = false
end end
@@ -461,7 +461,7 @@ function AI_AIR:onafterStatus()
-- end -- end
if not self:Is( "Fuel" ) and not self:Is( "Home" ) then if not self:Is( "Fuel" ) and not self:Is( "Home" ) and not self:is( "Refuelling" )then
local Fuel = self.Controllable:GetFuelMin() local Fuel = self.Controllable:GetFuelMin()
@@ -470,10 +470,10 @@ function AI_AIR:onafterStatus()
if Fuel < self.FuelThresholdPercentage then if Fuel < self.FuelThresholdPercentage then
if self.TankerName then if self.TankerName then
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" ) self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
self:Refuel() self:Refuel()
else else
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" ) self:I( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
local OldAIControllable = self.Controllable local OldAIControllable = self.Controllable
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed ) local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
@@ -495,7 +495,7 @@ function AI_AIR:onafterStatus()
-- Note that a group can consist of more units, so if one unit is damaged of a group, the mission may continue. -- Note that a group can consist of more units, so if one unit is damaged of a group, the mission may continue.
-- The damaged unit will RTB due to DCS logic, and the others will continue to engage. -- The damaged unit will RTB due to DCS logic, and the others will continue to engage.
if ( Damage / InitialLife ) < self.PatrolDamageThreshold then if ( Damage / InitialLife ) < self.PatrolDamageThreshold then
self:E( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" ) self:I( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" )
self:Damaged() self:Damaged()
RTB = true RTB = true
self:SetStatusOff() self:SetStatusOff()
@@ -513,7 +513,7 @@ function AI_AIR:onafterStatus()
if Damage ~= InitialLife then if Damage ~= InitialLife then
self:Damaged() self:Damaged()
else else
self:E( self.Controllable:GetName() .. " control lost! " ) self:I( self.Controllable:GetName() .. " control lost! " )
self:LostControl() self:LostControl()
end end
@@ -570,7 +570,7 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
if AIGroup and AIGroup:IsAlive() then if AIGroup and AIGroup:IsAlive() then
self:E( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" ) self:I( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
self:ClearTargetDistance() self:ClearTargetDistance()
--AIGroup:ClearTasks() --AIGroup:ClearTasks()
@@ -588,7 +588,7 @@ function AI_AIR:onafterRTB( AIGroup, From, Event, To )
local ToAirbaseCoord = FromCoord:Translate( 5000, ToAirbaseAngle ) local ToAirbaseCoord = FromCoord:Translate( 5000, ToAirbaseAngle )
if Distance < 5000 then if Distance < 5000 then
self:E( "RTB and near the airbase!" ) self:I( "RTB and near the airbase!" )
self:Home() self:Home()
return return
end end
@@ -634,7 +634,7 @@ end
function AI_AIR:onafterHome( AIGroup, From, Event, To ) function AI_AIR:onafterHome( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } ) self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" ) self:I( "Group " .. self.Controllable:GetName() .. " ... Home! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then if AIGroup and AIGroup:IsAlive() then
end end
@@ -648,7 +648,7 @@ end
function AI_AIR:onafterHold( AIGroup, From, Event, To, HoldTime ) function AI_AIR:onafterHold( AIGroup, From, Event, To, HoldTime )
self:F( { AIGroup, From, Event, To } ) self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" ) self:I( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then if AIGroup and AIGroup:IsAlive() then
local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed ) local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
@@ -680,12 +680,14 @@ end
function AI_AIR:onafterRefuel( AIGroup, From, Event, To ) function AI_AIR:onafterRefuel( AIGroup, From, Event, To )
self:F( { AIGroup, From, Event, To } ) self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Refuelling! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then if AIGroup and AIGroup:IsAlive() then
local Tanker = GROUP:FindByName( self.TankerName ) local Tanker = GROUP:FindByName( self.TankerName )
if Tanker:IsAlive() and Tanker:IsAirPlane() then if Tanker:IsAlive() and Tanker:IsAirPlane() then
self:I( "Group " .. self.Controllable:GetName() .. " ... Refuelling! ( " .. self:GetState() .. "), at tanker " .. self.TankerName )
local RefuelRoute = {} local RefuelRoute = {}
--- Calculate the target route point. --- Calculate the target route point.
@@ -3289,6 +3289,9 @@ do
self:Patrol( SquadronName, PatrolTaskType ) self:Patrol( SquadronName, PatrolTaskType )
end end
end end
+1 -1
View File
@@ -545,7 +545,7 @@ function AI_ESCORT:SetFlightMenuFormation( Formation )
if MenuFormation then if MenuFormation then
local Arguments = MenuFormation.Arguments local Arguments = MenuFormation.Arguments
self:I({Arguments=unpack(Arguments)}) --self:I({Arguments=unpack(Arguments)})
local FlightMenuFormation = MENU_GROUP:New( self.PlayerGroup, "Formation", self.MainMenu ) local FlightMenuFormation = MENU_GROUP:New( self.PlayerGroup, "Formation", self.MainMenu )
local MenuFlightFormationID = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, FlightMenuFormation, local MenuFlightFormationID = MENU_GROUP_COMMAND:New( self.PlayerGroup, Formation, FlightMenuFormation,
function ( self, Formation, ... ) function ( self, Formation, ... )
@@ -3,6 +3,7 @@
-- ## Features: -- ## Features:
-- -- -- --
-- * Provides the facilities to trigger escorts when players join flight slots. -- * Provides the facilities to trigger escorts when players join flight slots.
-- *
-- --
-- === -- ===
-- --
@@ -83,13 +83,6 @@ function AI_ESCORT_DISPATCHER_REQUEST:OnEventExit( EventData )
local PlayerGroup = EventData.IniGroup local PlayerGroup = EventData.IniGroup
local PlayerUnit = EventData.IniUnit local PlayerUnit = EventData.IniUnit
self.CarrierSet:Flush(self)
self:I({EscortAirbase= self.EscortAirbase } )
self:I({PlayerGroupName = PlayerGroupName } )
self:I({PlayerGroup = PlayerGroup})
self:I({FirstGroup = self.CarrierSet:GetFirst()})
self:I({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
if self.CarrierSet:FindGroup( PlayerGroupName ) then if self.CarrierSet:FindGroup( PlayerGroupName ) then
if self.AI_Escorts[PlayerGroupName] then if self.AI_Escorts[PlayerGroupName] then
self.AI_Escorts[PlayerGroupName]:Stop() self.AI_Escorts[PlayerGroupName]:Stop()
@@ -107,11 +100,6 @@ function AI_ESCORT_DISPATCHER_REQUEST:OnEventBirth( EventData )
local PlayerGroup = EventData.IniGroup local PlayerGroup = EventData.IniGroup
local PlayerUnit = EventData.IniUnit local PlayerUnit = EventData.IniUnit
self:I({PlayerGroupName = PlayerGroupName } )
self:I({PlayerGroup = PlayerGroup})
self:I({FirstGroup = self.CarrierSet:GetFirst()})
self:I({FindGroup = self.CarrierSet:FindGroup( PlayerGroupName )})
if self.CarrierSet:FindGroup( PlayerGroupName ) then if self.CarrierSet:FindGroup( PlayerGroupName ) then
if not self.AI_Escorts[PlayerGroupName] then if not self.AI_Escorts[PlayerGroupName] then
local LeaderUnit = PlayerUnit local LeaderUnit = PlayerUnit
+2 -3
View File
@@ -825,7 +825,7 @@ function AI_PATROL_ZONE:onafterStatus()
local Fuel = self.Controllable:GetFuelMin() local Fuel = self.Controllable:GetFuelMin()
if Fuel < self.PatrolFuelThresholdPercentage then if Fuel < self.PatrolFuelThresholdPercentage then
self:E( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" ) self:I( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" )
local OldAIControllable = self.Controllable local OldAIControllable = self.Controllable
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed ) local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
@@ -839,7 +839,7 @@ function AI_PATROL_ZONE:onafterStatus()
-- TODO: Check GROUP damage function. -- TODO: Check GROUP damage function.
local Damage = self.Controllable:GetLife() local Damage = self.Controllable:GetLife()
if Damage <= self.PatrolDamageThreshold then if Damage <= self.PatrolDamageThreshold then
self:E( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" ) self:I( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" )
RTB = true RTB = true
end end
@@ -900,7 +900,6 @@ end
function AI_PATROL_ZONE:OnCrash( EventData ) function AI_PATROL_ZONE:OnCrash( EventData )
if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then if self.Controllable:IsAlive() and EventData.IniDCSGroupName == self.Controllable:GetName() then
self:E( self.Controllable:GetUnits() )
if #self.Controllable:GetUnits() == 1 then if #self.Controllable:GetUnits() == 1 then
self:__Crash( 1, EventData ) self:__Crash( 1, EventData )
end end
+38 -16
View File
@@ -805,15 +805,17 @@ do -- Scheduling
end end
self.Scheduler.SchedulerObject = self.Scheduler self.Scheduler.SchedulerObject = self.Scheduler
--self.MasterObject = self
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule( local ScheduleID = self.Scheduler:Schedule(
self, self,
SchedulerFunction, SchedulerFunction,
{ ... }, { ... },
Start, Start,
Repeat, Repeat,
RandomizeFactor, RandomizeFactor,
Stop Stop,
4
) )
self._.Schedules[#self._.Schedules+1] = ScheduleID self._.Schedules[#self._.Schedules+1] = ScheduleID
@@ -889,6 +891,26 @@ end
-- Log a trace (only shown when trace is on) -- Log a trace (only shown when trace is on)
-- TODO: Make trace function using variable parameters. -- TODO: Make trace function using variable parameters.
--- Set trace on.
-- @param #BASE self
-- @usage
-- -- Switch the tracing On
-- BASE:TraceOn()
function BASE:TraceOn()
self:TraceOnOff( true )
end
--- Set trace off.
-- @param #BASE self
-- @usage
-- -- Switch the tracing Off
-- BASE:TraceOff()
function BASE:TraceOff()
self:TraceOnOff( false )
end
--- Set trace on or off --- Set trace on or off
-- Note that when trace is off, no BASE.Debug statement is performed, increasing performance! -- Note that when trace is off, no BASE.Debug statement is performed, increasing performance!
-- When Moose is loaded statically, (as one file), tracing is switched off by default. -- When Moose is loaded statically, (as one file), tracing is switched off by default.
@@ -903,7 +925,7 @@ end
-- -- Switch the tracing Off -- -- Switch the tracing Off
-- BASE:TraceOnOff( false ) -- BASE:TraceOnOff( false )
function BASE:TraceOnOff( TraceOnOff ) function BASE:TraceOnOff( TraceOnOff )
_TraceOnOff = TraceOnOff _TraceOnOff = TraceOnOff or true
end end
@@ -923,8 +945,8 @@ end
-- @param #BASE self -- @param #BASE self
-- @param #number Level -- @param #number Level
function BASE:TraceLevel( Level ) function BASE:TraceLevel( Level )
_TraceLevel = Level _TraceLevel = Level or 1
self:E( "Tracing level " .. Level ) self:I( "Tracing level " .. _TraceLevel )
end end
--- Trace all methods in MOOSE --- Trace all methods in MOOSE
@@ -932,12 +954,12 @@ end
-- @param #boolean TraceAll true = trace all methods in MOOSE. -- @param #boolean TraceAll true = trace all methods in MOOSE.
function BASE:TraceAll( TraceAll ) function BASE:TraceAll( TraceAll )
_TraceAll = TraceAll _TraceAll = TraceAll or true
if _TraceAll then if _TraceAll then
self:E( "Tracing all methods in MOOSE " ) self:I( "Tracing all methods in MOOSE " )
else else
self:E( "Switched off tracing all methods in MOOSE" ) self:I( "Switched off tracing all methods in MOOSE" )
end end
end end
@@ -947,7 +969,7 @@ end
function BASE:TraceClass( Class ) function BASE:TraceClass( Class )
_TraceClass[Class] = true _TraceClass[Class] = true
_TraceClassMethod[Class] = {} _TraceClassMethod[Class] = {}
self:E( "Tracing class " .. Class ) self:I( "Tracing class " .. Class )
end end
--- Set tracing for a specific method of class --- Set tracing for a specific method of class
@@ -960,7 +982,7 @@ function BASE:TraceClassMethod( Class, Method )
_TraceClassMethod[Class].Method = {} _TraceClassMethod[Class].Method = {}
end end
_TraceClassMethod[Class].Method[Method] = true _TraceClassMethod[Class].Method[Method] = true
self:E( "Tracing method " .. Method .. " of class " .. Class ) self:I( "Tracing method " .. Method .. " of class " .. Class )
end end
--- Trace a function call. This function is private. --- Trace a function call. This function is private.
@@ -987,7 +1009,7 @@ function BASE:_F( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
if DebugInfoFrom then if DebugInfoFrom then
LineFrom = DebugInfoFrom.currentline LineFrom = DebugInfoFrom.currentline
end end
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "F", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
end end
end end
end end
@@ -1062,7 +1084,7 @@ function BASE:_T( Arguments, DebugInfoCurrentParam, DebugInfoFromParam )
if DebugInfoFrom then if DebugInfoFrom then
LineFrom = DebugInfoFrom.currentline LineFrom = DebugInfoFrom.currentline
end end
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s" , LineCurrent, LineFrom, "T", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
end end
end end
end end
@@ -1133,9 +1155,9 @@ function BASE:E( Arguments )
LineFrom = DebugInfoFrom.currentline LineFrom = DebugInfoFrom.currentline
end end
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "E", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
else else
env.info( string.format( "%1s:%20s%05d(%s)" , "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%1s:%30s%05d(%s)" , "E", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
end end
end end
@@ -1161,9 +1183,9 @@ function BASE:I( Arguments )
LineFrom = DebugInfoFrom.currentline LineFrom = DebugInfoFrom.currentline
end end
env.info( string.format( "%6d(%6d)/%1s:%20s%05d.%s(%s)" , LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%6d(%6d)/%1s:%30s%05d.%s(%s)" , LineCurrent, LineFrom, "I", self.ClassName, self.ClassID, Function, routines.utils.oneLineSerialize( Arguments ) ) )
else else
env.info( string.format( "%1s:%20s%05d(%s)" , "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) ) env.info( string.format( "%1s:%30s%05d(%s)" , "I", self.ClassName, self.ClassID, routines.utils.oneLineSerialize( Arguments ) ) )
end end
end end
+167 -136
View File
@@ -1,9 +1,9 @@
--- **Core** - Manages several databases containing templates, mission objects, and mission information. --- **Core** - Manages several databases containing templates, mission objects, and mission information.
-- --
-- === -- ===
-- --
-- ## Features: -- ## Features:
-- --
-- * During mission startup, scan the mission environment, and create / instantiate intelligently the different objects as defined within the mission. -- * During mission startup, scan the mission environment, and create / instantiate intelligently the different objects as defined within the mission.
-- * Manage database of DCS Group templates (as modelled using the mission editor). -- * Manage database of DCS Group templates (as modelled using the mission editor).
-- - Group templates. -- - Group templates.
@@ -20,14 +20,14 @@
-- * Manage database of hits to units and statics. -- * Manage database of hits to units and statics.
-- * Manage database of destroys of units and statics. -- * Manage database of destroys of units and statics.
-- * Manage database of @{Core.Zone#ZONE_BASE} objects. -- * Manage database of @{Core.Zone#ZONE_BASE} objects.
-- --
-- === -- ===
-- --
-- ### Author: **FlightControl** -- ### Author: **FlightControl**
-- ### Contributions: -- ### Contributions:
-- --
-- === -- ===
-- --
-- @module Core.Database -- @module Core.Database
-- @image Core_Database.JPG -- @image Core_Database.JPG
@@ -36,9 +36,9 @@
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
--- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator. --- Contains collections of wrapper objects defined within MOOSE that reflect objects within the simulator.
-- --
-- Mission designers can use the DATABASE class to refer to: -- Mission designers can use the DATABASE class to refer to:
-- --
-- * STATICS -- * STATICS
-- * UNITS -- * UNITS
-- * GROUPS -- * GROUPS
@@ -47,12 +47,12 @@
-- * PLAYERSJOINED -- * PLAYERSJOINED
-- * PLAYERS -- * PLAYERS
-- * CARGOS -- * CARGOS
-- --
-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor. -- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
-- --
-- The singleton object **_DATABASE** is automatically created by MOOSE, that administers all objects within the mission. -- The singleton object **_DATABASE** is automatically created by MOOSE, that administers all objects within the mission.
-- Moose refers to **_DATABASE** within the framework extensively, but you can also refer to the _DATABASE object within your missions if required. -- Moose refers to **_DATABASE** within the framework extensively, but you can also refer to the _DATABASE object within your missions if required.
-- --
-- @field #DATABASE -- @field #DATABASE
DATABASE = { DATABASE = {
ClassName = "DATABASE", ClassName = "DATABASE",
@@ -81,6 +81,7 @@ DATABASE = {
HITS = {}, HITS = {},
DESTROYS = {}, DESTROYS = {},
ZONES = {}, ZONES = {},
ZONES_GOAL = {},
WAREHOUSES = {}, WAREHOUSES = {},
FLIGHTGROUPS = {}, FLIGHTGROUPS = {},
FLIGHTCONTROLS = {}, FLIGHTCONTROLS = {},
@@ -115,7 +116,7 @@ function DATABASE:New()
local self = BASE:Inherit( self, BASE:New() ) -- #DATABASE local self = BASE:Inherit( self, BASE:New() ) -- #DATABASE
self:SetEventPriority( 1 ) self:SetEventPriority( 1 )
self:HandleEvent( EVENTS.Birth, self._EventOnBirth ) self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash ) self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
@@ -125,11 +126,11 @@ function DATABASE:New()
self:HandleEvent( EVENTS.DeleteCargo ) self:HandleEvent( EVENTS.DeleteCargo )
self:HandleEvent( EVENTS.NewZone ) self:HandleEvent( EVENTS.NewZone )
self:HandleEvent( EVENTS.DeleteZone ) self:HandleEvent( EVENTS.DeleteZone )
-- Follow alive players and clients -- Follow alive players and clients
--self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) -- This is not working anymore!, handling this through the birth event. --self:HandleEvent( EVENTS.PlayerEnterUnit, self._EventOnPlayerEnterUnit ) -- This is not working anymore!, handling this through the birth event.
self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit ) self:HandleEvent( EVENTS.PlayerLeaveUnit, self._EventOnPlayerLeaveUnit )
self:_RegisterTemplates() self:_RegisterTemplates()
self:_RegisterGroupsAndUnits() self:_RegisterGroupsAndUnits()
self:_RegisterClients() self:_RegisterClients()
@@ -138,16 +139,16 @@ function DATABASE:New()
self:_RegisterAirbases() self:_RegisterAirbases()
self.UNITS_Position = 0 self.UNITS_Position = 0
--- @param #DATABASE self --- @param #DATABASE self
local function CheckPlayers( self ) local function CheckPlayers( self )
local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ), AlivePlayersNeutral = coalition.getPlayers( coalition.side.NEUTRAL )} local CoalitionsData = { AlivePlayersRed = coalition.getPlayers( coalition.side.RED ), AlivePlayersBlue = coalition.getPlayers( coalition.side.BLUE ), AlivePlayersNeutral = coalition.getPlayers( coalition.side.NEUTRAL )}
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
--self:E( { "CoalitionData:", CoalitionData } ) --self:E( { "CoalitionData:", CoalitionData } )
for UnitId, UnitData in pairs( CoalitionData ) do for UnitId, UnitData in pairs( CoalitionData ) do
if UnitData and UnitData:isExist() then if UnitData and UnitData:isExist() then
local UnitName = UnitData:getName() local UnitName = UnitData:getName()
local PlayerName = UnitData:getPlayerName() local PlayerName = UnitData:getPlayerName()
local PlayerUnit = UNIT:Find( UnitData ) local PlayerUnit = UNIT:Find( UnitData )
@@ -166,10 +167,10 @@ function DATABASE:New()
end end
end end
end end
--self:E( "Scheduling" ) --self:E( "Scheduling" )
--PlayerCheckSchedule = SCHEDULER:New( nil, CheckPlayers, { self }, 1, 1 ) --PlayerCheckSchedule = SCHEDULER:New( nil, CheckPlayers, { self }, 1, 1 )
return self return self
end end
@@ -189,12 +190,13 @@ end
function DATABASE:AddUnit( DCSUnitName ) function DATABASE:AddUnit( DCSUnitName )
if not self.UNITS[DCSUnitName] then if not self.UNITS[DCSUnitName] then
self:I( { "Add UNIT:", DCSUnitName } )
local UnitRegister = UNIT:Register( DCSUnitName ) local UnitRegister = UNIT:Register( DCSUnitName )
self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName ) self.UNITS[DCSUnitName] = UNIT:Register( DCSUnitName )
table.insert( self.UNITS_Index, DCSUnitName ) table.insert( self.UNITS_Index, DCSUnitName )
end end
return self.UNITS[DCSUnitName] return self.UNITS[DCSUnitName]
end end
@@ -203,7 +205,7 @@ end
-- @param #DATABASE self -- @param #DATABASE self
function DATABASE:DeleteUnit( DCSUnitName ) function DATABASE:DeleteUnit( DCSUnitName )
self.UNITS[DCSUnitName] = nil self.UNITS[DCSUnitName] = nil
end end
--- Adds a Static based on the Static Name in the DATABASE. --- Adds a Static based on the Static Name in the DATABASE.
@@ -214,7 +216,7 @@ function DATABASE:AddStatic( DCSStaticName )
self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName ) self.STATICS[DCSStaticName] = STATIC:Register( DCSStaticName )
return self.STATICS[DCSStaticName] return self.STATICS[DCSStaticName]
end end
return nil return nil
end end
@@ -223,7 +225,7 @@ end
-- @param #DATABASE self -- @param #DATABASE self
function DATABASE:DeleteStatic( DCSStaticName ) function DATABASE:DeleteStatic( DCSStaticName )
--self.STATICS[DCSStaticName] = nil --self.STATICS[DCSStaticName] = nil
end end
--- Finds a STATIC based on the StaticName. --- Finds a STATIC based on the StaticName.
@@ -262,7 +264,7 @@ end
-- @param #string AirbaseName The name of the airbase -- @param #string AirbaseName The name of the airbase
function DATABASE:DeleteAirbase( AirbaseName ) function DATABASE:DeleteAirbase( AirbaseName )
self.AIRBASES[AirbaseName] = nil self.AIRBASES[AirbaseName] = nil
end end
--- Finds an AIRBASE based on the AirbaseName. --- Finds an AIRBASE based on the AirbaseName.
@@ -283,29 +285,29 @@ do -- Zones
-- @param #string ZoneName The name of the zone. -- @param #string ZoneName The name of the zone.
-- @return Core.Zone#ZONE_BASE The found ZONE. -- @return Core.Zone#ZONE_BASE The found ZONE.
function DATABASE:FindZone( ZoneName ) function DATABASE:FindZone( ZoneName )
local ZoneFound = self.ZONES[ZoneName] local ZoneFound = self.ZONES[ZoneName]
return ZoneFound return ZoneFound
end end
--- Adds a @{Zone} based on the zone name in the DATABASE. --- Adds a @{Zone} based on the zone name in the DATABASE.
-- @param #DATABASE self -- @param #DATABASE self
-- @param #string ZoneName The name of the zone. -- @param #string ZoneName The name of the zone.
-- @param Core.Zone#ZONE_BASE Zone The zone. -- @param Core.Zone#ZONE_BASE Zone The zone.
function DATABASE:AddZone( ZoneName, Zone ) function DATABASE:AddZone( ZoneName, Zone )
if not self.ZONES[ZoneName] then if not self.ZONES[ZoneName] then
self.ZONES[ZoneName] = Zone self.ZONES[ZoneName] = Zone
end end
end end
--- Deletes a @{Zone} from the DATABASE based on the zone name. --- Deletes a @{Zone} from the DATABASE based on the zone name.
-- @param #DATABASE self -- @param #DATABASE self
-- @param #string ZoneName The name of the zone. -- @param #string ZoneName The name of the zone.
function DATABASE:DeleteZone( ZoneName ) function DATABASE:DeleteZone( ZoneName )
self.ZONES[ZoneName] = nil self.ZONES[ZoneName] = nil
end end
@@ -322,56 +324,89 @@ do -- Zones
self.ZONENAMES[ZoneName] = ZoneName self.ZONENAMES[ZoneName] = ZoneName
self:AddZone( ZoneName, Zone ) self:AddZone( ZoneName, Zone )
end end
for ZoneGroupName, ZoneGroup in pairs( self.GROUPS ) do for ZoneGroupName, ZoneGroup in pairs( self.GROUPS ) do
if ZoneGroupName:match("#ZONE_POLYGON") then if ZoneGroupName:match("#ZONE_POLYGON") then
local ZoneName1 = ZoneGroupName:match("(.*)#ZONE_POLYGON") local ZoneName1 = ZoneGroupName:match("(.*)#ZONE_POLYGON")
local ZoneName2 = ZoneGroupName:match(".*#ZONE_POLYGON(.*)") local ZoneName2 = ZoneGroupName:match(".*#ZONE_POLYGON(.*)")
local ZoneName = ZoneName1 .. ( ZoneName2 or "" ) local ZoneName = ZoneName1 .. ( ZoneName2 or "" )
self:I( { "Register ZONE_POLYGON:", Name = ZoneName } ) self:I( { "Register ZONE_POLYGON:", Name = ZoneName } )
local Zone_Polygon = ZONE_POLYGON:New( ZoneName, ZoneGroup ) local Zone_Polygon = ZONE_POLYGON:New( ZoneName, ZoneGroup )
self.ZONENAMES[ZoneName] = ZoneName self.ZONENAMES[ZoneName] = ZoneName
self:AddZone( ZoneName, Zone_Polygon ) self:AddZone( ZoneName, Zone_Polygon )
end end
end end
end end
end -- zone end -- zone
do -- Zone_Goal
--- Finds a @{Zone} based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
-- @return Core.Zone#ZONE_BASE The found ZONE.
function DATABASE:FindZoneGoal( ZoneName )
local ZoneFound = self.ZONES_GOAL[ZoneName]
return ZoneFound
end
--- Adds a @{Zone} based on the zone name in the DATABASE.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
-- @param Core.Zone#ZONE_BASE Zone The zone.
function DATABASE:AddZoneGoal( ZoneName, Zone )
if not self.ZONES_GOAL[ZoneName] then
self.ZONES_GOAL[ZoneName] = Zone
end
end
--- Deletes a @{Zone} from the DATABASE based on the zone name.
-- @param #DATABASE self
-- @param #string ZoneName The name of the zone.
function DATABASE:DeleteZoneGoal( ZoneName )
self.ZONES_GOAL[ZoneName] = nil
end
end -- Zone_Goal
do -- cargo do -- cargo
--- Adds a Cargo based on the Cargo Name in the DATABASE. --- Adds a Cargo based on the Cargo Name in the DATABASE.
-- @param #DATABASE self -- @param #DATABASE self
-- @param #string CargoName The name of the airbase -- @param #string CargoName The name of the airbase
function DATABASE:AddCargo( Cargo ) function DATABASE:AddCargo( Cargo )
if not self.CARGOS[Cargo.Name] then if not self.CARGOS[Cargo.Name] then
self.CARGOS[Cargo.Name] = Cargo self.CARGOS[Cargo.Name] = Cargo
end end
end end
--- Deletes a Cargo from the DATABASE based on the Cargo Name. --- Deletes a Cargo from the DATABASE based on the Cargo Name.
-- @param #DATABASE self -- @param #DATABASE self
-- @param #string CargoName The name of the airbase -- @param #string CargoName The name of the airbase
function DATABASE:DeleteCargo( CargoName ) function DATABASE:DeleteCargo( CargoName )
self.CARGOS[CargoName] = nil self.CARGOS[CargoName] = nil
end end
--- Finds an CARGO based on the CargoName. --- Finds an CARGO based on the CargoName.
-- @param #DATABASE self -- @param #DATABASE self
-- @param #string CargoName -- @param #string CargoName
-- @return Wrapper.Cargo#CARGO The found CARGO. -- @return Wrapper.Cargo#CARGO The found CARGO.
function DATABASE:FindCargo( CargoName ) function DATABASE:FindCargo( CargoName )
local CargoFound = self.CARGOS[CargoName] local CargoFound = self.CARGOS[CargoName]
return CargoFound return CargoFound
end end
--- Checks if the Template name has a #CARGO tag. --- Checks if the Template name has a #CARGO tag.
-- If yes, the group is a cargo. -- If yes, the group is a cargo.
-- @param #DATABASE self -- @param #DATABASE self
@@ -380,10 +415,10 @@ do -- cargo
function DATABASE:IsCargo( TemplateName ) function DATABASE:IsCargo( TemplateName )
TemplateName = env.getValueDictByKey( TemplateName ) TemplateName = env.getValueDictByKey( TemplateName )
local Cargo = TemplateName:match( "#(CARGO)" ) local Cargo = TemplateName:match( "#(CARGO)" )
return Cargo and Cargo == "CARGO" return Cargo and Cargo == "CARGO"
end end
--- Private method that registers new Static Templates within the DATABASE Object. --- Private method that registers new Static Templates within the DATABASE Object.
@@ -392,7 +427,7 @@ do -- cargo
function DATABASE:_RegisterCargos() function DATABASE:_RegisterCargos()
local Groups = UTILS.DeepCopy( self.GROUPS ) -- This is a very important statement. CARGO_GROUP:New creates a new _DATABASE.GROUP entry, which will confuse the loop. I searched 4 hours on this to find the bug! local Groups = UTILS.DeepCopy( self.GROUPS ) -- This is a very important statement. CARGO_GROUP:New creates a new _DATABASE.GROUP entry, which will confuse the loop. I searched 4 hours on this to find the bug!
for CargoGroupName, CargoGroup in pairs( Groups ) do for CargoGroupName, CargoGroup in pairs( Groups ) do
self:I( { Cargo = CargoGroupName } ) self:I( { Cargo = CargoGroupName } )
if self:IsCargo( CargoGroupName ) then if self:IsCargo( CargoGroupName ) then
@@ -405,12 +440,12 @@ do -- cargo
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName
local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") ) local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") )
local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") ) local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") )
self:I({"Register CargoGroup:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) self:I({"Register CargoGroup:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius ) CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius )
end end
end end
for CargoStaticName, CargoStatic in pairs( self.STATICS ) do for CargoStaticName, CargoStatic in pairs( self.STATICS ) do
if self:IsCargo( CargoStaticName ) then if self:IsCargo( CargoStaticName ) then
local CargoInfo = CargoStaticName:match("#CARGO(.*)") local CargoInfo = CargoStaticName:match("#CARGO(.*)")
@@ -421,7 +456,7 @@ do -- cargo
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName
local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") ) local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") )
local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") ) local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") )
if Category == "SLING" then if Category == "SLING" then
self:I({"Register CargoSlingload:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius}) self:I({"Register CargoSlingload:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius ) CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
@@ -433,7 +468,7 @@ do -- cargo
end end
end end
end end
end end
end -- cargo end -- cargo
@@ -479,9 +514,9 @@ function DATABASE:AddGroup( GroupName )
if not self.GROUPS[GroupName] then if not self.GROUPS[GroupName] then
self:I( { "Add GROUP:", GroupName } ) self:I( { "Add GROUP:", GroupName } )
self.GROUPS[GroupName] = GROUP:Register( GroupName ) self.GROUPS[GroupName] = GROUP:Register( GroupName )
end end
return self.GROUPS[GroupName] return self.GROUPS[GroupName]
end end
--- Adds a player based on the Player Name in the DATABASE. --- Adds a player based on the Player Name in the DATABASE.
@@ -584,7 +619,7 @@ function DATABASE:Spawn( SpawnTemplate )
for UnitID, UnitData in pairs( SpawnTemplate.units ) do for UnitID, UnitData in pairs( SpawnTemplate.units ) do
self:AddUnit( UnitData.name ) self:AddUnit( UnitData.name )
end end
return SpawnGroup return SpawnGroup
end end
@@ -616,21 +651,21 @@ end
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName ) function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName )
local GroupTemplateName = GroupName or env.getValueDictByKey( GroupTemplate.name ) local GroupTemplateName = GroupName or env.getValueDictByKey( GroupTemplate.name )
if not self.Templates.Groups[GroupTemplateName] then if not self.Templates.Groups[GroupTemplateName] then
self.Templates.Groups[GroupTemplateName] = {} self.Templates.Groups[GroupTemplateName] = {}
self.Templates.Groups[GroupTemplateName].Status = nil self.Templates.Groups[GroupTemplateName].Status = nil
end end
-- Delete the spans from the route, it is not needed and takes memory. -- Delete the spans from the route, it is not needed and takes memory.
if GroupTemplate.route and GroupTemplate.route.spans then if GroupTemplate.route and GroupTemplate.route.spans then
GroupTemplate.route.spans = nil GroupTemplate.route.spans = nil
end end
GroupTemplate.CategoryID = CategoryID GroupTemplate.CategoryID = CategoryID
GroupTemplate.CoalitionID = CoalitionSide GroupTemplate.CoalitionID = CoalitionSide
GroupTemplate.CountryID = CountryID GroupTemplate.CountryID = CountryID
self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName
self.Templates.Groups[GroupTemplateName].Template = GroupTemplate self.Templates.Groups[GroupTemplateName].Template = GroupTemplate
self.Templates.Groups[GroupTemplateName].groupId = GroupTemplate.groupId self.Templates.Groups[GroupTemplateName].groupId = GroupTemplate.groupId
@@ -645,7 +680,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do for unit_num, UnitTemplate in pairs( GroupTemplate.units ) do
UnitTemplate.name = env.getValueDictByKey(UnitTemplate.name) UnitTemplate.name = env.getValueDictByKey(UnitTemplate.name)
self.Templates.Units[UnitTemplate.name] = {} self.Templates.Units[UnitTemplate.name] = {}
self.Templates.Units[UnitTemplate.name].UnitName = UnitTemplate.name self.Templates.Units[UnitTemplate.name].UnitName = UnitTemplate.name
self.Templates.Units[UnitTemplate.name].Template = UnitTemplate self.Templates.Units[UnitTemplate.name].Template = UnitTemplate
@@ -663,8 +698,8 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, Category
self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID
self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate
end end
UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName UnitNames[#UnitNames+1] = self.Templates.Units[UnitTemplate.name].UnitName
end end
self:I( { Group = self.Templates.Groups[GroupTemplateName].GroupName, self:I( { Group = self.Templates.Groups[GroupTemplateName].GroupName,
@@ -693,13 +728,13 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
local StaticTemplate = UTILS.DeepCopy( StaticTemplate ) local StaticTemplate = UTILS.DeepCopy( StaticTemplate )
local StaticTemplateName = env.getValueDictByKey(StaticTemplate.name) local StaticTemplateName = env.getValueDictByKey(StaticTemplate.name)
self.Templates.Statics[StaticTemplateName] = self.Templates.Statics[StaticTemplateName] or {} self.Templates.Statics[StaticTemplateName] = self.Templates.Statics[StaticTemplateName] or {}
StaticTemplate.CategoryID = CategoryID StaticTemplate.CategoryID = CategoryID
StaticTemplate.CoalitionID = CoalitionID StaticTemplate.CoalitionID = CoalitionID
StaticTemplate.CountryID = CountryID StaticTemplate.CountryID = CountryID
self.Templates.Statics[StaticTemplateName].StaticName = StaticTemplateName self.Templates.Statics[StaticTemplateName].StaticName = StaticTemplateName
self.Templates.Statics[StaticTemplateName].GroupTemplate = StaticTemplate self.Templates.Statics[StaticTemplateName].GroupTemplate = StaticTemplate
self.Templates.Statics[StaticTemplateName].UnitTemplate = StaticTemplate.units[1] self.Templates.Statics[StaticTemplateName].UnitTemplate = StaticTemplate.units[1]
@@ -710,12 +745,12 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
self:I( { Static = self.Templates.Statics[StaticTemplateName].StaticName, self:I( { Static = self.Templates.Statics[StaticTemplateName].StaticName,
Coalition = self.Templates.Statics[StaticTemplateName].CoalitionID, Coalition = self.Templates.Statics[StaticTemplateName].CoalitionID,
Category = self.Templates.Statics[StaticTemplateName].CategoryID, Category = self.Templates.Statics[StaticTemplateName].CategoryID,
Country = self.Templates.Statics[StaticTemplateName].CountryID Country = self.Templates.Statics[StaticTemplateName].CountryID
} }
) )
self:AddStatic( StaticTemplateName ) self:AddStatic( StaticTemplateName )
end end
@@ -783,7 +818,7 @@ function DATABASE:_RegisterPlayers()
end end
end end
end end
return self return self
end end
@@ -799,12 +834,12 @@ function DATABASE:_RegisterGroupsAndUnits()
if DCSGroup:isExist() then if DCSGroup:isExist() then
local DCSGroupName = DCSGroup:getName() local DCSGroupName = DCSGroup:getName()
self:I( { "Register Group:", DCSGroupName } ) self:I( { "Register Group:", DCSGroupName } )
self:AddGroup( DCSGroupName ) self:AddGroup( DCSGroupName )
for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do
local DCSUnitName = DCSUnit:getName() local DCSUnitName = DCSUnit:getName()
self:I( { "Register Unit:", DCSUnitName } ) self:I( { "Register Unit:", DCSUnitName } )
self:AddUnit( DCSUnitName ) self:AddUnit( DCSUnitName )
@@ -812,10 +847,10 @@ function DATABASE:_RegisterGroupsAndUnits()
else else
self:E( { "Group does not exist: ", DCSGroup } ) self:E( { "Group does not exist: ", DCSGroup } )
end end
end end
end end
self:I("Groups:") self:I("Groups:")
for GroupName, Group in pairs( self.GROUPS ) do for GroupName, Group in pairs( self.GROUPS ) do
self:I( { "Group:", GroupName } ) self:I( { "Group:", GroupName } )
@@ -833,7 +868,7 @@ function DATABASE:_RegisterClients()
self:I( { "Register Client:", ClientName } ) self:I( { "Register Client:", ClientName } )
self:AddClient( ClientName ) self:AddClient( ClientName )
end end
return self return self
end end
@@ -847,7 +882,7 @@ function DATABASE:_RegisterStatics()
if DCSStatic:isExist() then if DCSStatic:isExist() then
local DCSStaticName = DCSStatic:getName() local DCSStaticName = DCSStatic:getName()
self:I( { "Register Static:", DCSStaticName } ) self:I( { "Register Static:", DCSStaticName } )
self:AddStatic( DCSStaticName ) self:AddStatic( DCSStaticName )
else else
@@ -887,7 +922,7 @@ function DATABASE:_EventOnBirth( Event )
if Event.IniDCSUnit then if Event.IniDCSUnit then
if Event.IniObjectCategory == 3 then if Event.IniObjectCategory == 3 then
self:AddStatic( Event.IniDCSUnitName ) self:AddStatic( Event.IniDCSUnitName )
else else
if Event.IniObjectCategory == 1 then if Event.IniObjectCategory == 1 then
self:AddUnit( Event.IniDCSUnitName ) self:AddUnit( Event.IniDCSUnitName )
@@ -923,7 +958,7 @@ function DATABASE:_EventOnDeadOrCrash( Event )
if Event.IniObjectCategory == 3 then if Event.IniObjectCategory == 3 then
if self.STATICS[Event.IniDCSUnitName] then if self.STATICS[Event.IniDCSUnitName] then
self:DeleteStatic( Event.IniDCSUnitName ) self:DeleteStatic( Event.IniDCSUnitName )
end end
else else
if Event.IniObjectCategory == 1 then if Event.IniObjectCategory == 1 then
if self.UNITS[Event.IniDCSUnitName] then if self.UNITS[Event.IniDCSUnitName] then
@@ -932,7 +967,7 @@ function DATABASE:_EventOnDeadOrCrash( Event )
end end
end end
end end
self:AccountDestroys( Event ) self:AccountDestroys( Event )
end end
@@ -986,7 +1021,7 @@ end
-- @return #DATABASE self -- @return #DATABASE self
function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set ) function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set )
self:F2( arg ) self:F2( arg )
local function CoRoutine() local function CoRoutine()
local Count = 0 local Count = 0
for ObjectID, Object in pairs( Set ) do for ObjectID, Object in pairs( Set ) do
@@ -995,20 +1030,20 @@ function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set )
Count = Count + 1 Count = Count + 1
-- if Count % 100 == 0 then -- if Count % 100 == 0 then
-- coroutine.yield( false ) -- coroutine.yield( false )
-- end -- end
end end
return true return true
end end
-- local co = coroutine.create( CoRoutine ) -- local co = coroutine.create( CoRoutine )
local co = CoRoutine local co = CoRoutine
local function Schedule() local function Schedule()
-- local status, res = coroutine.resume( co ) -- local status, res = coroutine.resume( co )
local status, res = co() local status, res = co()
self:T3( { status, res } ) self:T3( { status, res } )
if status == false then if status == false then
error( res ) error( res )
end end
@@ -1021,8 +1056,9 @@ function DATABASE:ForEach( IteratorFunction, FinalizeFunction, arg, Set )
return false return false
end end
local Scheduler = SCHEDULER:New( self, Schedule, {}, 0.001, 0.001, 0 ) --local Scheduler = SCHEDULER:New( self, Schedule, {}, 0.001, 0.001, 0 )
Schedule()
return self return self
end end
@@ -1033,7 +1069,7 @@ end
-- @return #DATABASE self -- @return #DATABASE self
function DATABASE:ForEachStatic( IteratorFunction, FinalizeFunction, ... ) --R2.1 function DATABASE:ForEachStatic( IteratorFunction, FinalizeFunction, ... ) --R2.1
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.STATICS ) self:ForEach( IteratorFunction, FinalizeFunction, arg, self.STATICS )
return self return self
@@ -1046,7 +1082,7 @@ end
-- @return #DATABASE self -- @return #DATABASE self
function DATABASE:ForEachUnit( IteratorFunction, FinalizeFunction, ... ) function DATABASE:ForEachUnit( IteratorFunction, FinalizeFunction, ... )
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.UNITS ) self:ForEach( IteratorFunction, FinalizeFunction, arg, self.UNITS )
return self return self
@@ -1059,7 +1095,7 @@ end
-- @return #DATABASE self -- @return #DATABASE self
function DATABASE:ForEachGroup( IteratorFunction, FinalizeFunction, ... ) function DATABASE:ForEachGroup( IteratorFunction, FinalizeFunction, ... )
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.GROUPS ) self:ForEach( IteratorFunction, FinalizeFunction, arg, self.GROUPS )
return self return self
@@ -1072,9 +1108,9 @@ end
-- @return #DATABASE self -- @return #DATABASE self
function DATABASE:ForEachPlayer( IteratorFunction, FinalizeFunction, ... ) function DATABASE:ForEachPlayer( IteratorFunction, FinalizeFunction, ... )
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERS ) self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERS )
return self return self
end end
@@ -1085,9 +1121,9 @@ end
-- @return #DATABASE self -- @return #DATABASE self
function DATABASE:ForEachPlayerJoined( IteratorFunction, FinalizeFunction, ... ) function DATABASE:ForEachPlayerJoined( IteratorFunction, FinalizeFunction, ... )
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERSJOINED ) self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERSJOINED )
return self return self
end end
@@ -1097,9 +1133,9 @@ end
-- @return #DATABASE self -- @return #DATABASE self
function DATABASE:ForEachPlayerUnit( IteratorFunction, FinalizeFunction, ... ) function DATABASE:ForEachPlayerUnit( IteratorFunction, FinalizeFunction, ... )
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERUNITS ) self:ForEach( IteratorFunction, FinalizeFunction, arg, self.PLAYERUNITS )
return self return self
end end
@@ -1110,7 +1146,7 @@ end
-- @return #DATABASE self -- @return #DATABASE self
function DATABASE:ForEachClient( IteratorFunction, ... ) function DATABASE:ForEachClient( IteratorFunction, ... )
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self.CLIENTS ) self:ForEach( IteratorFunction, arg, self.CLIENTS )
return self return self
@@ -1122,7 +1158,7 @@ end
-- @return #DATABASE self -- @return #DATABASE self
function DATABASE:ForEachCargo( IteratorFunction, ... ) function DATABASE:ForEachCargo( IteratorFunction, ... )
self:F2( arg ) self:F2( arg )
self:ForEach( IteratorFunction, arg, self.CARGOS ) self:ForEach( IteratorFunction, arg, self.CARGOS )
return self return self
@@ -1244,10 +1280,10 @@ function DATABASE:_RegisterTemplates()
if (CoalitionName == 'red' or CoalitionName == 'blue' or CoalitionName == 'neutrals') and type(coa_data) == 'table' then if (CoalitionName == 'red' or CoalitionName == 'blue' or CoalitionName == 'neutrals') and type(coa_data) == 'table' then
--self.Units[coa_name] = {} --self.Units[coa_name] = {}
local CoalitionSide = coalition.side[string.upper(CoalitionName)] local CoalitionSide = coalition.side[string.upper(CoalitionName)]
if CoalitionName=="red" then if CoalitionName=="red" then
CoalitionSide=coalition.side.NEUTRAL CoalitionSide=coalition.side.RED
elseif CoalitionName=="blue" then elseif CoalitionName=="blue" then
CoalitionSide=coalition.side.BLUE CoalitionSide=coalition.side.BLUE
else else
@@ -1277,10 +1313,10 @@ function DATABASE:_RegisterTemplates()
local CountryName = string.upper(cntry_data.name) local CountryName = string.upper(cntry_data.name)
local CountryID = cntry_data.id local CountryID = cntry_data.id
self.COUNTRY_ID[CountryName] = CountryID self.COUNTRY_ID[CountryName] = CountryID
self.COUNTRY_NAME[CountryID] = CountryName self.COUNTRY_NAME[CountryID] = CountryName
--self.Units[coa_name][countryName] = {} --self.Units[coa_name][countryName] = {}
--self.Units[coa_name][countryName]["countryId"] = cntry_data.id --self.Units[coa_name][countryName]["countryId"] = cntry_data.id
@@ -1299,18 +1335,18 @@ function DATABASE:_RegisterTemplates()
for group_num, Template in pairs(obj_type_data.group) do for group_num, Template in pairs(obj_type_data.group) do
if obj_type_name ~= "static" and Template and Template.units and type(Template.units) == 'table' then --making sure again- this is a valid group if obj_type_name ~= "static" and Template and Template.units and type(Template.units) == 'table' then --making sure again- this is a valid group
self:_RegisterGroupTemplate( self:_RegisterGroupTemplate(
Template, Template,
CoalitionSide, CoalitionSide,
_DATABASECategory[string.lower(CategoryName)], _DATABASECategory[string.lower(CategoryName)],
CountryID CountryID
) )
else else
self:_RegisterStaticTemplate( self:_RegisterStaticTemplate(
Template, Template,
CoalitionSide, CoalitionSide,
_DATABASECategory[string.lower(CategoryName)], _DATABASECategory[string.lower(CategoryName)],
CountryID CountryID
) )
end --if GroupTemplate and GroupTemplate.units then end --if GroupTemplate and GroupTemplate.units then
end --for group_num, GroupTemplate in pairs(obj_type_data.group) do end --for group_num, GroupTemplate in pairs(obj_type_data.group) do
@@ -1331,35 +1367,35 @@ end
-- @param Core.Event#EVENTDATA Event -- @param Core.Event#EVENTDATA Event
function DATABASE:AccountHits( Event ) function DATABASE:AccountHits( Event )
self:F( { Event } ) self:F( { Event } )
if Event.IniPlayerName ~= nil then -- It is a player that is hitting something if Event.IniPlayerName ~= nil then -- It is a player that is hitting something
self:T( "Hitting Something" ) self:T( "Hitting Something" )
-- What is he hitting? -- What is he hitting?
if Event.TgtCategory then if Event.TgtCategory then
-- A target got hit -- A target got hit
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {} self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
local Hit = self.HITS[Event.TgtUnitName] local Hit = self.HITS[Event.TgtUnitName]
Hit.Players = Hit.Players or {} Hit.Players = Hit.Players or {}
Hit.Players[Event.IniPlayerName] = true Hit.Players[Event.IniPlayerName] = true
end end
end end
-- It is a weapon initiated by a player, that is hitting something -- It is a weapon initiated by a player, that is hitting something
-- This seems to occur only with scenery and static objects. -- This seems to occur only with scenery and static objects.
if Event.WeaponPlayerName ~= nil then if Event.WeaponPlayerName ~= nil then
self:T( "Hitting Scenery" ) self:T( "Hitting Scenery" )
-- What is he hitting? -- What is he hitting?
if Event.TgtCategory then if Event.TgtCategory then
if Event.WeaponCoalition then -- A coalition object was hit, probably a static. if Event.WeaponCoalition then -- A coalition object was hit, probably a static.
-- A target got hit -- A target got hit
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {} self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
local Hit = self.HITS[Event.TgtUnitName] local Hit = self.HITS[Event.TgtUnitName]
Hit.Players = Hit.Players or {} Hit.Players = Hit.Players or {}
Hit.Players[Event.WeaponPlayerName] = true Hit.Players[Event.WeaponPlayerName] = true
else -- A scenery object was hit. else -- A scenery object was hit.
@@ -1367,13 +1403,13 @@ end
end end
end end
end end
--- Account the destroys. --- Account the destroys.
-- @param #DATABASE self -- @param #DATABASE self
-- @param Core.Event#EVENTDATA Event -- @param Core.Event#EVENTDATA Event
function DATABASE:AccountDestroys( Event ) function DATABASE:AccountDestroys( Event )
self:F( { Event } ) self:F( { Event } )
local TargetUnit = nil local TargetUnit = nil
local TargetGroup = nil local TargetGroup = nil
local TargetUnitName = "" local TargetUnitName = ""
@@ -1385,26 +1421,26 @@ end
local TargetUnitCoalition = nil local TargetUnitCoalition = nil
local TargetUnitCategory = nil local TargetUnitCategory = nil
local TargetUnitType = nil local TargetUnitType = nil
if Event.IniDCSUnit then if Event.IniDCSUnit then
TargetUnit = Event.IniUnit TargetUnit = Event.IniUnit
TargetUnitName = Event.IniDCSUnitName TargetUnitName = Event.IniDCSUnitName
TargetGroup = Event.IniDCSGroup TargetGroup = Event.IniDCSGroup
TargetGroupName = Event.IniDCSGroupName TargetGroupName = Event.IniDCSGroupName
TargetPlayerName = Event.IniPlayerName TargetPlayerName = Event.IniPlayerName
TargetCoalition = Event.IniCoalition TargetCoalition = Event.IniCoalition
--TargetCategory = TargetUnit:getCategory() --TargetCategory = TargetUnit:getCategory()
--TargetCategory = TargetUnit:getDesc().category -- Workaround --TargetCategory = TargetUnit:getDesc().category -- Workaround
TargetCategory = Event.IniCategory TargetCategory = Event.IniCategory
TargetType = Event.IniTypeName TargetType = Event.IniTypeName
TargetUnitType = TargetType TargetUnitType = TargetType
self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } ) self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } )
end end
local Destroyed = false local Destroyed = false
-- What is the player destroying? -- What is the player destroying?
@@ -1413,8 +1449,3 @@ end
self.DESTROYS[Event.IniUnitName] = true self.DESTROYS[Event.IniUnitName] = true
end end
end end
+47 -1
View File
@@ -189,7 +189,9 @@ world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000
world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001 world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001
world.event.S_EVENT_NEW_ZONE = world.event.S_EVENT_MAX + 1002 world.event.S_EVENT_NEW_ZONE = world.event.S_EVENT_MAX + 1002
world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1003 world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1003
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1004 world.event.S_EVENT_NEW_ZONE_GOAL = world.event.S_EVENT_MAX + 1004
world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
--- The different types of events supported by MOOSE. --- The different types of events supported by MOOSE.
@@ -226,6 +228,8 @@ EVENTS = {
DeleteCargo = world.event.S_EVENT_DELETE_CARGO, DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
NewZone = world.event.S_EVENT_NEW_ZONE, NewZone = world.event.S_EVENT_NEW_ZONE,
DeleteZone = world.event.S_EVENT_DELETE_ZONE, DeleteZone = world.event.S_EVENT_DELETE_ZONE,
NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL,
DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL,
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT, RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
} }
@@ -462,6 +466,16 @@ local _EVENTMETA = {
Event = "OnEventDeleteZone", Event = "OnEventDeleteZone",
Text = "S_EVENT_DELETE_ZONE" Text = "S_EVENT_DELETE_ZONE"
}, },
[EVENTS.NewZoneGoal] = {
Order = 1,
Event = "OnEventNewZoneGoal",
Text = "S_EVENT_NEW_ZONE_GOAL"
},
[EVENTS.DeleteZoneGoal] = {
Order = 1,
Event = "OnEventDeleteZoneGoal",
Text = "S_EVENT_DELETE_ZONE_GOAL"
},
[EVENTS.RemoveUnit] = { [EVENTS.RemoveUnit] = {
Order = -1, Order = -1,
Event = "OnEventRemoveUnit", Event = "OnEventRemoveUnit",
@@ -800,6 +814,38 @@ do -- Event Creation
world.onEvent( Event ) world.onEvent( Event )
end end
--- Creation of a New ZoneGoal Event.
-- @param #EVENT self
-- @param Core.Functional#ZONE_GOAL ZoneGoal The ZoneGoal created.
function EVENT:CreateEventNewZoneGoal( ZoneGoal )
self:F( { ZoneGoal } )
local Event = {
id = EVENTS.NewZoneGoal,
time = timer.getTime(),
ZoneGoal = ZoneGoal,
}
world.onEvent( Event )
end
--- Creation of a ZoneGoal Deletion Event.
-- @param #EVENT self
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
function EVENT:CreateEventDeleteZoneGoal( ZoneGoal )
self:F( { ZoneGoal } )
local Event = {
id = EVENTS.DeleteZoneGoal,
time = timer.getTime(),
ZoneGoal = ZoneGoal,
}
world.onEvent( Event )
end
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event. --- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
-- @param #EVENT self -- @param #EVENT self
-- @param Wrapper.Unit#UNIT PlayerUnit. -- @param Wrapper.Unit#UNIT PlayerUnit.
+13 -3
View File
@@ -594,7 +594,17 @@ do -- FSM
return errmsg return errmsg
end end
if self[handler] then if self[handler] then
self:T( "*** FSM *** " .. step .. " *** " .. params[1] .. " --> " .. params[2] .. " --> " .. params[3] ) if step == "onafter" or step == "OnAfter" then
self:T( ":::>" .. step .. params[2] .. " : " .. params[1] .. " >> " .. params[2] .. ">" .. step .. params[2] .. "()" .. " >> " .. params[3] )
elseif step == "onbefore" or step == "OnBefore" then
self:T( ":::>" .. step .. params[2] .. " : " .. params[1] .. " >> " .. step .. params[2] .. "()" .. ">" .. params[2] .. " >> " .. params[3] )
elseif step == "onenter" or step == "OnEnter" then
self:T( ":::>" .. step .. params[3] .. " : " .. params[1] .. " >> " .. params[2] .. " >> " .. step .. params[3] .. "()" .. ">" .. params[3] )
elseif step == "onleave" or step == "OnLeave" then
self:T( ":::>" .. step .. params[1] .. " : " .. params[1] .. ">" .. step .. params[1] .. "()" .. " >> " .. params[2] .. " >> " .. params[3] )
else
self:T( ":::>" .. step .. " : " .. params[1] .. " >> " .. params[2] .. " >> " .. params[3] )
end
self._EventSchedules[EventName] = nil self._EventSchedules[EventName] = nil
local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler ) local Result, Value = xpcall( function() return self[handler]( self, unpack( params ) ) end, ErrorHandler )
return Value return Value
@@ -718,13 +728,13 @@ do -- FSM
if DelaySeconds < 0 then -- Only call the event ONCE! if DelaySeconds < 0 then -- Only call the event ONCE!
DelaySeconds = math.abs( DelaySeconds ) DelaySeconds = math.abs( DelaySeconds )
if not self._EventSchedules[EventName] then if not self._EventSchedules[EventName] then
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 ) CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
self._EventSchedules[EventName] = CallID self._EventSchedules[EventName] = CallID
else else
-- reschedule -- reschedule
end end
else else
CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1 ) CallID = self.CallScheduler:Schedule( self, self._handler, { EventName, ... }, DelaySeconds or 1, nil, nil, nil, 4, true )
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." )
+1 -1
View File
@@ -2075,7 +2075,7 @@ do -- COORDINATE
-- @return #string The coordinate Text in the configured coordinate system. -- @return #string The coordinate Text in the configured coordinate system.
function COORDINATE:ToString( Controllable, Settings, Task ) function COORDINATE:ToString( Controllable, Settings, Task )
self:E( { Controllable = Controllable and Controllable:GetName() } ) -- self:E( { Controllable = Controllable and Controllable:GetName() } )
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
-466
View File
@@ -800,470 +800,4 @@ function BEACON:_TACANToFrequency(TACANChannel, TACANMode)
return (A + TACANChannel - B) * 1000000 return (A + TACANChannel - B) * 1000000
end end
--- Manages radio transmissions.
--
-- @type RADIOQUEUE
-- @field #string ClassName Name of the class "RADIOQUEUE".
-- @field #string lid ID for dcs.log.
-- @field #number frequency The radio frequency in Hz.
-- @field #number modulation The radio modulation. Either radio.modulation.AM or radio.modulation.FM.
-- @field Core.Scheduler#SCHEDULER scheduler The scheduler.
-- @field #string RQid The radio queue scheduler ID.
-- @field #table queue The queue of transmissions.
-- @field #number Tlast Time (abs) when the last transmission finished.
-- @field Core.Point#COORDINATE sendercoord Coordinate from where transmissions are broadcasted.
-- @field #number sendername Name of the sending unit or static.
-- @field Wrapper.Positionable#POSITIONABLE positionable The positionable to broadcast the message.
-- @field #number power Power of radio station in Watts. Default 100 W.
-- @field #table numbers Table of number transmission parameters.
-- @extends Core.Base#BASE
RADIOQUEUE = {
ClassName = "RADIOQUEUE",
lid=nil,
frequency=nil,
modulation=nil,
scheduler=nil,
RQid=nil,
queue={},
Tlast=nil,
sendercoord=nil,
sendername=nil,
positionable=nil,
power=100,
numbers={},
}
--- Radio queue transmission data.
-- @type RADIOQUEUE.Transmission
-- @field #string filename Name of the file to be transmitted.
-- @field #string path Path in miz file where the file is located.
-- @field #number duration Duration in seconds.
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
-- @field #boolean isplaying If true, transmission is currently playing.
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
--- Create a new RADIOQUEUE object for a given radio frequency/modulation.
-- @param #RADIOQUEUE self
-- @param #number frequency The radio frequency in MHz.
-- @param #number modulation (Optional) The radio modulation. Default radio.modulation.AM.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:New(frequency, modulation)
-- Inherit base
local self=BASE:Inherit(self, BASE:New()) -- Core.Radio#RADIOQUEUE
self.lid="RADIOQUEUE | "
if frequency==nil then
self:E(self.lid.."ERROR: No frequency specified as first parameter!")
return nil
end
-- Frequency in Hz.
self.frequency=frequency*1000000
-- Modulation.
self.modulation=modulation or radio.modulation.AM
-- Scheduler
self.scheduler=SCHEDULER:New()
return self
end
--- Start the radio queue.
-- @param #RADIOQUEUE self
-- @param #number delay (Optional) Delay in seconds, before the radio queue is started. Default 1 sec.
-- @param #number dt (Optional) Time step in seconds for checking the queue. Default 0.01 sec.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:Start(delay, dt)
delay=delay or 1
dt=dt or 0.01
self:I(self.lid..string.format("Starting RADIOQUEUE in %.1f seconds with interval dt=%.3f seconds.", delay, dt))
self.RQid=self.scheduler:Schedule(self, self._CheckRadioQueue, {}, delay, dt)
return self
end
--- Stop the radio queue. Stop scheduler and delete queue.
-- @param #RADIOQUEUE self
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:Stop()
self:I(self.lid.."Stopping RADIOQUEUE.")
self.scheduler:Stop(self.RQid)
self.queue={}
return self
end
--- Set coordinate from where the transmission is broadcasted.
-- @param #RADIOQUEUE self
-- @param Core.Point#COORDINATE coordinate Coordinate of the sender.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetSenderCoordinate(coordinate)
self.sendercoord=coordinate
return self
end
--- Set name of unit or static from which transmissions are made.
-- @param #RADIOQUEUE self
-- @param #string name Name of the unit or static used for transmissions.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetSenderUnitName(name)
self.sendername=name
return self
end
--- Set parameters of a digit.
-- @param #RADIOQUEUE self
-- @param #number digit The digit 0-9.
-- @param #string filename The name of the sound file.
-- @param #number duration The duration of the sound file in seconds.
-- @param #string path The directory within the miz file where the sound is located. Default "l10n/DEFAULT/".
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetDigit(digit, filename, duration, path)
local transmission={} --#RADIOQUEUE.Transmission
transmission.filename=filename
transmission.duration=duration
transmission.path=path or "l10n/DEFAULT/"
-- Convert digit to string in case it is given as a number.
if type(digit)=="number" then
digit=tostring(digit)
end
-- Set transmission.
self.numbers[digit]=transmission
return self
end
--- Add a transmission to the radio queue.
-- @param #RADIOQUEUE self
-- @param #RADIOQUEUE.Transmission transmission The transmission data table.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:AddTransmission(transmission)
self:F({transmission=transmission})
-- Init.
transmission.isplaying=false
transmission.Tstarted=nil
-- Add to queue.
table.insert(self.queue, transmission)
return self
end
--- Add a transmission to the radio queue.
-- @param #RADIOQUEUE self
-- @param #string filename Name of the sound file. Usually an ogg or wav file type.
-- @param #number duration Duration in seconds the file lasts.
-- @param #number path Directory path inside the miz file where the sound file is located. Default "l10n/DEFAULT/".
-- @param #number tstart Start time (abs) seconds. Default now.
-- @param #number interval Interval in seconds after the last transmission finished.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval)
-- Sanity checks.
if not filename then
self:E(self.lid.."ERROR: No filename specified.")
return nil
end
if type(filename)~="string" then
self:E(self.lid.."ERROR: Filename specified is NOT a string.")
return nil
end
if not duration then
self:E(self.lid.."ERROR: No duration of transmission specified.")
return nil
end
if type(duration)~="number" then
self:E(self.lid.."ERROR: Duration specified is NOT a number.")
return nil
end
local transmission={} --#RADIOQUEUE.Transmission
transmission.filename=filename
transmission.duration=duration
transmission.path=path or "l10n/DEFAULT/"
transmission.Tplay=tstart or timer.getAbsTime()
-- Add transmission to queue.
self:AddTransmission(transmission)
return self
end
--- Convert a number (as string) into a radio transmission.
-- E.g. for board number or headings.
-- @param #RADIOQUEUE self
-- @param #string number Number string, e.g. "032" or "183".
-- @param #number delay Delay before transmission in seconds.
-- @param #number interval Interval between the next call.
-- @return #number Duration of the call in seconds.
function RADIOQUEUE:Number2Transmission(number, delay, interval)
--- Split string into characters.
local function _split(str)
local chars={}
for i=1,#str do
local c=str:sub(i,i)
table.insert(chars, c)
end
return chars
end
-- Split string into characters.
local numbers=_split(number)
local wait=0
for i=1,#numbers do
-- Current number
local n=numbers[i]
-- Radio call.
local transmission=UTILS.DeepCopy(self.numbers[n]) --#RADIOQUEUE.Transmission
transmission.Tplay=timer.getAbsTime()+(delay or 0)
if interval and i==1 then
transmission.interval=interval
end
self:AddTransmission(transmission)
-- Add up duration of the number.
wait=wait+transmission.duration
end
-- Return the total duration of the call.
return wait
end
--- Broadcast radio message.
-- @param #RADIOQUEUE self
-- @param #RADIOQUEUE.Transmission transmission The transmission.
function RADIOQUEUE:Broadcast(transmission)
-- Get unit sending the transmission.
local sender=self:_GetRadioSender()
-- Construct file name.
local filename=string.format("%s%s", transmission.path, transmission.filename)
-- Create subtitle for transmission.
--local subtitle=self:_RadioSubtitle(radio, call, loud)
if sender then
-- Broadcasting from aircraft. Only players tuned in to the right frequency will see the message.
self:T(self.lid..string.format("Broadcasting from aircraft %s", sender:GetName()))
-- Command to set the Frequency for the transmission.
local commandFrequency={
id="SetFrequency",
params={
frequency=self.frequency, -- Frequency in Hz.
modulation=self.modulation,
}}
-- Command to tranmit the call.
local commandTransmit={
id = "TransmitMessage",
params = {
file=filename,
duration=transmission.subduration or 5,
subtitle=transmission.subtitle or "",
loop=false,
}}
-- Set commend for frequency
sender:SetCommand(commandFrequency)
-- Set command for radio transmission.
sender:SetCommand(commandTransmit)
else
-- Broadcasting from carrier. No subtitle possible. Need to send messages to players.
self:T(self.lid..string.format("Broadcasting from carrier via trigger.action.radioTransmission()."))
-- Position from where to transmit.
local vec3=nil
-- Try to get positon from sender unit/static.
if self.sendername then
local coord=self:_GetRadioSenderCoord()
if coord then
vec3=coord:GetVec3()
end
end
-- Try to get fixed positon.
if self.sendercoord and not vec3 then
vec3=self.sendercoord:GetVec3()
end
-- Transmit via trigger.
if vec3 then
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
end
end
end
--- Check radio queue for transmissions to be broadcasted.
-- @param #RADIOQUEUE self
function RADIOQUEUE:_CheckRadioQueue()
-- Check if queue is empty.
if #self.queue==0 then
return
end
-- Get current abs time.
local time=timer.getAbsTime()
local playing=false
local next=nil --#RADIOQUEUE.Transmission
local remove=nil
for i,_transmission in ipairs(self.queue) do
local transmission=_transmission --#RADIOQUEUE.Transmission
-- Check if transmission time has passed.
if time>=transmission.Tplay then
-- Check if transmission is currently playing.
if transmission.isplaying then
-- Check if transmission is finished.
if time>=transmission.Tstarted+transmission.duration then
-- Transmission over.
transmission.isplaying=false
-- Remove ith element in queue.
remove=i
-- Store time last transmission finished.
self.Tlast=time
else -- still playing
-- Transmission is still playing.
playing=true
end
else -- not playing yet
local Tlast=self.Tlast
if transmission.interval==nil then
-- Not playing ==> this will be next.
if next==nil then
next=transmission
end
else
if Tlast==nil or time-Tlast>=transmission.interval then
next=transmission
else
end
end
-- We got a transmission or one with an interval that is not due yet. No need for anything else.
if next or Tlast then
break
end
end
else
-- Transmission not due yet.
end
end
-- Found a new transmission.
if next~=nil and not playing then
self:Broadcast(next)
next.isplaying=true
next.Tstarted=time
end
-- Remove completed calls from queue.
if remove then
table.remove(self.queue, remove)
end
end
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
-- @param #RADIOQUEUE self
-- @return Wrapper.Unit#UNIT Sending aircraft unit or nil if was not setup, is not an aircraft or is not alive.
function RADIOQUEUE:_GetRadioSender()
-- Check if we have a sending aircraft.
local sender=nil --Wrapper.Unit#UNIT
-- Try the general default.
if self.sendername then
-- First try to find a unit
sender=UNIT:FindByName(self.sendername)
-- Check that sender is alive and an aircraft.
if sender and sender:IsAlive() and sender:IsAir() then
return sender
end
end
return nil
end
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
-- @param #RADIOQUEUE self
-- @return Core.Point#COORDINATE Coordinate of the sender unit.
function RADIOQUEUE:_GetRadioSenderCoord()
local vec3=nil
-- Try the general default.
if self.sendername then
-- First try to find a unit
local sender=UNIT:FindByName(self.sendername)
-- Check that sender is alive and an aircraft.
if sender and sender:IsAlive() then
return sender:GetCoodinate()
end
-- Now try a static.
local sender=STATIC:FindByName(self.sendername)
-- Check that sender is alive and an aircraft.
if sender then
return sender:GetCoodinate()
end
end
return nil
end
+483
View File
@@ -0,0 +1,483 @@
--- **Core** - Queues Radio Transmissions.
--
-- ===
--
-- ## Features:
--
-- * Managed Radio Transmissions.
--
-- ===
--
-- ### Authors: funkyfranky
--
-- @module Core.RadioQueue
-- @image Core_Radio.JPG
--- Manages radio transmissions.
--
-- @type RADIOQUEUE
-- @field #string ClassName Name of the class "RADIOQUEUE".
-- @field #string lid ID for dcs.log.
-- @field #number frequency The radio frequency in Hz.
-- @field #number modulation The radio modulation. Either radio.modulation.AM or radio.modulation.FM.
-- @field Core.Scheduler#SCHEDULER scheduler The scheduler.
-- @field #string RQid The radio queue scheduler ID.
-- @field #table queue The queue of transmissions.
-- @field #number Tlast Time (abs) when the last transmission finished.
-- @field Core.Point#COORDINATE sendercoord Coordinate from where transmissions are broadcasted.
-- @field #number sendername Name of the sending unit or static.
-- @field Wrapper.Positionable#POSITIONABLE positionable The positionable to broadcast the message.
-- @field #number power Power of radio station in Watts. Default 100 W.
-- @field #table numbers Table of number transmission parameters.
-- @extends Core.Base#BASE
RADIOQUEUE = {
ClassName = "RADIOQUEUE",
lid=nil,
frequency=nil,
modulation=nil,
scheduler=nil,
RQid=nil,
queue={},
Tlast=nil,
sendercoord=nil,
sendername=nil,
positionable=nil,
power=100,
numbers={},
}
--- Radio queue transmission data.
-- @type RADIOQUEUE.Transmission
-- @field #string filename Name of the file to be transmitted.
-- @field #string path Path in miz file where the file is located.
-- @field #number duration Duration in seconds.
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
-- @field #boolean isplaying If true, transmission is currently playing.
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
--- Create a new RADIOQUEUE object for a given radio frequency/modulation.
-- @param #RADIOQUEUE self
-- @param #number frequency The radio frequency in MHz.
-- @param #number modulation (Optional) The radio modulation. Default radio.modulation.AM.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:New(frequency, modulation)
-- Inherit base
local self=BASE:Inherit(self, BASE:New()) -- #RADIOQUEUE
self.lid="RADIOQUEUE | "
if frequency==nil then
self:E(self.lid.."ERROR: No frequency specified as first parameter!")
return nil
end
-- Frequency in Hz.
self.frequency=frequency*1000000
-- Modulation.
self.modulation=modulation or radio.modulation.AM
-- Scheduler
self.scheduler=SCHEDULER:New()
return self
end
--- Start the radio queue.
-- @param #RADIOQUEUE self
-- @param #number delay (Optional) Delay in seconds, before the radio queue is started. Default 1 sec.
-- @param #number dt (Optional) Time step in seconds for checking the queue. Default 0.01 sec.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:Start(delay, dt)
delay=delay or 1
dt=dt or 0.01
self:I(self.lid..string.format("Starting RADIOQUEUE in %.1f seconds with interval dt=%.3f seconds.", delay, dt))
self.RQid=self.scheduler:Schedule(self, self._CheckRadioQueue, {}, delay, dt)
return self
end
--- Stop the radio queue. Stop scheduler and delete queue.
-- @param #RADIOQUEUE self
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:Stop()
self:I(self.lid.."Stopping RADIOQUEUE.")
self.scheduler:Stop(self.RQid)
self.queue={}
return self
end
--- Set coordinate from where the transmission is broadcasted.
-- @param #RADIOQUEUE self
-- @param Core.Point#COORDINATE coordinate Coordinate of the sender.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetSenderCoordinate(coordinate)
self.sendercoord=coordinate
return self
end
--- Set name of unit or static from which transmissions are made.
-- @param #RADIOQUEUE self
-- @param #string name Name of the unit or static used for transmissions.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetSenderUnitName(name)
self.sendername=name
return self
end
--- Set parameters of a digit.
-- @param #RADIOQUEUE self
-- @param #number digit The digit 0-9.
-- @param #string filename The name of the sound file.
-- @param #number duration The duration of the sound file in seconds.
-- @param #string path The directory within the miz file where the sound is located. Default "l10n/DEFAULT/".
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:SetDigit(digit, filename, duration, path)
local transmission={} --#RADIOQUEUE.Transmission
transmission.filename=filename
transmission.duration=duration
transmission.path=path or "l10n/DEFAULT/"
-- Convert digit to string in case it is given as a number.
if type(digit)=="number" then
digit=tostring(digit)
end
-- Set transmission.
self.numbers[digit]=transmission
return self
end
--- Add a transmission to the radio queue.
-- @param #RADIOQUEUE self
-- @param #RADIOQUEUE.Transmission transmission The transmission data table.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:AddTransmission(transmission)
self:F({transmission=transmission})
-- Init.
transmission.isplaying=false
transmission.Tstarted=nil
-- Add to queue.
table.insert(self.queue, transmission)
return self
end
--- Add a transmission to the radio queue.
-- @param #RADIOQUEUE self
-- @param #string filename Name of the sound file. Usually an ogg or wav file type.
-- @param #number duration Duration in seconds the file lasts.
-- @param #number path Directory path inside the miz file where the sound file is located. Default "l10n/DEFAULT/".
-- @param #number tstart Start time (abs) seconds. Default now.
-- @param #number interval Interval in seconds after the last transmission finished.
-- @return #RADIOQUEUE self The RADIOQUEUE object.
function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval)
-- Sanity checks.
if not filename then
self:E(self.lid.."ERROR: No filename specified.")
return nil
end
if type(filename)~="string" then
self:E(self.lid.."ERROR: Filename specified is NOT a string.")
return nil
end
if not duration then
self:E(self.lid.."ERROR: No duration of transmission specified.")
return nil
end
if type(duration)~="number" then
self:E(self.lid.."ERROR: Duration specified is NOT a number.")
return nil
end
local transmission={} --#RADIOQUEUE.Transmission
transmission.filename=filename
transmission.duration=duration
transmission.path=path or "l10n/DEFAULT/"
transmission.Tplay=tstart or timer.getAbsTime()
-- Add transmission to queue.
self:AddTransmission(transmission)
return self
end
--- Convert a number (as string) into a radio transmission.
-- E.g. for board number or headings.
-- @param #RADIOQUEUE self
-- @param #string number Number string, e.g. "032" or "183".
-- @param #number delay Delay before transmission in seconds.
-- @param #number interval Interval between the next call.
-- @return #number Duration of the call in seconds.
function RADIOQUEUE:Number2Transmission(number, delay, interval)
--- Split string into characters.
local function _split(str)
local chars={}
for i=1,#str do
local c=str:sub(i,i)
table.insert(chars, c)
end
return chars
end
-- Split string into characters.
local numbers=_split(number)
local wait=0
for i=1,#numbers do
-- Current number
local n=numbers[i]
-- Radio call.
local transmission=UTILS.DeepCopy(self.numbers[n]) --#RADIOQUEUE.Transmission
transmission.Tplay=timer.getAbsTime()+(delay or 0)
if interval and i==1 then
transmission.interval=interval
end
self:AddTransmission(transmission)
-- Add up duration of the number.
wait=wait+transmission.duration
end
-- Return the total duration of the call.
return wait
end
--- Broadcast radio message.
-- @param #RADIOQUEUE self
-- @param #RADIOQUEUE.Transmission transmission The transmission.
function RADIOQUEUE:Broadcast(transmission)
-- Get unit sending the transmission.
local sender=self:_GetRadioSender()
-- Construct file name.
local filename=string.format("%s%s", transmission.path, transmission.filename)
-- Create subtitle for transmission.
--local subtitle=self:_RadioSubtitle(radio, call, loud)
if sender then
-- Broadcasting from aircraft. Only players tuned in to the right frequency will see the message.
self:T(self.lid..string.format("Broadcasting from aircraft %s", sender:GetName()))
-- Command to set the Frequency for the transmission.
local commandFrequency={
id="SetFrequency",
params={
frequency=self.frequency, -- Frequency in Hz.
modulation=self.modulation,
}}
-- Command to tranmit the call.
local commandTransmit={
id = "TransmitMessage",
params = {
file=filename,
duration=transmission.subduration or 5,
subtitle=transmission.subtitle or "",
loop=false,
}}
-- Set commend for frequency
sender:SetCommand(commandFrequency)
-- Set command for radio transmission.
sender:SetCommand(commandTransmit)
else
-- Broadcasting from carrier. No subtitle possible. Need to send messages to players.
self:T(self.lid..string.format("Broadcasting from carrier via trigger.action.radioTransmission()."))
-- Position from where to transmit.
local vec3=nil
-- Try to get positon from sender unit/static.
if self.sendername then
local coord=self:_GetRadioSenderCoord()
if coord then
vec3=coord:GetVec3()
end
end
-- Try to get fixed positon.
if self.sendercoord and not vec3 then
vec3=self.sendercoord:GetVec3()
end
-- Transmit via trigger.
if vec3 then
self:E("Sending")
self:E( { filename = filename, vec3 = vec3, modulation = self.modulation, frequency = self.frequency, power = self.power } )
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
end
end
end
--- Check radio queue for transmissions to be broadcasted.
-- @param #RADIOQUEUE self
function RADIOQUEUE:_CheckRadioQueue()
-- Check if queue is empty.
if #self.queue==0 then
return
end
-- Get current abs time.
local time=timer.getAbsTime()
local playing=false
local next=nil --#RADIOQUEUE.Transmission
local remove=nil
for i,_transmission in ipairs(self.queue) do
local transmission=_transmission --#RADIOQUEUE.Transmission
-- Check if transmission time has passed.
if time>=transmission.Tplay then
-- Check if transmission is currently playing.
if transmission.isplaying then
-- Check if transmission is finished.
if time>=transmission.Tstarted+transmission.duration then
-- Transmission over.
transmission.isplaying=false
-- Remove ith element in queue.
remove=i
-- Store time last transmission finished.
self.Tlast=time
else -- still playing
-- Transmission is still playing.
playing=true
end
else -- not playing yet
local Tlast=self.Tlast
if transmission.interval==nil then
-- Not playing ==> this will be next.
if next==nil then
next=transmission
end
else
if Tlast==nil or time-Tlast>=transmission.interval then
next=transmission
else
end
end
-- We got a transmission or one with an interval that is not due yet. No need for anything else.
if next or Tlast then
break
end
end
else
-- Transmission not due yet.
end
end
-- Found a new transmission.
if next~=nil and not playing then
self:Broadcast(next)
next.isplaying=true
next.Tstarted=time
end
-- Remove completed calls from queue.
if remove then
table.remove(self.queue, remove)
end
end
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
-- @param #RADIOQUEUE self
-- @return Wrapper.Unit#UNIT Sending aircraft unit or nil if was not setup, is not an aircraft or is not alive.
function RADIOQUEUE:_GetRadioSender()
-- Check if we have a sending aircraft.
local sender=nil --Wrapper.Unit#UNIT
-- Try the general default.
if self.sendername then
-- First try to find a unit
sender=UNIT:FindByName(self.sendername)
-- Check that sender is alive and an aircraft.
if sender and sender:IsAlive() and sender:IsAir() then
return sender
end
end
return nil
end
--- Get unit from which we want to transmit a radio message. This has to be an aircraft for subtitles to work.
-- @param #RADIOQUEUE self
-- @return Core.Point#COORDINATE Coordinate of the sender unit.
function RADIOQUEUE:_GetRadioSenderCoord()
local vec3=nil
-- Try the general default.
if self.sendername then
-- First try to find a unit
local sender=UNIT:FindByName(self.sendername)
-- Check that sender is alive and an aircraft.
if sender and sender:IsAlive() then
return sender:GetCoordinate()
end
-- Now try a static.
local sender=STATIC:FindByName(self.sendername)
-- Check that sender is alive and an aircraft.
if sender then
return sender:GetCoordinate()
end
end
return nil
end
@@ -52,8 +52,8 @@ end
-- Nothing of this code should be modified without testing it thoroughly. -- Nothing of this code should be modified without testing it thoroughly.
-- @param #SCHEDULEDISPATCHER self -- @param #SCHEDULEDISPATCHER self
-- @param Core.Scheduler#SCHEDULER Scheduler -- @param Core.Scheduler#SCHEDULER Scheduler
function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop ) function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop, TraceLevel, Fsm )
self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } ) self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop, TraceLevel } )
self.CallID = self.CallID + 1 self.CallID = self.CallID + 1
local CallID = self.CallID .. "#" .. ( Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "" ) or "" local CallID = self.CallID .. "#" .. ( Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "" ) or ""
@@ -84,11 +84,52 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
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
-- This section handles the tracing of the scheduled calls.
-- Because these calls will be executed with a delay, we inspect the place where these scheduled calls are initiated.
-- The Info structure contains the output of the debug.getinfo() calls, which inspects the call stack for the function name, line number and source name.
-- The call stack has many levels, and the correct semantical function call depends on where in the code AddSchedule was "used".
-- - Using SCHEDULER:New()
-- - Using Schedule:AddSchedule()
-- - Using Fsm:__Func()
-- - Using Class:ScheduleOnce()
-- - Using Class:ScheduleRepeat()
-- - ...
-- So for each of these scheduled call variations, AddSchedule is the workhorse which will schedule the call.
-- But the correct level with the correct semantical function location will differ depending on the above scheduled call invocation forms.
-- That's where the field TraceLevel contains optionally the level in the call stack where the call information is obtained.
-- The TraceLevel field indicates the correct level where the semantical scheduled call was invoked within the source, ensuring that function name, line number and source name are correct.
-- There is one quick ...
-- The FSM class models scheduled calls using the __Func syntax. However, these functions are "tailed".
-- There aren't defined anywhere within the source code, but rather implemented as triggers within the FSM logic,
-- and using the onbefore, onafter, onenter, onleave prefixes. (See the FSM for details).
-- Therefore, in the call stack, at the TraceLevel these functions are mentioned as "tail calls", and the Info.name field will be nil as a result.
-- To obtain the correct function name for FSM object calls, the function is mentioned in the call stack at a higher stack level.
-- So when function name stored in Info.name is nil, then I inspect the function name within the call stack one level higher.
-- So this little piece of code does its magic wonderfully, preformance overhead is neglectible, as scheduled calls don't happen that often.
local Info = {}
if debug then
TraceLevel = TraceLevel or 2
Info = debug.getinfo( TraceLevel, "nlS" )
local name_fsm = debug.getinfo( TraceLevel - 1, "n" ).name -- #string
if name_fsm then
Info.name = name_fsm
end
--env.info( debug.traceback() )
end
self:T3( self.Schedule[Scheduler][CallID] ) self:T3( self.Schedule[Scheduler][CallID] )
self.Schedule[Scheduler][CallID].CallHandler = function( CallID ) self.Schedule[Scheduler][CallID].CallHandler = function( Params )
--self:E( CallID )
local CallID = Params.CallID
local Info = Params.Info
local Source = Info.source or "?"
local Line = Info.currentline or "?"
local Name = Info.name or "?"
local ErrorHandler = function( errmsg ) local ErrorHandler = function( errmsg )
env.info( "Error in timer function: " .. errmsg ) env.info( "Error in timer function: " .. errmsg )
@@ -122,15 +163,19 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
local Stop = Schedule.Stop or 0 local Stop = Schedule.Stop or 0
local ScheduleID = Schedule.ScheduleID local ScheduleID = Schedule.ScheduleID
local Prefix = ( Repeat == 0 ) and "--->" or "+++>"
local Status, Result local Status, Result
--self:E( { SchedulerObject = SchedulerObject } ) --self:E( { SchedulerObject = SchedulerObject } )
if SchedulerObject then if SchedulerObject then
local function Timer() local function Timer()
SchedulerObject:T( Prefix .. Name .. ":" .. Line .. " (" .. Source .. ")" )
return ScheduleFunction( SchedulerObject, unpack( ScheduleArguments ) ) return ScheduleFunction( SchedulerObject, unpack( ScheduleArguments ) )
end end
Status, Result = xpcall( Timer, ErrorHandler ) Status, Result = xpcall( Timer, ErrorHandler )
else else
local function Timer() local function Timer()
self:T( Prefix .. Name .. ":" .. Line .. " (" .. Source .. ")" )
return ScheduleFunction( unpack( ScheduleArguments ) ) return ScheduleFunction( unpack( ScheduleArguments ) )
end end
Status, Result = xpcall( Timer, ErrorHandler ) Status, Result = xpcall( Timer, ErrorHandler )
@@ -161,13 +206,13 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
self:Stop( Scheduler, CallID ) self:Stop( Scheduler, CallID )
end end
else else
self:E( "Scheduled obsolete call for CallID: " .. CallID ) self:I( "<<<>" .. Name .. ":" .. Line .. " (" .. Source .. ")" )
end end
return nil return nil
end end
self:Start( Scheduler, CallID ) self:Start( Scheduler, CallID, Info )
return CallID return CallID
end end
@@ -181,7 +226,7 @@ function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID )
end end
end end
function SCHEDULEDISPATCHER:Start( Scheduler, CallID ) function SCHEDULEDISPATCHER:Start( Scheduler, CallID, Info )
self:F2( { Start = CallID, Scheduler = Scheduler } ) self:F2( { Start = CallID, Scheduler = Scheduler } )
if CallID then if CallID then
@@ -192,13 +237,13 @@ function SCHEDULEDISPATCHER:Start( Scheduler, CallID )
Schedule[CallID].StartTime = timer.getTime() -- Set the StartTime field to indicate when the scheduler started. Schedule[CallID].StartTime = timer.getTime() -- Set the StartTime field to indicate when the scheduler started.
Schedule[CallID].ScheduleID = timer.scheduleFunction( Schedule[CallID].ScheduleID = timer.scheduleFunction(
Schedule[CallID].CallHandler, Schedule[CallID].CallHandler,
CallID, { CallID = CallID, Info = Info },
timer.getTime() + Schedule[CallID].Start timer.getTime() + Schedule[CallID].Start
) )
end end
else else
for CallID, Schedule in pairs( self.Schedule[Scheduler] or {} ) do for CallID, Schedule in pairs( self.Schedule[Scheduler] or {} ) do
self:Start( Scheduler, CallID ) -- Recursive self:Start( Scheduler, CallID, Info ) -- Recursive
end end
end end
end end
+5 -3
View File
@@ -216,7 +216,7 @@ function SCHEDULER:New( SchedulerObject, SchedulerFunction, SchedulerArguments,
self.MasterObject = SchedulerObject self.MasterObject = SchedulerObject
if SchedulerFunction then if SchedulerFunction then
ScheduleID = self:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop ) ScheduleID = self:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop, 4 )
end end
return self, ScheduleID return self, ScheduleID
@@ -238,7 +238,7 @@ end
-- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat. -- @param #number RandomizeFactor Specifies a randomization factor between 0 and 1 to randomize the Repeat.
-- @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.
-- @return #number The ScheduleID of the planned schedule. -- @return #number The ScheduleID of the planned schedule.
function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop ) function SCHEDULER:Schedule( SchedulerObject, 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 } )
@@ -256,7 +256,9 @@ function SCHEDULER:Schedule( SchedulerObject, SchedulerFunction, SchedulerArgume
Start, Start,
Repeat, Repeat,
RandomizeFactor, RandomizeFactor,
Stop Stop,
TraceLevel or 3,
Fsm
) )
self.Schedules[#self.Schedules+1] = ScheduleID self.Schedules[#self.Schedules+1] = ScheduleID
+321 -2
View File
@@ -384,7 +384,6 @@ do -- SET_BASE
for ObjectName, Object in pairs( self.Database ) do for ObjectName, Object in pairs( self.Database ) do
if self:IsIncludeObject( Object ) then if self:IsIncludeObject( Object ) then
self:E( { "Adding Object:", ObjectName } )
self:Add( ObjectName, Object ) self:Add( ObjectName, Object )
end end
end end
@@ -5497,4 +5496,324 @@ do -- SET_ZONE
return nil return nil
end end
end end
do -- SET_ZONE_GOAL
--- @type SET_ZONE_GOAL
-- @extends Core.Set#SET_BASE
--- Mission designers can use the @{Core.Set#SET_ZONE_GOAL} class to build sets of zones of various types.
--
-- ## SET_ZONE_GOAL constructor
--
-- Create a new SET_ZONE_GOAL object with the @{#SET_ZONE_GOAL.New} method:
--
-- * @{#SET_ZONE_GOAL.New}: Creates a new SET_ZONE_GOAL object.
--
-- ## Add or Remove ZONEs from SET_ZONE_GOAL
--
-- ZONEs can be added and removed using the @{Core.Set#SET_ZONE_GOAL.AddZonesByName} and @{Core.Set#SET_ZONE_GOAL.RemoveZonesByName} respectively.
-- These methods take a single ZONE name or an array of ZONE names to be added or removed from SET_ZONE_GOAL.
--
-- ## SET_ZONE_GOAL filter criteria
--
-- You can set filter criteria to build the collection of zones in SET_ZONE_GOAL.
-- Filter criteria are defined by:
--
-- * @{#SET_ZONE_GOAL.FilterPrefixes}: Builds the SET_ZONE_GOAL with the zones having a certain text pattern of prefix.
--
-- Once the filter criteria have been set for the SET_ZONE_GOAL, you can start filtering using:
--
-- * @{#SET_ZONE_GOAL.FilterStart}: Starts the filtering of the zones within the SET_ZONE_GOAL.
--
-- ## SET_ZONE_GOAL iterators
--
-- Once the filters have been defined and the SET_ZONE_GOAL has been built, you can iterate the SET_ZONE_GOAL with the available iterator methods.
-- The iterator methods will walk the SET_ZONE_GOAL set, and call for each airbase within the set a function that you provide.
-- The following iterator methods are currently available within the SET_ZONE_GOAL:
--
-- * @{#SET_ZONE_GOAL.ForEachZone}: Calls a function for each zone it finds within the SET_ZONE_GOAL.
--
-- ===
-- @field #SET_ZONE_GOAL SET_ZONE_GOAL
SET_ZONE_GOAL = {
ClassName = "SET_ZONE_GOAL",
Zones = {},
Filter = {
Prefixes = nil,
},
FilterMeta = {
},
}
--- Creates a new SET_ZONE_GOAL object, building a set of zones.
-- @param #SET_ZONE_GOAL self
-- @return #SET_ZONE_GOAL self
-- @usage
-- -- Define a new SET_ZONE_GOAL Object. The DatabaseSet will contain a reference to all Zones.
-- DatabaseSet = SET_ZONE_GOAL:New()
function SET_ZONE_GOAL:New()
-- Inherits from BASE
local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.ZONES_GOAL ) )
return self
end
--- Add ZONEs to SET_ZONE_GOAL.
-- @param Core.Set#SET_ZONE_GOAL self
-- @param Core.Zone#ZONE_BASE Zone A ZONE_BASE object.
-- @return self
function SET_ZONE_GOAL:AddZone( Zone )
self:Add( Zone:GetName(), Zone )
return self
end
--- Remove ZONEs from SET_ZONE_GOAL.
-- @param Core.Set#SET_ZONE_GOAL self
-- @param Core.Zone#ZONE_BASE RemoveZoneNames A single name or an array of ZONE_BASE names.
-- @return self
function SET_ZONE_GOAL:RemoveZonesByName( RemoveZoneNames )
local RemoveZoneNamesArray = ( type( RemoveZoneNames ) == "table" ) and RemoveZoneNames or { RemoveZoneNames }
for RemoveZoneID, RemoveZoneName in pairs( RemoveZoneNamesArray ) do
self:Remove( RemoveZoneName )
end
return self
end
--- Finds a Zone based on the Zone Name.
-- @param #SET_ZONE_GOAL self
-- @param #string ZoneName
-- @return Core.Zone#ZONE_BASE The found Zone.
function SET_ZONE_GOAL:FindZone( ZoneName )
local ZoneFound = self.Set[ZoneName]
return ZoneFound
end
--- Get a random zone from the set.
-- @param #SET_ZONE_GOAL self
-- @return Core.Zone#ZONE_BASE The random Zone.
-- @return #nil if no zone in the collection.
function SET_ZONE_GOAL:GetRandomZone()
if self:Count() ~= 0 then
local Index = self.Index
local ZoneFound = nil -- Core.Zone#ZONE_BASE
-- Loop until a zone has been found.
-- The :GetZoneMaybe() call will evaluate the probability for the zone to be selected.
-- If the zone is not selected, then nil is returned by :GetZoneMaybe() and the loop continues!
while not ZoneFound do
local ZoneRandom = math.random( 1, #Index )
ZoneFound = self.Set[Index[ZoneRandom]]:GetZoneMaybe()
end
return ZoneFound
end
return nil
end
--- Set a zone probability.
-- @param #SET_ZONE_GOAL self
-- @param #string ZoneName The name of the zone.
function SET_ZONE_GOAL:SetZoneProbability( ZoneName, ZoneProbability )
local Zone = self:FindZone( ZoneName )
Zone:SetZoneProbability( ZoneProbability )
end
--- Builds a set of zones of defined zone prefixes.
-- All the zones starting with the given prefixes will be included within the set.
-- @param #SET_ZONE_GOAL self
-- @param #string Prefixes The prefix of which the zone name starts with.
-- @return #SET_ZONE_GOAL self
function SET_ZONE_GOAL:FilterPrefixes( Prefixes )
if not self.Filter.Prefixes then
self.Filter.Prefixes = {}
end
if type( Prefixes ) ~= "table" then
Prefixes = { Prefixes }
end
for PrefixID, Prefix in pairs( Prefixes ) do
self.Filter.Prefixes[Prefix] = Prefix
end
return self
end
--- Starts the filtering.
-- @param #SET_ZONE_GOAL self
-- @return #SET_ZONE_GOAL self
function SET_ZONE_GOAL:FilterStart()
if _DATABASE then
-- We initialize the first set.
for ObjectName, Object in pairs( self.Database ) do
if self:IsIncludeObject( Object ) then
self:Add( ObjectName, Object )
else
self:RemoveZonesByName( ObjectName )
end
end
end
self:HandleEvent( EVENTS.NewZoneGoal )
self:HandleEvent( EVENTS.DeleteZoneGoal )
return self
end
--- Stops the filtering for the defined collection.
-- @param #SET_ZONE_GOAL self
-- @return #SET_ZONE_GOAL self
function SET_ZONE_GOAL:FilterStop()
self:UnHandleEvent( EVENTS.NewZoneGoal )
self:UnHandleEvent( EVENTS.DeleteZoneGoal )
return self
end
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
-- @param #SET_ZONE_GOAL self
-- @param Core.Event#EVENTDATA Event
-- @return #string The name of the AIRBASE
-- @return #table The AIRBASE
function SET_ZONE_GOAL:AddInDatabase( Event )
self:F3( { Event } )
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
end
--- Handles the Database to check on any event that Object exists in the Database.
-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa!
-- @param #SET_ZONE_GOAL self
-- @param Core.Event#EVENTDATA Event
-- @return #string The name of the AIRBASE
-- @return #table The AIRBASE
function SET_ZONE_GOAL:FindInDatabase( Event )
self:F3( { Event } )
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
end
--- Iterate the SET_ZONE_GOAL and call an interator function for each ZONE, providing the ZONE and optional parameters.
-- @param #SET_ZONE_GOAL self
-- @param #function IteratorFunction The function that will be called when there is an alive ZONE in the SET_ZONE_GOAL. The function needs to accept a AIRBASE parameter.
-- @return #SET_ZONE_GOAL self
function SET_ZONE_GOAL:ForEachZone( IteratorFunction, ... )
self:F2( arg )
self:ForEach( IteratorFunction, arg, self:GetSet() )
return self
end
---
-- @param #SET_ZONE_GOAL self
-- @param Core.Zone#ZONE_BASE MZone
-- @return #SET_ZONE_GOAL self
function SET_ZONE_GOAL:IsIncludeObject( MZone )
self:F2( MZone )
local MZoneInclude = true
if MZone then
local MZoneName = MZone:GetName()
if self.Filter.Prefixes then
local MZonePrefix = false
for ZonePrefixId, ZonePrefix in pairs( self.Filter.Prefixes ) do
self:T3( { "Prefix:", string.find( MZoneName, ZonePrefix, 1 ), ZonePrefix } )
if string.find( MZoneName, ZonePrefix, 1 ) then
MZonePrefix = true
end
end
self:T( { "Evaluated Prefix", MZonePrefix } )
MZoneInclude = MZoneInclude and MZonePrefix
end
end
self:T2( MZoneInclude )
return MZoneInclude
end
--- Handles the OnEventNewZone event for the Set.
-- @param #SET_ZONE_GOAL self
-- @param Core.Event#EVENTDATA EventData
function SET_ZONE_GOAL:OnEventNewZoneGoal( EventData )
self:I( { "New Zone Capture Coalition", EventData } )
self:I( { "Zone Capture Coalition", EventData.ZoneGoal } )
if EventData.ZoneGoal then
if EventData.ZoneGoal and self:IsIncludeObject( EventData.ZoneGoal ) then
self:I( { "Adding Zone Capture Coalition", EventData.ZoneGoal.ZoneName, EventData.ZoneGoal } )
self:Add( EventData.ZoneGoal.ZoneName , EventData.ZoneGoal )
end
end
end
--- Handles the OnDead or OnCrash event for alive units set.
-- @param #SET_ZONE_GOAL self
-- @param Core.Event#EVENTDATA EventData
function SET_ZONE_GOAL:OnEventDeleteZoneGoal( EventData ) --R2.1
self:F3( { EventData } )
if EventData.ZoneGoal then
local Zone = _DATABASE:FindZone( EventData.ZoneGoal.ZoneName )
if Zone and Zone.ZoneName then
-- When cargo was deleted, it may probably be because of an S_EVENT_DEAD.
-- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call.
-- And this is a problem because it will remove all entries from the SET_ZONE_GOALs.
-- To prevent this from happening, the Zone object has a flag NoDestroy.
-- When true, the SET_ZONE_GOAL won't Remove the Zone object from the set.
-- This flag is switched off after the event handlers have been called in the EVENT class.
self:F( { ZoneNoDestroy=Zone.NoDestroy } )
if Zone.NoDestroy then
else
self:Remove( Zone.ZoneName )
end
end
end
end
--- Validate if a coordinate is in one of the zones in the set.
-- Returns the ZONE object where the coordiante is located.
-- If zones overlap, the first zone that validates the test is returned.
-- @param #SET_ZONE_GOAL self
-- @param Core.Point#COORDINATE Coordinate The coordinate to be searched.
-- @return Core.Zone#ZONE_BASE The zone that validates the coordinate location.
-- @return #nil No zone has been found.
function SET_ZONE_GOAL:IsCoordinateInZone( Coordinate )
for _, Zone in pairs( self:GetSet() ) do
local Zone = Zone -- Core.Zone#ZONE_BASE
if Zone:IsCoordinateInZone( Coordinate ) then
return Zone
end
end
return nil
end
end
+247 -181
View File
@@ -1,9 +1,9 @@
--- **Core** - Manages various settings for running missions, consumed by moose classes and provides a menu system for players to tweak settings in running missions. --- **Core** - Manages various settings for running missions, consumed by moose classes and provides a menu system for players to tweak settings in running missions.
-- --
-- === -- ===
-- --
-- ## Features: -- ## Features:
-- --
-- * Provide a settings menu system to the players. -- * Provide a settings menu system to the players.
-- * Provide a player settings menu and an overall mission settings menu. -- * Provide a player settings menu and an overall mission settings menu.
-- * Mission settings provide default settings, while player settings override mission settings. -- * Mission settings provide default settings, while player settings override mission settings.
@@ -11,19 +11,19 @@
-- * Provide a menu to select between different coordinate formats for A2A coordinates. -- * Provide a menu to select between different coordinate formats for A2A coordinates.
-- * Provide a menu to select between different message time duration options. -- * Provide a menu to select between different message time duration options.
-- * Provide a menu to select between different metric systems. -- * Provide a menu to select between different metric systems.
-- --
-- === -- ===
-- --
-- The documentation of the SETTINGS class can be found further in this document. -- The documentation of the SETTINGS class can be found further in this document.
-- --
-- === -- ===
-- --
-- # **AUTHORS and CONTRIBUTIONS** -- # **AUTHORS and CONTRIBUTIONS**
-- --
-- ### Contributions: -- ### Contributions:
-- --
-- ### Authors: -- ### Authors:
-- --
-- * **FlightControl**: Design & Programming -- * **FlightControl**: Design & Programming
-- --
-- @module Core.Settings -- @module Core.Settings
@@ -34,168 +34,181 @@
-- @extends Core.Base#BASE -- @extends Core.Base#BASE
--- Takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework. --- Takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
-- --
-- === -- ===
-- --
-- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework. -- The SETTINGS class takes care of various settings that influence the behaviour of certain functionalities and classes within the MOOSE framework.
-- SETTINGS can work on 2 levels: -- SETTINGS can work on 2 levels:
-- --
-- - **Default settings**: A running mission has **Default settings**. -- - **Default settings**: A running mission has **Default settings**.
-- - **Player settings**: For each player its own **Player settings** can be defined, overriding the **Default settings**. -- - **Player settings**: For each player its own **Player settings** can be defined, overriding the **Default settings**.
-- --
-- So, when there isn't any **Player setting** defined for a player for a specific setting, or, the player cannot be identified, the **Default setting** will be used instead. -- So, when there isn't any **Player setting** defined for a player for a specific setting, or, the player cannot be identified, the **Default setting** will be used instead.
-- --
-- # 1) \_SETTINGS object -- # 1) \_SETTINGS object
-- --
-- MOOSE defines by default a singleton object called **\_SETTINGS**. Use this object to modify all the **Default settings** for a running mission. -- MOOSE defines by default a singleton object called **\_SETTINGS**. Use this object to modify all the **Default settings** for a running mission.
-- For each player, MOOSE will automatically allocate also a **player settings** object, and will expose a radio menu to allow the player to adapt the settings to his own preferences. -- For each player, MOOSE will automatically allocate also a **player settings** object, and will expose a radio menu to allow the player to adapt the settings to his own preferences.
-- --
-- # 2) SETTINGS Menu -- # 2) SETTINGS Menu
-- --
-- Settings can be adapted by the Players and by the Mission Administrator through **radio menus, which are automatically available in the mission**. -- Settings can be adapted by the Players and by the Mission Administrator through **radio menus, which are automatically available in the mission**.
-- These menus can be found **on level F10 under "Settings"**. There are two kinds of menus generated by the system. -- These menus can be found **on level F10 under "Settings"**. There are two kinds of menus generated by the system.
-- --
-- ## 2.1) Default settings menu -- ## 2.1) Default settings menu
-- --
-- A menu is created automatically per Command Center that allows to modify the **Default** settings. -- A menu is created automatically per Command Center that allows to modify the **Default** settings.
-- So, when joining a CC unit, a menu will be available that allows to change the settings parameters **FOR ALL THE PLAYERS**! -- So, when joining a CC unit, a menu will be available that allows to change the settings parameters **FOR ALL THE PLAYERS**!
-- Note that the **Default settings** will only be used when a player has not choosen its own settings. -- Note that the **Default settings** will only be used when a player has not choosen its own settings.
-- --
-- ## 2.2) Player settings menu -- ## 2.2) Player settings menu
-- --
-- A menu is created automatically per Player Slot (group) that allows to modify the **Player** settings. -- A menu is created automatically per Player Slot (group) that allows to modify the **Player** settings.
-- So, when joining a slot, a menu wil be available that allows to change the settings parameters **FOR THE PLAYER ONLY**! -- So, when joining a slot, a menu wil be available that allows to change the settings parameters **FOR THE PLAYER ONLY**!
-- Note that when a player has not chosen a specific setting, the **Default settings** will be used. -- Note that when a player has not chosen a specific setting, the **Default settings** will be used.
-- --
-- ## 2.3) Show or Hide the Player Setting menus -- ## 2.3) Show or Hide the Player Setting menus
-- --
-- Of course, it may be requried not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**. -- Of course, it may be requried not to show any setting menus. In this case, a method is available on the **\_SETTINGS object**.
-- Use @{#SETTINGS.SetPlayerMenuOff}() to hide the player menus, and use @{#SETTINGS.SetPlayerMenuOn}() show the player menus. -- Use @{#SETTINGS.SetPlayerMenuOff}() to hide the player menus, and use @{#SETTINGS.SetPlayerMenuOn}() show the player menus.
-- Note that when this method is used, any player already in a slot will not have its menus visibility changed. -- Note that when this method is used, any player already in a slot will not have its menus visibility changed.
-- The option will only have effect when a player enters a new slot or changes a slot. -- The option will only have effect when a player enters a new slot or changes a slot.
-- --
-- Example: -- Example:
-- --
-- _SETTINGS:SetPlayerMenuOff() -- will disable the player menus. -- _SETTINGS:SetPlayerMenuOff() -- will disable the player menus.
-- _SETTINGS:SetPlayerMenuOn() -- will enable the player menus. -- _SETTINGS:SetPlayerMenuOn() -- will enable the player menus.
-- -- But only when a player exits and reenters the slot these settings will have effect! -- -- But only when a player exits and reenters the slot these settings will have effect!
-- --
-- --
-- # 3) Settings -- # 3) Settings
-- --
-- There are different settings that are managed and applied within the MOOSE framework. -- There are different settings that are managed and applied within the MOOSE framework.
-- See below a comprehensive description of each. -- See below a comprehensive description of each.
-- --
-- ## 3.1) **A2G coordinates** display formatting -- ## 3.1) **A2G coordinates** display formatting
-- --
-- ### 3.1.1) A2G coordinates setting **types** -- ### 3.1.1) A2G coordinates setting **types**
-- --
-- Will customize which display format is used to indicate A2G coordinates in text as part of the Command Center communications. -- Will customize which display format is used to indicate A2G coordinates in text as part of the Command Center communications.
-- --
-- - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_(navigation)). -- - A2G BR: [Bearing Range](https://en.wikipedia.org/wiki/Bearing_(navigation)).
-- - A2G MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted. -- - A2G MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
-- - A2G LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted. -- - A2G LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
-- - A2G LL DDM: Lattitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted. -- - A2G LL DDM: Lattitude Longitude [Decimal Degrees Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
-- --
-- ### 3.1.2) A2G coordinates setting **menu** -- ### 3.1.2) A2G coordinates setting **menu**
-- --
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
-- --
-- ### 3.1.3) A2G coordinates setting **methods** -- ### 3.1.3) A2G coordinates setting **methods**
-- --
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object. -- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
-- --
-- - @{#SETTINGS.SetA2G_BR}(): Enable the BR display formatting by default. -- - @{#SETTINGS.SetA2G_BR}(): Enable the BR display formatting by default.
-- - @{#SETTINGS.SetA2G_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting. -- - @{#SETTINGS.SetA2G_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
-- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting. -- - @{#SETTINGS.SetA2G_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
-- - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting. -- - @{#SETTINGS.SetA2G_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
-- --
-- ### 3.1.4) A2G coordinates setting - additional notes -- ### 3.1.4) A2G coordinates setting - additional notes
-- --
-- One additional note on BR. In a situation when a BR coordinate should be given, -- One additional note on BR. In a situation when a BR coordinate should be given,
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied! -- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
-- --
-- ## 3.2) **A2A coordinates** formatting -- ## 3.2) **A2A coordinates** formatting
-- --
-- ### 3.2.1) A2A coordinates setting **types** -- ### 3.2.1) A2A coordinates setting **types**
-- --
-- Will customize which display format is used to indicate A2A coordinates in text as part of the Command Center communications. -- Will customize which display format is used to indicate A2A coordinates in text as part of the Command Center communications.
-- --
-- - A2A BRAA: [Bearing Range Altitude Aspect](https://en.wikipedia.org/wiki/Bearing_(navigation)). -- - A2A BRAA: [Bearing Range Altitude Aspect](https://en.wikipedia.org/wiki/Bearing_(navigation)).
-- - A2A MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted. -- - A2A MGRS: The [Military Grid Reference System](https://en.wikipedia.org/wiki/Military_Grid_Reference_System). The accuracy can also be adapted.
-- - A2A LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted. -- - A2A LL DMS: Lattitude Longitude [Degrees Minutes Seconds](https://en.wikipedia.org/wiki/Geographic_coordinate_conversion). The accuracy can also be adapted.
-- - A2A LL DDM: Lattitude Longitude [Decimal Degrees and Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted. -- - A2A LL DDM: Lattitude Longitude [Decimal Degrees and Minutes](https://en.wikipedia.org/wiki/Decimal_degrees). The accuracy can also be adapted.
-- - A2A BULLS: [Bullseye](http://falcon4.wikidot.com/concepts:bullseye). -- - A2A BULLS: [Bullseye](http://falcon4.wikidot.com/concepts:bullseye).
-- --
-- ### 3.2.2) A2A coordinates setting **menu** -- ### 3.2.2) A2A coordinates setting **menu**
-- --
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
-- --
-- ### 3.2.3) A2A coordinates setting **methods** -- ### 3.2.3) A2A coordinates setting **methods**
-- --
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object. -- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
-- --
-- - @{#SETTINGS.SetA2A_BRAA}(): Enable the BR display formatting by default. -- - @{#SETTINGS.SetA2A_BRAA}(): Enable the BR display formatting by default.
-- - @{#SETTINGS.SetA2A_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting. -- - @{#SETTINGS.SetA2A_MGRS}(): Enable the MGRS display formatting by default. Use @{SETTINGS.SetMGRS_Accuracy}() to adapt the accuracy of the MGRS formatting.
-- - @{#SETTINGS.SetA2A_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting. -- - @{#SETTINGS.SetA2A_LL_DMS}(): Enable the LL DMS display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
-- - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting. -- - @{#SETTINGS.SetA2A_LL_DDM}(): Enable the LL DDM display formatting by default. Use @{SETTINGS.SetLL_Accuracy}() to adapt the accuracy of the Seconds formatting.
-- - @{#SETTINGS.SetA2A_BULLS}(): Enable the BULLSeye display formatting by default. -- - @{#SETTINGS.SetA2A_BULLS}(): Enable the BULLSeye display formatting by default.
-- --
-- ### 3.2.4) A2A coordinates settings - additional notes -- ### 3.2.4) A2A coordinates settings - additional notes
-- --
-- One additional note on BRAA. In a situation when a BRAA coordinate should be given, -- One additional note on BRAA. In a situation when a BRAA coordinate should be given,
-- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied! -- but there isn't any player context (no player unit to reference from), the MGRS formatting will be applied!
-- --
-- ## 3.3) **Measurements** formatting -- ## 3.3) **Measurements** formatting
-- --
-- ### 3.3.1) Measurements setting **types** -- ### 3.3.1) Measurements setting **types**
-- --
-- Will customize the measurements system being used as part as part of the Command Center communications. -- Will customize the measurements system being used as part as part of the Command Center communications.
-- --
-- - **Metrics** system: Applies the [Metrics system](https://en.wikipedia.org/wiki/Metric_system) ... -- - **Metrics** system: Applies the [Metrics system](https://en.wikipedia.org/wiki/Metric_system) ...
-- - **Imperial** system: Applies the [Imperial system](https://en.wikipedia.org/wiki/Imperial_units) ... -- - **Imperial** system: Applies the [Imperial system](https://en.wikipedia.org/wiki/Imperial_units) ...
-- --
-- ### 3.3.2) Measurements setting **menu** -- ### 3.3.2) Measurements setting **menu**
-- --
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
-- --
-- ### 3.3.3) Measurements setting **methods** -- ### 3.3.3) Measurements setting **methods**
-- --
-- There are different methods that can be used to change the **Default settings** using the \_SETTINGS object. -- There are different methods that can be used to change the **Default settings** using the \_SETTINGS object.
-- --
-- - @{#SETTINGS.SetMetric}(): Enable the Metric system. -- - @{#SETTINGS.SetMetric}(): Enable the Metric system.
-- - @{#SETTINGS.SetImperial}(): Enable the Imperial system. -- - @{#SETTINGS.SetImperial}(): Enable the Imperial system.
-- --
-- ## 3.4) **Message** display times -- ## 3.4) **Message** display times
-- --
-- ### 3.4.1) Message setting **types** -- ### 3.4.1) Message setting **types**
-- --
-- There are various **Message Types** that will influence the duration how long a message will appear as part of the Command Center communications. -- There are various **Message Types** that will influence the duration how long a message will appear as part of the Command Center communications.
-- --
-- - **Update** message: A short update message. -- - **Update** message: A short update message.
-- - **Information** message: Provides new information **while** executing a mission. -- - **Information** message: Provides new information **while** executing a mission.
-- - **Briefing** message: Provides a complete briefing **before** executing a mission. -- - **Briefing** message: Provides a complete briefing **before** executing a mission.
-- - **Overview report**: Provides a short report overview, the summary of the report. -- - **Overview report**: Provides a short report overview, the summary of the report.
-- - **Detailed report**: Provides a complete report. -- - **Detailed report**: Provides a complete report.
-- --
-- ### 3.4.2) Message setting **menu** -- ### 3.4.2) Message setting **menu**
-- --
-- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot. -- The settings can be changed by using the **Default settings menu** on the Command Center or the **Player settings menu** on the Player Slot.
-- --
-- Each Message Type has specific timings that will be applied when the message is displayed. -- Each Message Type has specific timings that will be applied when the message is displayed.
-- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be choosen. -- The Settings Menu will provide for each Message Type a selection of proposed durations from which can be choosen.
-- So the player can choose its own amount of seconds how long a message should be displayed of a certain type. -- So the player can choose its own amount of seconds how long a message should be displayed of a certain type.
-- Note that **Update** messages can be chosen not to be displayed at all! -- Note that **Update** messages can be chosen not to be displayed at all!
-- --
-- ### 3.4.3) Message setting **methods** -- ### 3.4.3) Message setting **methods**
-- --
-- There are different methods that can be used to change the **System settings** using the \_SETTINGS object. -- There are different methods that can be used to change the **System settings** using the \_SETTINGS object.
-- --
-- - @{#SETTINGS.SetMessageTime}(): Define for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds. -- - @{#SETTINGS.SetMessageTime}(): Define for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
-- - @{#SETTINGS.GetMessageTime}(): Retrieves for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds. -- - @{#SETTINGS.GetMessageTime}(): Retrieves for a specific @{Message.MESSAGE.MessageType} the duration to be displayed in seconds.
-- --
-- ## 3.5) **Era** of the battle
--
-- The threat level metric is scaled according the era of the battle. A target that is AAA, will pose a much greather threat in WWII than on modern warfare.
-- Therefore, there are 4 era that are defined within the settings:
--
-- - **WWII** era: Use for warfare with equipment during the world war II time.
-- - **Korea** era: Use for warfare with equipment during the Korea war time.
-- - **Cold War** era: Use for warfare with equipment during the cold war time.
-- - **Modern** era: Use for warfare with modern equipment in the 2000s.
--
-- There are different API defined that you can use with the _SETTINGS object to configure your mission script to work in one of the 4 era:
-- @{#SETTINGS.SetEraWWII}(), @{#SETTINGS.SetEraKorea}(), @{#SETTINGS.SetEraCold}(), @{#SETTINGS.SetEraModern}()
--
-- === -- ===
-- --
-- @field #SETTINGS -- @field #SETTINGS
SETTINGS = { SETTINGS = {
ClassName = "SETTINGS", ClassName = "SETTINGS",
@@ -204,6 +217,19 @@ SETTINGS = {
MenuStatic = true, MenuStatic = true,
} }
SETTINGS.__Enum = {}
--- @type SETTINGS.__Enum.Era
-- @field #number WWII
-- @field #number Korea
-- @field #number Cold
-- @field #number Modern
SETTINGS.__Enum.Era = {
WWII = 1,
Korea = 2,
Cold = 3,
Modern = 4,
}
do -- SETTINGS do -- SETTINGS
@@ -211,7 +237,7 @@ do -- SETTINGS
--- SETTINGS constructor. --- SETTINGS constructor.
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #SETTINGS -- @return #SETTINGS
function SETTINGS:Set( PlayerName ) function SETTINGS:Set( PlayerName )
if PlayerName == nil then if PlayerName == nil then
local self = BASE:Inherit( self, BASE:New() ) -- #SETTINGS local self = BASE:Inherit( self, BASE:New() ) -- #SETTINGS
@@ -225,6 +251,7 @@ do -- SETTINGS
self:SetMessageTime( MESSAGE.Type.Information, 30 ) self:SetMessageTime( MESSAGE.Type.Information, 30 )
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:SetMenutextShort(true) self:SetMenutextShort(true)
self:SetMenuStatic(true) self:SetMenuStatic(true)
return self return self
@@ -245,20 +272,20 @@ do -- SETTINGS
function SETTINGS:SetMenutextShort(onoff) function SETTINGS:SetMenutextShort(onoff)
self.MenuShort = onoff self.MenuShort = onoff
end end
--- Set menu to be static. --- Set menu to be static.
-- @param #SETTINGS self -- @param #SETTINGS self
-- @param #boolean onoff If *true* menu is static. If *false* menu will be updated after changes (default). -- @param #boolean onoff If *true* menu is static. If *false* menu will be updated after changes (default).
function SETTINGS:SetMenuStatic(onoff) function SETTINGS:SetMenuStatic(onoff)
self.MenuStatic = onoff self.MenuStatic = onoff
end end
--- Sets the SETTINGS metric. --- Sets the SETTINGS metric.
-- @param #SETTINGS self -- @param #SETTINGS self
function SETTINGS:SetMetric() function SETTINGS:SetMetric()
self.Metric = true self.Metric = true
end 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.
@@ -271,7 +298,7 @@ do -- SETTINGS
function SETTINGS:SetImperial() function SETTINGS:SetImperial()
self.Metric = false self.Metric = false
end end
--- Gets if the SETTINGS is imperial. --- Gets if the SETTINGS is imperial.
-- @param #SETTINGS self -- @param #SETTINGS self
-- @return #boolean true if imperial. -- @return #boolean true if imperial.
@@ -308,7 +335,7 @@ do -- SETTINGS
function SETTINGS:GetMGRS_Accuracy() function SETTINGS:GetMGRS_Accuracy()
return self.MGRS_Accuracy or _SETTINGS:GetMGRS_Accuracy() return self.MGRS_Accuracy or _SETTINGS:GetMGRS_Accuracy()
end end
--- Sets the SETTINGS Message Display Timing of a MessageType --- Sets the SETTINGS Message Display Timing of a MessageType
-- @param #SETTINGS self -- @param #SETTINGS self
-- @param Core.Message#MESSAGE MessageType The type of the message. -- @param Core.Message#MESSAGE MessageType The type of the message.
@@ -317,8 +344,8 @@ do -- SETTINGS
self.MessageTypeTimings = self.MessageTypeTimings or {} self.MessageTypeTimings = self.MessageTypeTimings or {}
self.MessageTypeTimings[MessageType] = MessageTime self.MessageTypeTimings[MessageType] = MessageTime
end end
--- Gets the SETTINGS Message Display Timing of a MessageType --- Gets the SETTINGS Message Display Timing of a MessageType
-- @param #SETTINGS self -- @param #SETTINGS self
-- @param Core.Message#MESSAGE MessageType The type of the message. -- @param Core.Message#MESSAGE MessageType The type of the message.
@@ -460,9 +487,9 @@ do -- SETTINGS
function SETTINGS:SetSystemMenu( MenuGroup, RootMenu ) function SETTINGS:SetSystemMenu( MenuGroup, RootMenu )
local MenuText = "System Settings" local MenuText = "System Settings"
local MenuTime = timer.getTime() local MenuTime = timer.getTime()
local SettingsMenu = MENU_GROUP:New( MenuGroup, MenuText, RootMenu ):SetTime( MenuTime ) local SettingsMenu = MENU_GROUP:New( MenuGroup, MenuText, RootMenu ):SetTime( MenuTime )
------- -------
@@ -472,9 +499,9 @@ do -- SETTINGS
local text="A2G Coordinate System XXX" local text="A2G Coordinate System XXX"
if self.MenuShort then if self.MenuShort then
text="A2G Coordinates" text="A2G Coordinates"
end end
local A2GCoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime ) local A2GCoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
-- Set LL DMS -- Set LL DMS
if not self:IsA2G_LL_DMS() then if not self:IsA2G_LL_DMS() then
local text="Lat/Lon Degree Min Sec (LL DMS)" local text="Lat/Lon Degree Min Sec (LL DMS)"
@@ -483,16 +510,16 @@ do -- SETTINGS
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
end end
-- Set LL DDM -- Set LL DDM
if not self:IsA2G_LL_DDM() then if not self:IsA2G_LL_DDM() then
local text="Lat/Lon Degree Dec Min (LL DDM)" local text="Lat/Lon Degree Dec Min (LL DDM)"
if self.MenuShort then if self.MenuShort then
text="LL DDM" text="LL DDM"
end end
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
end end
-- Set LL DMS accuracy. -- Set LL DMS accuracy.
if self:IsA2G_LL_DDM() then if self:IsA2G_LL_DDM() then
local text1="LL DDM Accuracy 1" local text1="LL DDM Accuracy 1"
@@ -500,30 +527,30 @@ do -- SETTINGS
local text3="LL DDM Accuracy 3" local text3="LL DDM Accuracy 3"
if self.MenuShort then if self.MenuShort then
text1="LL DDM" text1="LL DDM"
end end
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
end end
-- Set BR. -- Set BR.
if not self:IsA2G_BR() then if not self:IsA2G_BR() then
local text="Bearing, Range (BR)" local text="Bearing, Range (BR)"
if self.MenuShort then if self.MenuShort then
text="BR" text="BR"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text , A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text , A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
end end
-- Set MGRS. -- Set MGRS.
if not self:IsA2G_MGRS() then if not self:IsA2G_MGRS() then
local text="Military Grid (MGRS)" local text="Military Grid (MGRS)"
if self.MenuShort then if self.MenuShort then
text="MGRS" text="MGRS"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
end end
-- Set MGRS accuracy. -- Set MGRS accuracy.
if self:IsA2G_MGRS() then if self:IsA2G_MGRS() then
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
@@ -532,22 +559,22 @@ do -- SETTINGS
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
end end
------- -------
-- A2A Coordinate System -- A2A Coordinate System
------- -------
local text="A2A Coordinate System" local text="A2A Coordinate System"
if self.MenuShort then if self.MenuShort then
text="A2A Coordinates" text="A2A Coordinates"
end end
local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime ) local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
if not self:IsA2A_LL_DMS() then if not self:IsA2A_LL_DMS() then
local text="Lat/Lon Degree Min Sec (LL DMS)" local text="Lat/Lon Degree Min Sec (LL DMS)"
if self.MenuShort then if self.MenuShort then
text="LL DMS" text="LL DMS"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
end end
@@ -555,7 +582,7 @@ do -- SETTINGS
local text="Lat/Lon Degree Dec Min (LL DDM)" local text="Lat/Lon Degree Dec Min (LL DDM)"
if self.MenuShort then if self.MenuShort then
text="LL DDM" text="LL DDM"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
end end
@@ -563,7 +590,7 @@ do -- SETTINGS
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 1", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 2", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 3", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "LL DDM Accuracy 3", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
end end
if not self:IsA2A_BULLS() then if not self:IsA2A_BULLS() then
local text="Bullseye (BULLS)" local text="Bullseye (BULLS)"
@@ -572,20 +599,20 @@ do -- SETTINGS
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime )
end end
if not self:IsA2A_BRAA() then if not self:IsA2A_BRAA() then
local text="Bearing Range Altitude Aspect (BRAA)" local text="Bearing Range Altitude Aspect (BRAA)"
if self.MenuShort then if self.MenuShort then
text="BRAA" text="BRAA"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime )
end end
if not self:IsA2A_MGRS() then if not self:IsA2A_MGRS() then
local text="Military Grid (MGRS)" local text="Military Grid (MGRS)"
if self.MenuShort then if self.MenuShort then
text="MGRS" text="MGRS"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
end end
@@ -596,33 +623,33 @@ do -- SETTINGS
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 4", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 4 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 5", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 5 ):SetTime( MenuTime )
end end
local text="Measures and Weights System" local text="Measures and Weights System"
if self.MenuShort then if self.MenuShort then
text="Unit System" text="Unit System"
end end
local MetricsMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime ) local MetricsMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
if self:IsMetric() then if self:IsMetric() then
local text="Imperial (Miles,Feet)" local text="Imperial (Miles,Feet)"
if self.MenuShort then if self.MenuShort then
text="Imperial" text="Imperial"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, false ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, false ):SetTime( MenuTime )
end end
if self:IsImperial() then if self:IsImperial() then
local text="Metric (Kilometers,Meters)" local text="Metric (Kilometers,Meters)"
if self.MenuShort then if self.MenuShort then
text="Metric" text="Metric"
end end
MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, text, MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime )
end end
local text="Messages and Reports" local text="Messages and Reports"
if self.MenuShort then if self.MenuShort then
text="Messages & Reports" text="Messages & Reports"
end end
local MessagesMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime ) local MessagesMenu = MENU_GROUP:New( MenuGroup, text, SettingsMenu ):SetTime( MenuTime )
local UpdateMessagesMenu = MENU_GROUP:New( MenuGroup, "Update Messages", MessagesMenu ):SetTime( MenuTime ) local UpdateMessagesMenu = MENU_GROUP:New( MenuGroup, "Update Messages", MessagesMenu ):SetTime( MenuTime )
@@ -661,10 +688,10 @@ do -- SETTINGS
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 60 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 60 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 120 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 120 ):SetTime( MenuTime )
MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 180 ):SetTime( MenuTime ) MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 180 ):SetTime( MenuTime )
SettingsMenu:Remove( MenuTime ) SettingsMenu:Remove( MenuTime )
return self return self
end end
@@ -697,24 +724,24 @@ do -- SETTINGS
function SETTINGS:SetPlayerMenu( PlayerUnit ) function SETTINGS:SetPlayerMenu( PlayerUnit )
if _SETTINGS.ShowPlayerMenu == true then if _SETTINGS.ShowPlayerMenu == true then
local PlayerGroup = PlayerUnit:GetGroup() local PlayerGroup = PlayerUnit:GetGroup()
local PlayerName = PlayerUnit:GetPlayerName() local PlayerName = PlayerUnit:GetPlayerName()
local PlayerNames = PlayerGroup:GetPlayerNames() local PlayerNames = PlayerGroup:GetPlayerNames()
local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' ) local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' )
self.PlayerMenu = PlayerMenu self.PlayerMenu = PlayerMenu
self:I(string.format("FF Setting menu for player %s", tostring(PlayerName))) self:I(string.format("FF Setting menu for player %s", tostring(PlayerName)))
local submenu = MENU_GROUP:New( PlayerGroup, "LL Accuracy", PlayerMenu ) local submenu = MENU_GROUP:New( PlayerGroup, "LL Accuracy", PlayerMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "0 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 ) MENU_GROUP_COMMAND:New( PlayerGroup, "0 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 ) MENU_GROUP_COMMAND:New( PlayerGroup, "1 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 ) MENU_GROUP_COMMAND:New( PlayerGroup, "2 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
MENU_GROUP_COMMAND:New( PlayerGroup, "3 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 ) MENU_GROUP_COMMAND:New( PlayerGroup, "3 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
MENU_GROUP_COMMAND:New( PlayerGroup, "4 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 ) MENU_GROUP_COMMAND:New( PlayerGroup, "4 Decimal Places", submenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
local submenu = MENU_GROUP:New( PlayerGroup, "MGRS Accuracy", PlayerMenu ) local submenu = MENU_GROUP:New( PlayerGroup, "MGRS Accuracy", PlayerMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 0", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 ) MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 0", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 0 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 1", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 ) MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 1", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
@@ -722,7 +749,7 @@ do -- SETTINGS
MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 3", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 ) MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 3", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 4", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 ) MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 4", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 5", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 ) MENU_GROUP_COMMAND:New( PlayerGroup, "Accuracy 5", submenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
------ ------
-- A2G Coordinate System -- A2G Coordinate System
------ ------
@@ -730,118 +757,118 @@ do -- SETTINGS
local text="A2G Coordinate System" local text="A2G Coordinate System"
if self.MenuShort then if self.MenuShort then
text="A2G Coordinates" text="A2G Coordinates"
end end
local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu ) local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
if not self:IsA2G_LL_DMS() or self.MenuStatic then if not self:IsA2G_LL_DMS() or self.MenuStatic then
local text="Lat/Lon Degree Min Sec (LL DMS)" local text="Lat/Lon Degree Min Sec (LL DMS)"
if self.MenuShort then if self.MenuShort then
text="LL DMS" text="LL DMS"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
end end
if not self:IsA2G_LL_DDM() or self.MenuStatic then if not self:IsA2G_LL_DDM() or self.MenuStatic then
local text="Lat/Lon Degree Dec Min (LL DDM)" local text="Lat/Lon Degree Dec Min (LL DDM)"
if self.MenuShort then if self.MenuShort then
text="LL DDM" text="LL DDM"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
end end
if not self:IsA2G_BR() or self.MenuStatic then if not self:IsA2G_BR() or self.MenuStatic then
local text="Bearing, Range (BR)" local text="Bearing, Range (BR)"
if self.MenuShort then if self.MenuShort then
text="BR" text="BR"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
end end
if not self:IsA2G_MGRS() or self.MenuStatic then if not self:IsA2G_MGRS() or self.MenuStatic then
local text="Military Grid (MGRS)" local text="Military Grid (MGRS)"
if self.MenuShort then if self.MenuShort then
text="MGRS" text="MGRS"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
end end
------ ------
-- A2A Coordinates Menu -- A2A Coordinates Menu
------ ------
local text="A2A Coordinate System" local text="A2A Coordinate System"
if self.MenuShort then if self.MenuShort then
text="A2A Coordinates" text="A2A Coordinates"
end end
local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu ) local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
if not self:IsA2A_LL_DMS() or self.MenuStatic then if not self:IsA2A_LL_DMS() or self.MenuStatic then
local text="Lat/Lon Degree Min Sec (LL DMS)" local text="Lat/Lon Degree Min Sec (LL DMS)"
if self.MenuShort then if self.MenuShort then
text="LL DMS" text="LL DMS"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
end end
if not self:IsA2A_LL_DDM() or self.MenuStatic then if not self:IsA2A_LL_DDM() or self.MenuStatic then
local text="Lat/Lon Degree Dec Min (LL DDM)" local text="Lat/Lon Degree Dec Min (LL DDM)"
if self.MenuShort then if self.MenuShort then
text="LL DDM" text="LL DDM"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
end end
if not self:IsA2A_BULLS() or self.MenuStatic then if not self:IsA2A_BULLS() or self.MenuStatic then
local text="Bullseye (BULLS)" local text="Bullseye (BULLS)"
if self.MenuShort then if self.MenuShort then
text="BULLS" text="BULLS"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
end end
if not self:IsA2A_BRAA() or self.MenuStatic then if not self:IsA2A_BRAA() or self.MenuStatic then
local text="Bearing Range Altitude Aspect (BRAA)" local text="Bearing Range Altitude Aspect (BRAA)"
if self.MenuShort then if self.MenuShort then
text="BRAA" text="BRAA"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
end end
if not self:IsA2A_MGRS() or self.MenuStatic then if not self:IsA2A_MGRS() or self.MenuStatic then
local text="Military Grid (MGRS)" local text="Military Grid (MGRS)"
if self.MenuShort then if self.MenuShort then
text="MGRS" text="MGRS"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" ) MENU_GROUP_COMMAND:New( PlayerGroup, text, A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
end end
--- ---
-- Unit system -- Unit system
--- ---
local text="Measures and Weights System" local text="Measures and Weights System"
if self.MenuShort then if self.MenuShort then
text="Unit System" text="Unit System"
end end
local MetricsMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu ) local MetricsMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
if self:IsMetric() or self.MenuStatic then if self:IsMetric() or self.MenuStatic then
local text="Imperial (Miles,Feet)" local text="Imperial (Miles,Feet)"
if self.MenuShort then if self.MenuShort then
text="Imperial" text="Imperial"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false ) MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
end end
if self:IsImperial() or self.MenuStatic then if self:IsImperial() or self.MenuStatic then
local text="Metric (Kilometers,Meters)" local text="Metric (Kilometers,Meters)"
if self.MenuShort then if self.MenuShort then
text="Metric" text="Metric"
end end
MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true ) MENU_GROUP_COMMAND:New( PlayerGroup, text, MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
end end
--- ---
-- Messages and Reports -- Messages and Reports
--- ---
@@ -849,9 +876,9 @@ do -- SETTINGS
local text="Messages and Reports" local text="Messages and Reports"
if self.MenuShort then if self.MenuShort then
text="Messages & Reports" text="Messages & Reports"
end end
local MessagesMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu ) local MessagesMenu = MENU_GROUP:New( PlayerGroup, text, PlayerMenu )
local UpdateMessagesMenu = MENU_GROUP:New( PlayerGroup, "Update Messages", MessagesMenu ) local UpdateMessagesMenu = MENU_GROUP:New( PlayerGroup, "Update Messages", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "Off", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 0 ) MENU_GROUP_COMMAND:New( PlayerGroup, "Off", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 0 )
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 5 ) MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 5 )
@@ -859,7 +886,7 @@ do -- SETTINGS
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 15 ) MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 30 ) MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 60 ) MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 60 )
local InformationMessagesMenu = MENU_GROUP:New( PlayerGroup, "Information Messages", MessagesMenu ) local InformationMessagesMenu = MENU_GROUP:New( PlayerGroup, "Information Messages", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 5 ) MENU_GROUP_COMMAND:New( PlayerGroup, "5 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 5 )
MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 10 ) MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 10 )
@@ -867,30 +894,30 @@ do -- SETTINGS
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 30 ) MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 60 ) MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 120 ) MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 120 )
local BriefingReportsMenu = MENU_GROUP:New( PlayerGroup, "Briefing Reports", MessagesMenu ) local BriefingReportsMenu = MENU_GROUP:New( PlayerGroup, "Briefing Reports", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 15 ) MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 30 ) MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 60 ) MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 120 ) MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 120 )
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 180 ) MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", BriefingReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Briefing, 180 )
local OverviewReportsMenu = MENU_GROUP:New( PlayerGroup, "Overview Reports", MessagesMenu ) local OverviewReportsMenu = MENU_GROUP:New( PlayerGroup, "Overview Reports", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 15 ) MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 30 ) MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 60 ) MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 120 ) MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 120 )
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 180 ) MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", OverviewReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Overview, 180 )
local DetailedReportsMenu = MENU_GROUP:New( PlayerGroup, "Detailed Reports", MessagesMenu ) local DetailedReportsMenu = MENU_GROUP:New( PlayerGroup, "Detailed Reports", MessagesMenu )
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 15 ) MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 15 )
MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 30 ) MENU_GROUP_COMMAND:New( PlayerGroup, "30 seconds", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 30 )
MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 60 ) MENU_GROUP_COMMAND:New( PlayerGroup, "1 minute", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 60 )
MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 120 ) MENU_GROUP_COMMAND:New( PlayerGroup, "2 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 120 )
MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 180 ) MENU_GROUP_COMMAND:New( PlayerGroup, "3 minutes", DetailedReportsMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.DetailedReportsMenu, 180 )
end end
return self return self
end end
@@ -904,7 +931,7 @@ do -- SETTINGS
self.PlayerMenu:Remove() self.PlayerMenu:Remove()
self.PlayerMenu = nil self.PlayerMenu = nil
end end
return self return self
end end
@@ -961,7 +988,7 @@ do -- SETTINGS
self:SetPlayerMenu(PlayerUnit) self:SetPlayerMenu(PlayerUnit)
end end
end end
--- @param #SETTINGS self --- @param #SETTINGS self
function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem ) function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
self.A2ASystem = A2ASystem self.A2ASystem = A2ASystem
@@ -971,7 +998,7 @@ do -- SETTINGS
self:SetPlayerMenu(PlayerUnit) self:SetPlayerMenu(PlayerUnit)
end end
end end
--- @param #SETTINGS self --- @param #SETTINGS self
function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy ) function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
self.LL_Accuracy = LL_Accuracy self.LL_Accuracy = LL_Accuracy
@@ -981,7 +1008,7 @@ do -- SETTINGS
self:SetPlayerMenu(PlayerUnit) self:SetPlayerMenu(PlayerUnit)
end end
end end
--- @param #SETTINGS self --- @param #SETTINGS self
function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy ) function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
self.MGRS_Accuracy = MGRS_Accuracy self.MGRS_Accuracy = MGRS_Accuracy
@@ -1007,9 +1034,48 @@ do -- SETTINGS
self:SetMessageTime( MessageType, MessageTime ) self:SetMessageTime( MessageType, MessageTime )
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToGroup( PlayerGroup ) MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToGroup( PlayerGroup )
end end
end end
--- Configures the era of the mission to be WWII.
-- @param #SETTINGS self
-- @return #SETTINGS self
function SETTINGS:SetEraWWII()
self.Era = SETTINGS.__Enum.Era.WWII
end
--- Configures the era of the mission to be Korea.
-- @param #SETTINGS self
-- @return #SETTINGS self
function SETTINGS:SetEraKorea()
self.Era = SETTINGS.__Enum.Era.Korea
end
--- Configures the era of the mission to be Cold war.
-- @param #SETTINGS self
-- @return #SETTINGS self
function SETTINGS:SetEraCold()
self.Era = SETTINGS.__Enum.Era.Cold
end
--- Configures the era of the mission to be Modern war.
-- @param #SETTINGS self
-- @return #SETTINGS self
function SETTINGS:SetEraModern()
self.Era = SETTINGS.__Enum.Era.Modern
end
end end
+2 -2
View File
@@ -120,7 +120,7 @@ ZONE_BASE = {
-- @param #string ZoneName Name of the zone. -- @param #string ZoneName Name of the zone.
-- @return #ZONE_BASE self -- @return #ZONE_BASE self
function ZONE_BASE:New( ZoneName ) function ZONE_BASE:New( ZoneName )
local self = BASE:Inherit( self, BASE:New() ) local self = BASE:Inherit( self, FSM:New() )
self:F( ZoneName ) self:F( ZoneName )
self.ZoneName = ZoneName self.ZoneName = ZoneName
@@ -1393,7 +1393,7 @@ end
function ZONE_POLYGON_BASE:Flush() function ZONE_POLYGON_BASE:Flush()
self:F2() self:F2()
self:E( { Polygon = self.ZoneName, Coordinates = self._.Polygon } ) self:F( { Polygon = self.ZoneName, Coordinates = self._.Polygon } )
return self return self
end end
@@ -1682,9 +1682,7 @@ do -- DETECTION_BASE
-- @return #DETECTION_BASE.DetectedItem -- @return #DETECTION_BASE.DetectedItem
function DETECTION_BASE:GetDetectedItemByIndex( Index ) function DETECTION_BASE:GetDetectedItemByIndex( Index )
self:I( { DetectedItemsByIndex = self.DetectedItemsByIndex } ) self:F( { self.DetectedItemsByIndex } )
self:I( { self.DetectedItemsByIndex } )
local DetectedItem = self.DetectedItemsByIndex[Index] local DetectedItem = self.DetectedItemsByIndex[Index]
if DetectedItem then if DetectedItem then
@@ -549,6 +549,9 @@ do -- ZONE_CAPTURE_COALITION
-- If it is, then we must move the zone to attack state. -- If it is, then we must move the zone to attack state.
self:HandleEvent( EVENTS.Hit, self.OnEventHit ) self:HandleEvent( EVENTS.Hit, self.OnEventHit )
-- ZoneGoal objects are added to the _DATABASE.ZONES_GOAL and SET_ZONE_GOAL sets.
_EVENTDISPATCHER:CreateEventNewZoneGoal( self )
return self return self
end end
@@ -566,7 +569,7 @@ do -- ZONE_CAPTURE_COALITION
function ZONE_CAPTURE_COALITION:IsGuarded() function ZONE_CAPTURE_COALITION:IsGuarded()
local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition ) local IsGuarded = self:IsAllInZoneOfCoalition( self.Coalition )
self:F( { IsGuarded = IsGuarded } ) self:F( { IsGuarded = IsGuarded } )
return IsGuarded return IsGuarded
end end
@@ -574,7 +577,7 @@ do -- ZONE_CAPTURE_COALITION
function ZONE_CAPTURE_COALITION:IsEmpty() function ZONE_CAPTURE_COALITION:IsEmpty()
local IsEmpty = self.Zone:IsNoneInZone() local IsEmpty = self:IsNoneInZone()
self:F( { IsEmpty = IsEmpty } ) self:F( { IsEmpty = IsEmpty } )
return IsEmpty return IsEmpty
end end
@@ -582,7 +585,7 @@ do -- ZONE_CAPTURE_COALITION
function ZONE_CAPTURE_COALITION:IsCaptured() function ZONE_CAPTURE_COALITION:IsCaptured()
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition ) local IsCaptured = self:IsAllInZoneOfOtherCoalition( self.Coalition )
self:F( { IsCaptured = IsCaptured } ) self:F( { IsCaptured = IsCaptured } )
return IsCaptured return IsCaptured
end end
@@ -590,7 +593,7 @@ do -- ZONE_CAPTURE_COALITION
function ZONE_CAPTURE_COALITION:IsAttacked() function ZONE_CAPTURE_COALITION:IsAttacked()
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition ) local IsAttacked = self:IsSomeInZoneOfCoalition( self.Coalition )
self:F( { IsAttacked = IsAttacked } ) self:F( { IsAttacked = IsAttacked } )
return IsAttacked return IsAttacked
end end
@@ -601,7 +604,7 @@ do -- ZONE_CAPTURE_COALITION
-- @param #ZONE_CAPTURE_COALITION self -- @param #ZONE_CAPTURE_COALITION self
function ZONE_CAPTURE_COALITION:Mark() function ZONE_CAPTURE_COALITION:Mark()
local Coord = self.Zone:GetCoordinate() local Coord = self:GetCoordinate()
local ZoneName = self:GetZoneName() local ZoneName = self:GetZoneName()
local State = self:GetState() local State = self:GetState()
@@ -640,7 +643,7 @@ do -- ZONE_CAPTURE_COALITION
--self:GetParent( self ):onenterCaptured() --self:GetParent( self ):onenterCaptured()
local NewCoalition = self.Zone:GetScannedCoalition() local NewCoalition = self:GetScannedCoalition()
self:F( { NewCoalition = NewCoalition } ) self:F( { NewCoalition = NewCoalition } )
self:SetCoalition( NewCoalition ) self:SetCoalition( NewCoalition )
@@ -673,14 +676,14 @@ do -- ZONE_CAPTURE_COALITION
--BASE:GetParent( self ).onafterGuard( self ) --BASE:GetParent( self ).onafterGuard( self )
if not self.SmokeScheduler then if not self.SmokeScheduler then
self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self ) self.SmokeScheduler = self:ScheduleRepeat( self.StartInterval, self.RepeatInterval, 0.1, nil, self.StatusSmoke, self )
end end
end end
function ZONE_CAPTURE_COALITION:IsCaptured() function ZONE_CAPTURE_COALITION:IsCaptured()
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition ) local IsCaptured = self:IsAllInZoneOfOtherCoalition( self.Coalition )
self:F( { IsCaptured = IsCaptured } ) self:F( { IsCaptured = IsCaptured } )
return IsCaptured return IsCaptured
end end
@@ -688,7 +691,7 @@ do -- ZONE_CAPTURE_COALITION
function ZONE_CAPTURE_COALITION:IsAttacked() function ZONE_CAPTURE_COALITION:IsAttacked()
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition ) local IsAttacked = self:IsSomeInZoneOfCoalition( self.Coalition )
self:F( { IsAttacked = IsAttacked } ) self:F( { IsAttacked = IsAttacked } )
return IsAttacked return IsAttacked
end end
@@ -744,13 +747,13 @@ do -- ZONE_CAPTURE_COALITION
-- --
function ZONE_CAPTURE_COALITION:Start( StartInterval, RepeatInterval ) function ZONE_CAPTURE_COALITION:Start( StartInterval, RepeatInterval )
StartInterval = StartInterval or 15 self.StartInterval = StartInterval or 15
RepeatInterval = RepeatInterval or 15 self.RepeatInterval = RepeatInterval or 15
if self.ScheduleStatusZone then if self.ScheduleStatusZone then
self:ScheduleStop( self.ScheduleStatusZone ) self:ScheduleStop( self.ScheduleStatusZone )
end end
self.ScheduleStatusZone = self:ScheduleRepeat( StartInterval, RepeatInterval, 0.1, nil, self.StatusZone, self ) self.ScheduleStatusZone = self:ScheduleRepeat( self.StartInterval, self.RepeatInterval, 1.5, nil, self.StatusZone, self )
end end
@@ -803,7 +806,7 @@ do -- ZONE_CAPTURE_COALITION
local UnitHit = EventData.TgtUnit local UnitHit = EventData.TgtUnit
if UnitHit then if UnitHit then
if UnitHit:IsInZone( self.Zone ) then if UnitHit:IsInZone( self ) then
self:Attack() self:Attack()
end end
end end
@@ -44,14 +44,13 @@ do -- Zone
--- ZONE_GOAL Constructor. --- ZONE_GOAL Constructor.
-- @param #ZONE_GOAL self -- @param #ZONE_GOAL self
-- @param Core.Zone#ZONE_BASE Zone A @{Zone} object with the goal to be achieved. -- @param Core.Zone#ZONE_RADIUS Zone A @{Zone} object with the goal to be achieved.
-- @return #ZONE_GOAL -- @return #ZONE_GOAL
function ZONE_GOAL:New( Zone ) function ZONE_GOAL:New( Zone )
local self = BASE:Inherit( self, FSM:New() ) -- #ZONE_GOAL local self = BASE:Inherit( self, ZONE_RADIUS:New( Zone:GetName(), Zone:GetVec2(), Zone:GetRadius() ) ) -- #ZONE_GOAL
self:F( { Zone = Zone } ) self:F( { Zone = Zone } )
self.Zone = Zone -- Core.Zone#ZONE_BASE
self.Goal = GOAL:New() self.Goal = GOAL:New()
self.SmokeTime = nil self.SmokeTime = nil
@@ -67,6 +66,7 @@ do -- Zone
-- @param Wrapper.Unit#UNIT DestroyedUnit The destroyed unit. -- @param Wrapper.Unit#UNIT DestroyedUnit The destroyed unit.
-- @param #string PlayerName The name of the player. -- @param #string PlayerName The name of the player.
return self return self
end end
@@ -74,7 +74,7 @@ do -- Zone
-- @param #ZONE_GOAL self -- @param #ZONE_GOAL self
-- @return Core.Zone#ZONE_BASE -- @return Core.Zone#ZONE_BASE
function ZONE_GOAL:GetZone() function ZONE_GOAL:GetZone()
return self.Zone return self
end end
@@ -82,7 +82,7 @@ do -- Zone
-- @param #ZONE_GOAL self -- @param #ZONE_GOAL self
-- @return #string -- @return #string
function ZONE_GOAL:GetZoneName() function ZONE_GOAL:GetZoneName()
return self.Zone:GetName() return self:GetName()
end end
@@ -101,7 +101,7 @@ do -- Zone
-- @param #ZONE_GOAL self -- @param #ZONE_GOAL self
-- @param #SMOKECOLOR.Color FlareColor -- @param #SMOKECOLOR.Color FlareColor
function ZONE_GOAL:Flare( FlareColor ) function ZONE_GOAL:Flare( FlareColor )
self.Zone:FlareZone( FlareColor, math.random( 1, 360 ) ) self:FlareZone( FlareColor, math.random( 1, 360 ) )
end end
@@ -130,7 +130,7 @@ do -- Zone
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
if self.SmokeColor then if self.SmokeColor then
self.Zone:GetCoordinate():Smoke( self.SmokeColor ) self:GetCoordinate():Smoke( self.SmokeColor )
--self.SmokeColor = nil --self.SmokeColor = nil
self.SmokeTime = CurrentTime self.SmokeTime = CurrentTime
end end
@@ -147,11 +147,9 @@ do -- Zone
local Vec3 = EventData.IniDCSUnit:getPosition().p local Vec3 = EventData.IniDCSUnit:getPosition().p
self:F( { Vec3 = Vec3 } ) self:F( { Vec3 = Vec3 } )
local ZoneGoal = self:GetZone()
self:F({ZoneGoal})
if EventData.IniDCSUnit then if EventData.IniDCSUnit then
if ZoneGoal:IsVec3InZone(Vec3) then if self:IsVec3InZone(Vec3) then
local PlayerHits = _DATABASE.HITS[EventData.IniUnitName] local PlayerHits = _DATABASE.HITS[EventData.IniUnitName]
if PlayerHits then if PlayerHits then
for PlayerName, PlayerHit in pairs( PlayerHits.Players or {} ) do for PlayerName, PlayerHit in pairs( PlayerHits.Players or {} ) do
@@ -104,7 +104,7 @@ do -- ZoneGoal
local State = self:GetState() local State = self:GetState()
self:F( { State = self:GetState() } ) self:F( { State = self:GetState() } )
self.Zone:Scan( { Object.Category.UNIT, Object.Category.STATIC } ) self:Scan( { Object.Category.UNIT, Object.Category.STATIC } )
end end
+1
View File
@@ -20,6 +20,7 @@ __Moose.Include( 'Scripts/Moose/Core/Velocity.lua' )
__Moose.Include( 'Scripts/Moose/Core/Message.lua' ) __Moose.Include( 'Scripts/Moose/Core/Message.lua' )
__Moose.Include( 'Scripts/Moose/Core/Fsm.lua' ) __Moose.Include( 'Scripts/Moose/Core/Fsm.lua' )
__Moose.Include( 'Scripts/Moose/Core/Radio.lua' ) __Moose.Include( 'Scripts/Moose/Core/Radio.lua' )
__Moose.Include( 'Scripts/Moose/Core/RadioQueue.lua' )
__Moose.Include( 'Scripts/Moose/Core/Spawn.lua' ) __Moose.Include( 'Scripts/Moose/Core/Spawn.lua' )
__Moose.Include( 'Scripts/Moose/Core/SpawnStatic.lua' ) __Moose.Include( 'Scripts/Moose/Core/SpawnStatic.lua' )
__Moose.Include( 'Scripts/Moose/Core/Goal.lua' ) __Moose.Include( 'Scripts/Moose/Core/Goal.lua' )
@@ -180,7 +180,7 @@ COMMANDCENTER = {
COMMANDCENTER.AutoAssignMethods = { COMMANDCENTER.AutoAssignMethods = {
["Random"] = 1, ["Random"] = 1,
["Distance"] = 2, ["Distance"] = 2,
["Priority"] = 3 ["Priority"] = 3,
} }
--- The constructor takes an IDENTIFIABLE as the HQ command center. --- The constructor takes an IDENTIFIABLE as the HQ command center.
@@ -200,7 +200,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
self:SetAutoAssignTasks( false ) self:SetAutoAssignTasks( false )
self:SetAutoAcceptTasks( true ) self:SetAutoAcceptTasks( true )
self:SetAutoAssignMethod( COMMANDCENTER.AutoAssignMethods.Random ) self:SetAutoAssignMethod( COMMANDCENTER.AutoAssignMethods.Distance )
self:SetFlashStatus( false )
self:HandleEvent( EVENTS.Birth, self:HandleEvent( EVENTS.Birth,
--- @param #COMMANDCENTER self --- @param #COMMANDCENTER self
@@ -208,8 +209,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
function( self, EventData ) function( self, EventData )
if EventData.IniObjectCategory == 1 then if EventData.IniObjectCategory == 1 then
local EventGroup = GROUP:Find( EventData.IniDCSGroup ) local EventGroup = GROUP:Find( EventData.IniDCSGroup )
self:E( { CommandCenter = self:GetName(), EventGroup = EventGroup:GetName(), HasGroup = self:HasGroup( EventGroup ), EventData = EventData } ) --self:E( { CommandCenter = self:GetName(), EventGroup = EventGroup:GetName(), HasGroup = self:HasGroup( EventGroup ), EventData = EventData } )
if EventGroup and self:HasGroup( EventGroup ) then if EventGroup and EventGroup:IsAlive() and self:HasGroup( EventGroup ) then
local CommandCenterMenu = MENU_GROUP:New( EventGroup, self:GetText() ) local CommandCenterMenu = MENU_GROUP:New( EventGroup, self:GetText() )
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 )
@@ -791,3 +792,12 @@ function COMMANDCENTER:ReportDetails( ReportGroup, Task )
self:MessageToGroup( Report:Text(), ReportGroup ) self:MessageToGroup( Report:Text(), ReportGroup )
end end
--- Let the command center flash a report of the status of the subscribed task to a group.
-- @param #COMMANDCENTER self
function COMMANDCENTER:SetFlashStatus( Flash )
self:F()
self.FlashStatus = Flash or true
end
@@ -254,11 +254,45 @@ do -- DETECTION MANAGER
end end
--- Get the command center to communicate actions to the players.
-- @param #DETECTION_MANAGER self
-- @return Tasking.CommandCenter#COMMANDCENTER The command center.
function DETECTION_MANAGER:GetCommandCenter()
return self.CC
end
--- Set the frequency of communication and the mode of communication for voice overs.
-- @param #DETECTION_MANAGER self
-- @param #number RadioFrequency The frequency of communication.
-- @param #number RadioModulation The modulation of communication.
-- @param #number RadioPower The power in Watts of communication.
function DETECTION_MANAGER:SetRadioFrequency( RadioFrequency, RadioModulation, RadioPower )
self.RadioFrequency = RadioFrequency
self.RadioModulation = RadioModulation or radio.modulation.AM
self.RadioPower = RadioPower or 100
if self.RadioQueue then
self.RadioQueue:Stop()
end
self.RadioQueue = nil
self.RadioQueue = RADIOQUEUE:New( self.RadioFrequency, self.RadioModulation )
self.RadioQueue.power = self.RadioPower
self.RadioQueue:Start( 0.5 )
end
--- Send an information message to the players reporting to the command center. --- Send an information message to the players reporting to the command center.
-- @param #DETECTION_MANAGER self -- @param #DETECTION_MANAGER self
-- @param #string Message The message to be sent. -- @param #string Message The message to be sent.
-- @param #string SoundFile The name of the sound file .wav or .ogg.
-- @param #number SoundDuration The duration of the sound.
-- @param #string SoundPath The path pointing to the folder in the mission file.
-- @param Wrapper.Group#GROUP DefenderGroup The defender group sending the message.
-- @return #DETECTION_MANGER self -- @return #DETECTION_MANGER self
function DETECTION_MANAGER:MessageToPlayers( Message ) function DETECTION_MANAGER:MessageToPlayers( Message, SoundFile, SoundDuration, SoundPath, DefenderGroup )
self:F( { Message = Message } ) self:F( { Message = Message } )
@@ -269,6 +303,17 @@ do -- DETECTION MANAGER
end end
end end
-- Here we handle the transmission of the voice over.
-- If for a certain reason the Defender does not exist, we use the coordinate of the airbase to send the message from.
if SoundFile then
local RadioQueue = self.RadioQueue -- Core.RadioQueue#RADIOQUEUE
local DefenderUnit = DefenderGroup:GetUnit(1)
if DefenderUnit and DefenderUnit:IsAlive() then
RadioQueue:SetSenderUnitName( DefenderUnit:GetName() )
end
RadioQueue:NewTransmission( SoundFile, SoundDuration, SoundPath )
end
return self return self
end end
@@ -279,7 +324,6 @@ do -- DETECTION MANAGER
-- @param Functional.Detection#DETECTION_BASE Detection -- @param Functional.Detection#DETECTION_BASE Detection
-- @return #DETECTION_MANAGER self -- @return #DETECTION_MANAGER self
function DETECTION_MANAGER:ProcessDetected( Detection ) function DETECTION_MANAGER:ProcessDetected( Detection )
self:E()
end end
+33 -4
View File
@@ -856,6 +856,8 @@ do -- Group Assignment
CommandCenter:SetMenu() CommandCenter:SetMenu()
self:MenuFlashTaskStatus( TaskGroup, self:GetMission():GetCommandCenter().FlashStatus )
return self return self
end end
@@ -1111,6 +1113,11 @@ function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime )
end end
local MarkMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Mark Task Location on Map" ), TaskControl, self.MenuMarkToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) local MarkMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Mark Task Location on Map" ), TaskControl, self.MenuMarkToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Details" ), TaskControl, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ) local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Details" ), TaskControl, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
if not self.FlashTaskStatus then
local TaskFlashStatusMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Flash Task Details" ), TaskControl, self.MenuFlashTaskStatus, self, TaskGroup, true ):SetTime( MenuTime ):SetTag( "Tasking" )
else
local TaskFlashStatusMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Stop Flash Task Details" ), TaskControl, self.MenuFlashTaskStatus, self, TaskGroup, nil ):SetTime( MenuTime ):SetTag( "Tasking" )
end
end end
end end
@@ -1225,12 +1232,34 @@ end
--- Report the task status. --- Report the task status.
-- @param #TASK self -- @param #TASK self
-- @param Wrapper.Group#GROUP TaskGroup
function TASK:MenuTaskStatus( TaskGroup ) function TASK:MenuTaskStatus( TaskGroup )
local ReportText = self:ReportDetails( TaskGroup ) if TaskGroup:IsAlive() then
self:T( ReportText ) local ReportText = self:ReportDetails( TaskGroup )
self:GetMission():GetCommandCenter():MessageTypeToGroup( ReportText, TaskGroup, MESSAGE.Type.Detailed )
self:T( ReportText )
self:GetMission():GetCommandCenter():MessageTypeToGroup( ReportText, TaskGroup, MESSAGE.Type.Detailed )
end
end
--- Report the task status.
-- @param #TASK self
function TASK:MenuFlashTaskStatus( TaskGroup, Flash )
self.FlashTaskStatus = Flash
if self.FlashTaskStatus then
self.FlashTaskScheduler, self.FlashTaskScheduleID = SCHEDULER:New( self, self.MenuTaskStatus, { TaskGroup }, 0, 60 )
else
if self.FlashTaskScheduler then
self.FlashTaskScheduler:Stop( self.FlashTaskScheduleID )
self.FlashTaskScheduler = nil
self.FlashTaskScheduleID = nil
end
end
end end
+11 -10
View File
@@ -52,16 +52,16 @@ end
--- Add taskinfo. --- Add taskinfo.
-- @param #TASKINFO self -- @param #TASKINFO self
-- @param #string The info key. -- @param #string Key The info key.
-- @param Data The data of the info. -- @param Data The data of the info.
-- @param #number Order The display order, which is a number from 0 to 100. -- @param #number Order The display order, which is a number from 0 to 100.
-- @param #TASKINFO.Detail Detail The detail Level. -- @param #TASKINFO.Detail Detail The detail Level.
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports. -- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
-- @return #TASKINFO self -- @return #TASKINFO self
function TASKINFO:AddInfo( Key, Data, Order, Detail, Keep ) function TASKINFO:AddInfo( Key, Data, Order, Detail, Keep, ShowKey, Type )
self.VolatileInfo:Add( Key, { Data = Data, Order = Order, Detail = Detail } ) self.VolatileInfo:Add( Key, { Data = Data, Order = Order, Detail = Detail, ShowKey = ShowKey, Type = Type } )
if Keep == true then if Keep == true then
self.PersistentInfo:Add( Key, { Data = Data, Order = Order, Detail = Detail } ) self.PersistentInfo:Add( Key, { Data = Data, Order = Order, Detail = Detail, ShowKey = ShowKey, Type = Type } )
end end
return self return self
end end
@@ -124,8 +124,8 @@ end
-- @param #TASKINFO.Detail Detail The detail Level. -- @param #TASKINFO.Detail Detail The detail Level.
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports. -- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
-- @return #TASKINFO self -- @return #TASKINFO self
function TASKINFO:AddCoordinate( Coordinate, Order, Detail, Keep ) function TASKINFO:AddCoordinate( Coordinate, Order, Detail, Keep, ShowKey, Name )
self:AddInfo( "Coordinate", Coordinate, Order, Detail, Keep ) self:AddInfo( Name or "Coordinate", Coordinate, Order, Detail, Keep, ShowKey, "Coordinate" )
return self return self
end end
@@ -133,8 +133,8 @@ end
--- Get the Coordinate. --- Get the Coordinate.
-- @param #TASKINFO self -- @param #TASKINFO self
-- @return Core.Point#COORDINATE Coordinate -- @return Core.Point#COORDINATE Coordinate
function TASKINFO:GetCoordinate() function TASKINFO:GetCoordinate( Name )
return self:GetData( "Coordinate" ) return self:GetData( Name or "Coordinate" )
end end
@@ -308,10 +308,11 @@ function TASKINFO:Report( Report, Detail, ReportGroup, Task )
if Data.Detail:find( Detail ) then if Data.Detail:find( Detail ) then
local Text = "" local Text = ""
local ShowKey = ( Data.ShowKey == nil or Data.ShowKey == true )
if Key == "TaskName" then if Key == "TaskName" then
Key = nil Key = nil
Text = Data.Data Text = Data.Data
elseif Key == "Coordinate" then elseif Data.Type and Data.Type == "Coordinate" then
local Coordinate = Data.Data -- Core.Point#COORDINATE local Coordinate = Data.Data -- Core.Point#COORDINATE
Text = Coordinate:ToString( ReportGroup:GetUnit(1), nil, Task ) Text = Coordinate:ToString( ReportGroup:GetUnit(1), nil, Task )
elseif Key == "Threat" then elseif Key == "Threat" then
@@ -357,7 +358,7 @@ function TASKINFO:Report( Report, Detail, ReportGroup, Task )
end end
if Text ~= "" then if Text ~= "" then
LineReport:Add( ( Key and ( Key .. ":" ) or "" ) .. Text ) LineReport:Add( ( ( Key and ShowKey == true ) and ( Key .. ": " ) or "" ) .. Text )
end end
end end
@@ -194,6 +194,45 @@ do -- TASK_CAPTURE_DISPATCHER
end end
--- Link a task capture dispatcher from the other coalition to understand its plan for defenses.
-- This is used for the tactical overview, so the players also know the zones attacked by the other coalition!
-- @param #TASK_CAPTURE_DISPATCHER self
-- @param #TASK_CAPTURE_DISPATCHER DefenseTaskCaptureDispatcher
function TASK_CAPTURE_DISPATCHER:SetDefenseTaskCaptureDispatcher( DefenseTaskCaptureDispatcher )
self.DefenseTaskCaptureDispatcher = DefenseTaskCaptureDispatcher
end
--- Get the linked task capture dispatcher from the other coalition to understand its plan for defenses.
-- This is used for the tactical overview, so the players also know the zones attacked by the other coalition!
-- @param #TASK_CAPTURE_DISPATCHER self
-- @return #TASK_CAPTURE_DISPATCHER
function TASK_CAPTURE_DISPATCHER:GetDefenseTaskCaptureDispatcher()
return self.DefenseTaskCaptureDispatcher
end
--- Link an AI A2G dispatcher from the other coalition to understand its plan for defenses.
-- This is used for the tactical overview, so the players also know the zones attacked by the other AI A2G dispatcher!
-- @param #TASK_CAPTURE_DISPATCHER self
-- @param AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER DefenseAIA2GDispatcher
function TASK_CAPTURE_DISPATCHER:SetDefenseAIA2GDispatcher( DefenseAIA2GDispatcher )
self.DefenseAIA2GDispatcher = DefenseAIA2GDispatcher
end
--- Get the linked AI A2G dispatcher from the other coalition to understand its plan for defenses.
-- This is used for the tactical overview, so the players also know the zones attacked by the AI A2G dispatcher!
-- @param #TASK_CAPTURE_DISPATCHER self
-- @return AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER
function TASK_CAPTURE_DISPATCHER:GetDefenseAIA2GDispatcher()
return self.DefenseAIA2GDispatcher
end
--- Add a capture zone task. --- Add a capture zone task.
-- @param #TASK_CAPTURE_DISPATCHER self -- @param #TASK_CAPTURE_DISPATCHER self
@@ -274,6 +313,9 @@ do -- TASK_CAPTURE_DISPATCHER
CaptureZone.Task.TaskPrefix = CaptureZone.TaskPrefix -- We keep the TaskPrefix for further reference! CaptureZone.Task.TaskPrefix = CaptureZone.TaskPrefix -- We keep the TaskPrefix for further reference!
Mission:AddTask( CaptureZone.Task ) Mission:AddTask( CaptureZone.Task )
TaskReport:Add( TaskName ) TaskReport:Add( TaskName )
-- Link the Task Dispatcher to the capture zone task, because it is used on the UpdateTaskInfo.
CaptureZone.Task:SetDispatcher( self )
CaptureZone.Task:UpdateTaskInfo() CaptureZone.Task:UpdateTaskInfo()
function CaptureZone.Task.OnEnterAssigned( Task, From, Event, To ) function CaptureZone.Task.OnEnterAssigned( Task, From, Event, To )
@@ -281,6 +323,7 @@ do -- TASK_CAPTURE_DISPATCHER
self.AI_A2G_Dispatcher:Unlock( Task.TaskZoneName ) -- This will unlock the zone to be defended by AI. self.AI_A2G_Dispatcher:Unlock( Task.TaskZoneName ) -- This will unlock the zone to be defended by AI.
end end
CaptureZone.Task:UpdateTaskInfo() CaptureZone.Task:UpdateTaskInfo()
CaptureZone.Task.ZoneGoal.Attacked = true
end end
function CaptureZone.Task.OnEnterSuccess( Task, From, Event, To ) function CaptureZone.Task.OnEnterSuccess( Task, From, Event, To )
@@ -289,6 +332,7 @@ do -- TASK_CAPTURE_DISPATCHER
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI. self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
end end
CaptureZone.Task:UpdateTaskInfo() CaptureZone.Task:UpdateTaskInfo()
CaptureZone.Task.ZoneGoal.Attacked = false
end end
function CaptureZone.Task.OnEnterCancelled( Task, From, Event, To ) function CaptureZone.Task.OnEnterCancelled( Task, From, Event, To )
@@ -297,6 +341,7 @@ do -- TASK_CAPTURE_DISPATCHER
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI. self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
end end
CaptureZone.Task:UpdateTaskInfo() CaptureZone.Task:UpdateTaskInfo()
CaptureZone.Task.ZoneGoal.Attacked = false
end end
function CaptureZone.Task.OnEnterFailed( Task, From, Event, To ) function CaptureZone.Task.OnEnterFailed( Task, From, Event, To )
@@ -305,6 +350,7 @@ do -- TASK_CAPTURE_DISPATCHER
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI. self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
end end
CaptureZone.Task:UpdateTaskInfo() CaptureZone.Task:UpdateTaskInfo()
CaptureZone.Task.ZoneGoal.Attacked = false
end end
function CaptureZone.Task.OnEnterAborted( Task, From, Event, To ) function CaptureZone.Task.OnEnterAborted( Task, From, Event, To )
@@ -313,6 +359,7 @@ do -- TASK_CAPTURE_DISPATCHER
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI. self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
end end
CaptureZone.Task:UpdateTaskInfo() CaptureZone.Task:UpdateTaskInfo()
CaptureZone.Task.ZoneGoal.Attacked = false
end end
-- Now broadcast the onafterCargoPickedUp event to the Task Cargo Dispatcher. -- Now broadcast the onafterCargoPickedUp event to the Task Cargo Dispatcher.
@@ -322,6 +369,7 @@ do -- TASK_CAPTURE_DISPATCHER
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI. self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
end end
CaptureZone.Task:UpdateTaskInfo() CaptureZone.Task:UpdateTaskInfo()
CaptureZone.Task.ZoneGoal.Attacked = false
end end
end end
@@ -228,11 +228,47 @@ do -- TASK_CAPTURE_ZONE
local ZoneCoordinate = self.ZoneGoal:GetZone():GetCoordinate() local ZoneCoordinate = self.ZoneGoal:GetZone():GetCoordinate()
self.TaskInfo:AddTaskName( 0, "MSOD", Persist ) self.TaskInfo:AddTaskName( 0, "MSOD", Persist )
self.TaskInfo:AddCoordinate( ZoneCoordinate, 1, "SOD", Persist ) self.TaskInfo:AddCoordinate( ZoneCoordinate, 1, "SOD", Persist )
self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD", Persist ) -- self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD", Persist )
self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD", Persist ) -- self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD", Persist )
local SetUnit = self.ZoneGoal.Zone:GetScannedSetUnit() local SetUnit = self.ZoneGoal:GetScannedSetUnit()
local ThreatLevel, ThreatText = SetUnit:CalculateThreatLevelA2G() local ThreatLevel, ThreatText = SetUnit:CalculateThreatLevelA2G()
local ThreatCount = SetUnit:Count()
self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 20, "MOD", Persist ) self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 20, "MOD", Persist )
self.TaskInfo:AddInfo( "Remaining Units", ThreatCount, 21, "MOD", Persist, true)
if self.Dispatcher then
local DefenseTaskCaptureDispatcher = self.Dispatcher:GetDefenseTaskCaptureDispatcher() -- Tasking.Task_Capture_Dispatcher#TASK_CAPTURE_DISPATCHER
if DefenseTaskCaptureDispatcher then
-- Loop through all zones of the player Defenses, and check which zone has an assigned task!
-- The Zones collection contains a Task. This Task is checked if it is assigned.
-- If Assigned, then this task will be the task that is the closest to the defense zone.
for TaskName, CaptureZone in pairs( DefenseTaskCaptureDispatcher.Zones or {} ) do
local Task = CaptureZone.Task -- Tasking.Task_Capture_Zone#TASK_CAPTURE_ZONE
if Task and Task:IsStateAssigned() then -- We also check assigned.
-- Now we register the defense player zone information to the task report.
self.TaskInfo:AddInfo( "Defense Player Zone", Task.ZoneGoal:GetName(), 30, "MOD", Persist )
self.TaskInfo:AddCoordinate( Task.ZoneGoal:GetZone():GetCoordinate(), 31, "MOD", Persist, false, "Defense Player Coordinate" )
end
end
end
local DefenseAIA2GDispatcher = self.Dispatcher:GetDefenseAIA2GDispatcher() -- AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER
if DefenseAIA2GDispatcher then
-- Loop through all the tasks of the AI Defenses, and check which zone is involved in the defenses and is active!
for Defender, Task in pairs( DefenseAIA2GDispatcher:GetDefenderTasks() or {} ) do
local DetectedItem = DefenseAIA2GDispatcher:GetDefenderTaskTarget( Defender )
if DetectedItem then
local DetectedZone = DefenseAIA2GDispatcher.Detection:GetDetectedItemZone( DetectedItem )
if DetectedZone then
self.TaskInfo:AddInfo( "Defense AI Zone", DetectedZone:GetName(), 40, "MOD", Persist )
self.TaskInfo:AddCoordinate( DetectedZone:GetCoordinate(), 41, "MOD", Persist, false, "Defense AI Coordinate" )
end
end
end
end
end
end end
@@ -274,7 +310,7 @@ do -- TASK_CAPTURE_ZONE
-- @param #number AutoAssignMethod The method to be applied to the task. -- @param #number AutoAssignMethod The method to be applied to the task.
-- @param Tasking.CommandCenter#COMMANDCENTER CommandCenter The command center. -- @param Tasking.CommandCenter#COMMANDCENTER CommandCenter The command center.
-- @param Wrapper.Group#GROUP TaskGroup The player group. -- @param Wrapper.Group#GROUP TaskGroup The player group.
function TASK_CAPTURE_ZONE:GetAutoAssignPriority( AutoAssignMethod, CommandCenter, TaskGroup ) function TASK_CAPTURE_ZONE:GetAutoAssignPriority( AutoAssignMethod, CommandCenter, TaskGroup, AutoAssignReference )
if AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Random then if AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Random then
return math.random( 1, 9 ) return math.random( 1, 9 )
@@ -185,7 +185,6 @@ do -- TASK_MANAGER
-- @param #TASK_MANAGER self -- @param #TASK_MANAGER self
-- @return #TASK_MANAGER self -- @return #TASK_MANAGER self
function TASK_MANAGER:ManageTasks() function TASK_MANAGER:ManageTasks()
self:E()
end end
@@ -521,6 +521,32 @@ function UTILS.spairs( t, order )
end end
end end
-- Here is a customized version of pairs, which I called kpairs because it iterates over the table in a sorted order, based on a function that will determine the keys as reference first.
function UTILS.kpairs( t, getkey, order )
-- collect the keys
local keys = {}
local keyso = {}
for k, o in pairs(t) do keys[#keys+1] = k keyso[#keyso+1] = getkey( o ) end
-- if order function given, sort by it by passing the table and keys a, b,
-- otherwise just sort the keys
if order then
table.sort(keys, function(a,b) return order(t, a, b) end)
else
table.sort(keys)
end
-- return the iterator function
local i = 0
return function()
i = i + 1
if keys[i] then
return keyso[i], t[keys[i]]
end
end
end
-- Here is a customized version of pairs, which I called rpairs because it iterates over the table in a random order. -- Here is a customized version of pairs, which I called rpairs because it iterates over the table in a random order.
function UTILS.rpairs( t ) function UTILS.rpairs( t )
-- collect the keys -- collect the keys
+3 -2
View File
@@ -133,7 +133,8 @@ function CLIENT:FindByName( ClientName, ClientBriefing, Error )
end end
function CLIENT:Register( ClientName ) function CLIENT:Register( ClientName )
local self = BASE:Inherit( self, UNIT:Register( ClientName ) )
local self = BASE:Inherit( self, UNIT:Register( ClientName ) ) -- #CLIENT
self:F( ClientName ) self:F( ClientName )
self.ClientName = ClientName self.ClientName = ClientName
@@ -141,7 +142,7 @@ function CLIENT:Register( ClientName )
self.ClientAlive2 = false self.ClientAlive2 = false
--self.AliveCheckScheduler = routines.scheduleFunction( self._AliveCheckScheduler, { self }, timer.getTime() + 1, 5 ) --self.AliveCheckScheduler = routines.scheduleFunction( self._AliveCheckScheduler, { self }, timer.getTime() + 1, 5 )
self.AliveCheckScheduler = SCHEDULER:New( self, self._AliveCheckScheduler, { "Client Alive " .. ClientName }, 1, 5 ) self.AliveCheckScheduler = SCHEDULER:New( self, self._AliveCheckScheduler, { "Client Alive " .. ClientName }, 1, 5, 0.5 )
self:F( self ) self:F( self )
return self return self
@@ -307,7 +307,6 @@ end
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @return #CONTROLLABLE -- @return #CONTROLLABLE
function CONTROLLABLE:ClearTasks() function CONTROLLABLE:ClearTasks()
self:E( "ClearTasks" )
local DCSControllable = self:GetDCSObject() local DCSControllable = self:GetDCSObject()
@@ -444,7 +443,7 @@ end
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self
-- @param DCS#Time time DCS mission time. -- @param DCS#Time time DCS mission time.
-- @param #string userFlag Name of the user flag. -- @param #string userFlag Name of the user flag.
-- @param #boolean userFlagValue User flag value *true* or *false*. Could also be numeric, i.e. either 0=*false* or 1=*true*. Other numeric values don't work! -- @param #boolean userFlagValue User flag value *true* or *false*. Could also be numeric, i.e. either 0=*false* or 1=*true*. Other numeric values don't work!
-- @param #string condition Lua string. -- @param #string condition Lua string.
-- @param DCS#Time duration Duration in seconds. -- @param DCS#Time duration Duration in seconds.
-- @param #number lastWayPoint Last waypoint. -- @param #number lastWayPoint Last waypoint.
@@ -944,7 +943,7 @@ end
-- @param #boolean Divebomb (optional) Perform dive bombing. Default false. -- @param #boolean Divebomb (optional) Perform dive bombing. Default false.
-- @return DCS#Task The DCS task structure. -- @return DCS#Task The DCS task structure.
function CONTROLLABLE:TaskBombing( Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, WeaponType, Divebomb ) function CONTROLLABLE:TaskBombing( Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, WeaponType, Divebomb )
self:E( { self.ControllableName, Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, WeaponType, Divebomb } ) self:F( { self.ControllableName, Vec2, GroupAttack, WeaponExpend, AttackQty, Direction, Altitude, WeaponType, Divebomb } )
local _groupattack=false local _groupattack=false
if GroupAttack then if GroupAttack then
@@ -990,7 +989,7 @@ function CONTROLLABLE:TaskBombing( Vec2, GroupAttack, WeaponExpend, AttackQty, D
}, },
} }
self:E( { TaskBombing=DCSTask } ) self:F( { TaskBombing=DCSTask } )
return DCSTask return DCSTask
end end
+40 -2
View File
@@ -696,7 +696,9 @@ end
--- Returns the Unit's A2G threat level on a scale from 1 to 10 ... --- Returns the Unit's A2G threat level on a scale from 1 to 10 ...
-- The following threat levels are foreseen: -- Depending on the era and the type of unit, the following threat levels are foreseen:
--
-- **Modern**:
-- --
-- * Threat level 0: Unit is unarmed. -- * Threat level 0: Unit is unarmed.
-- * Threat level 1: Unit is infantry. -- * Threat level 1: Unit is infantry.
@@ -709,13 +711,49 @@ end
-- * Threat level 8: Unit is a Short Range SAM, radar guided. -- * Threat level 8: Unit is a Short Range SAM, radar guided.
-- * Threat level 9: Unit is a Medium Range SAM, radar guided. -- * Threat level 9: Unit is a Medium Range SAM, radar guided.
-- * Threat level 10: Unit is a Long Range SAM, radar guided. -- * Threat level 10: Unit is a Long Range SAM, radar guided.
--
-- **Cold**:
--
-- * Threat level 0: Unit is unarmed.
-- * Threat level 1: Unit is infantry.
-- * Threat level 2: Unit is an infantry vehicle.
-- * Threat level 3: Unit is ground artillery.
-- * Threat level 4: Unit is a tank.
-- * Threat level 5: Unit is a modern tank or ifv with ATGM.
-- * Threat level 6: Unit is a AAA.
-- * Threat level 7: Unit is a SAM or manpad, IR guided.
-- * Threat level 8: Unit is a Short Range SAM, radar guided.
-- * Threat level 10: Unit is a Medium Range SAM, radar guided.
--
-- **Korea**:
--
-- * Threat level 0: Unit is unarmed.
-- * Threat level 1: Unit is infantry.
-- * Threat level 2: Unit is an infantry vehicle.
-- * Threat level 3: Unit is ground artillery.
-- * Threat level 5: Unit is a tank.
-- * Threat level 6: Unit is a AAA.
-- * Threat level 7: Unit is a SAM or manpad, IR guided.
-- * Threat level 10: Unit is a Short Range SAM, radar guided.
--
-- **WWII**:
--
-- * Threat level 0: Unit is unarmed.
-- * Threat level 1: Unit is infantry.
-- * Threat level 2: Unit is an infantry vehicle.
-- * Threat level 3: Unit is ground artillery.
-- * Threat level 5: Unit is a tank.
-- * Threat level 7: Unit is FLAK.
-- * Threat level 10: Unit is AAA.
--
--
-- @param #UNIT self -- @param #UNIT self
function UNIT:GetThreatLevel() function UNIT:GetThreatLevel()
local ThreatLevel = 0 local ThreatLevel = 0
local ThreatText = "" local ThreatText = ""
local Descriptor = self:GetDesc() local Descriptor = self:GetDesc()
if Descriptor then if Descriptor then