mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Merge branch 'master' into LDT-Debug
# Conflicts: # Moose Development/Moose/Moose.lua # Moose Mission Setup/Moose.lua
This commit is contained in:
@@ -70,8 +70,9 @@ function AI_A2A:New( AIGroup )
|
||||
|
||||
self:SetControllable( AIGroup )
|
||||
|
||||
self:ManageFuel( .2, 60 )
|
||||
self:ManageDamage( 0.4 )
|
||||
self:SetFuelThreshold( .2, 60 )
|
||||
self:SetDamageThreshold( 0.4 )
|
||||
self:SetDisengageRadius( 70000 )
|
||||
|
||||
self:SetStartState( "Stopped" )
|
||||
|
||||
@@ -219,8 +220,37 @@ function AI_A2A:New( AIGroup )
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
|
||||
self:AddTransition( "Patrolling", "Refuel", "Refuelling" )
|
||||
|
||||
--- Refuel Handler OnBefore for AI_A2A
|
||||
-- @function [parent=#AI_A2A] OnBeforeRefuel
|
||||
-- @param #AI_A2A self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Refuel Handler OnAfter for AI_A2A
|
||||
-- @function [parent=#AI_A2A] OnAfterRefuel
|
||||
-- @param #AI_A2A self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- Refuel Trigger for AI_A2A
|
||||
-- @function [parent=#AI_A2A] Refuel
|
||||
-- @param #AI_A2A self
|
||||
|
||||
--- Refuel Asynchronous Trigger for AI_A2A
|
||||
-- @function [parent=#AI_A2A] __Refuel
|
||||
-- @param #AI_A2A self
|
||||
-- @param #number Delay
|
||||
|
||||
self:AddTransition( "*", "Takeoff", "Airborne" )
|
||||
self:AddTransition( "*", "Return", "Returning" )
|
||||
self:AddTransition( "*", "Hold", "Holding" )
|
||||
self:AddTransition( "*", "Home", "Home" )
|
||||
self:AddTransition( "*", "LostControl", "LostControl" )
|
||||
self:AddTransition( "*", "Fuel", "Fuel" )
|
||||
@@ -234,6 +264,13 @@ function AI_A2A:New( AIGroup )
|
||||
return self
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function GROUP:OnEventTakeoff( EventData, Fsm )
|
||||
Fsm:Takeoff()
|
||||
self:UnHandleEvent( EVENTS.Takeoff )
|
||||
end
|
||||
|
||||
function AI_A2A:SetDispatcher( Dispatcher )
|
||||
self.Dispatcher = Dispatcher
|
||||
end
|
||||
@@ -294,8 +331,27 @@ function AI_A2A:SetHomeAirbase( HomeAirbase )
|
||||
self.HomeAirbase = HomeAirbase
|
||||
end
|
||||
|
||||
--- Sets to refuel at the given tanker.
|
||||
-- @param #AI_A2A self
|
||||
-- @param Wrapper.Group#GROUP TankerName The group name of the tanker as defined within the Mission Editor or spawned.
|
||||
-- @return #AI_A2A self
|
||||
function AI_A2A:SetTanker( TankerName )
|
||||
self:F2( { TankerName } )
|
||||
|
||||
self.TankerName = TankerName
|
||||
end
|
||||
|
||||
|
||||
--- Sets the disengage range, that when engaging a target beyond the specified range, the engagement will be cancelled and the plane will RTB.
|
||||
-- @param #AI_A2A self
|
||||
-- @param #number DisengageRadius The disengage range.
|
||||
-- @return #AI_A2A self
|
||||
function AI_A2A:SetDisengageRadius( DisengageRadius )
|
||||
self:F2( { DisengageRadius } )
|
||||
|
||||
self.DisengageRadius = DisengageRadius
|
||||
end
|
||||
|
||||
--- Set the status checking off.
|
||||
-- @param #AI_A2A self
|
||||
-- @return #AI_A2A self
|
||||
@@ -311,13 +367,13 @@ end
|
||||
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_A2A.
|
||||
-- Once the time is finished, the old AI will return to the base.
|
||||
-- @param #AI_A2A self
|
||||
-- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
||||
-- @param #number PatrolFuelThresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
||||
-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
|
||||
-- @return #AI_A2A self
|
||||
function AI_A2A:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime )
|
||||
function AI_A2A:SetFuelThreshold( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
|
||||
|
||||
self.PatrolManageFuel = true
|
||||
self.PatrolFuelTresholdPercentage = PatrolFuelTresholdPercentage
|
||||
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
|
||||
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
|
||||
|
||||
self.Controllable:OptionRTBBingoFuel( false )
|
||||
@@ -332,12 +388,12 @@ end
|
||||
-- Note that for groups, the average damage of the complete group will be calculated.
|
||||
-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage treshold will be 0.25.
|
||||
-- @param #AI_A2A self
|
||||
-- @param #number PatrolDamageTreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
|
||||
-- @param #number PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
|
||||
-- @return #AI_A2A self
|
||||
function AI_A2A:ManageDamage( PatrolDamageTreshold )
|
||||
function AI_A2A:SetDamageThreshold( PatrolDamageThreshold )
|
||||
|
||||
self.PatrolManageDamage = true
|
||||
self.PatrolDamageTreshold = PatrolDamageTreshold
|
||||
self.PatrolDamageThreshold = PatrolDamageThreshold
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -372,45 +428,79 @@ end
|
||||
|
||||
--- @param #AI_A2A self
|
||||
function AI_A2A:onafterStatus()
|
||||
self:F()
|
||||
|
||||
self:F( " Checking Status" )
|
||||
|
||||
if self.Controllable and self.Controllable:IsAlive() then
|
||||
|
||||
local RTB = false
|
||||
|
||||
local Fuel = self.Controllable:GetUnit(1):GetFuel()
|
||||
self:F({Fuel=Fuel})
|
||||
if Fuel < self.PatrolFuelTresholdPercentage then
|
||||
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
|
||||
local OldAIControllable = self.Controllable
|
||||
local AIControllableTemplate = self.Controllable:GetTemplate()
|
||||
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
|
||||
|
||||
if not self:Is( "Holding" ) and not self:Is( "Returning" ) then
|
||||
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
|
||||
self:F({DistanceFromHomeBase=DistanceFromHomeBase})
|
||||
|
||||
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
||||
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) )
|
||||
OldAIControllable:SetTask( TimedOrbitTask, 10 )
|
||||
if DistanceFromHomeBase > self.DisengageRadius then
|
||||
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" )
|
||||
self:Hold( 300 )
|
||||
RTB = false
|
||||
end
|
||||
end
|
||||
|
||||
if self:Is( "Fuel" ) or self:Is( "Damaged" ) or self:Is( "LostControl" ) then
|
||||
if DistanceFromHomeBase < 5000 then
|
||||
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" )
|
||||
self:Home( "Destroy" )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self:Fuel()
|
||||
RTB = true
|
||||
else
|
||||
if not self:Is( "Fuel" ) and not self:Is( "Home" ) then
|
||||
local Fuel = self.Controllable:GetFuel()
|
||||
self:F({Fuel=Fuel})
|
||||
if Fuel < self.PatrolFuelThresholdPercentage then
|
||||
if self.TankerName then
|
||||
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... Refuelling at Tanker!" )
|
||||
self:Refuel()
|
||||
else
|
||||
self:E( self.Controllable:GetName() .. " is out of fuel: " .. Fuel .. " ... RTB!" )
|
||||
local OldAIControllable = self.Controllable
|
||||
|
||||
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
||||
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) )
|
||||
OldAIControllable:SetTask( TimedOrbitTask, 10 )
|
||||
|
||||
self:Fuel()
|
||||
RTB = true
|
||||
end
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO: Check GROUP damage function.
|
||||
local Damage = self.Controllable:GetLife()
|
||||
local InitialLife = self.Controllable:GetLife0()
|
||||
self:F( { Damage = Damage, InitialLife = InitialLife, DamageTreshold = self.PatrolDamageTreshold } )
|
||||
if ( Damage / InitialLife ) < self.PatrolDamageTreshold then
|
||||
self:F( { Damage = Damage, InitialLife = InitialLife, DamageThreshold = self.PatrolDamageThreshold } )
|
||||
if ( Damage / InitialLife ) < self.PatrolDamageThreshold then
|
||||
self:E( self.Controllable:GetName() .. " is damaged: " .. Damage .. " ... RTB!" )
|
||||
self:Damaged()
|
||||
RTB = true
|
||||
self:SetStatusOff()
|
||||
end
|
||||
|
||||
-- Check if planes went RTB and are out of control.
|
||||
if self.Controllable:HasTask() == false then
|
||||
if not self:Is( "Started" ) and
|
||||
not self:Is( "Stopped" ) then
|
||||
not self:Is( "Stopped" ) and
|
||||
not self:Is( "Home" ) then
|
||||
if self.IdleCount >= 2 then
|
||||
self:E( self.Controllable:GetName() .. " control lost! " )
|
||||
self:LostControl()
|
||||
if Damage ~= InitialLife then
|
||||
self:Damaged()
|
||||
else
|
||||
self:E( self.Controllable:GetName() .. " control lost! " )
|
||||
self:LostControl()
|
||||
end
|
||||
else
|
||||
self.IdleCount = self.IdleCount + 1
|
||||
end
|
||||
@@ -418,7 +508,7 @@ function AI_A2A:onafterStatus()
|
||||
else
|
||||
self.IdleCount = 0
|
||||
end
|
||||
|
||||
|
||||
if RTB == true then
|
||||
self:__RTB( 0.5 )
|
||||
end
|
||||
@@ -429,13 +519,28 @@ end
|
||||
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_A2A.RTBRoute( AIGroup )
|
||||
function AI_A2A.RTBRoute( AIGroup, Fsm )
|
||||
|
||||
AIGroup:E( { "RTBRoute:", AIGroup:GetName() } )
|
||||
local _AI_A2A = AIGroup:GetState( AIGroup, "AI_A2A" ) -- #AI_A2A
|
||||
_AI_A2A:__RTB( 0.5 )
|
||||
AIGroup:F( { "AI_A2A.RTBRoute:", AIGroup:GetName() } )
|
||||
|
||||
if AIGroup:IsAlive() then
|
||||
Fsm:__RTB( 0.5 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_A2A.RTBHold( AIGroup, Fsm )
|
||||
|
||||
AIGroup:F( { "AI_A2A.RTBHold:", AIGroup:GetName() } )
|
||||
if AIGroup:IsAlive() then
|
||||
Fsm:__RTB( 0.5 )
|
||||
Fsm:Return()
|
||||
local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
|
||||
AIGroup:SetTask( Task )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2A self
|
||||
@@ -448,8 +553,6 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
|
||||
|
||||
self:E( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
|
||||
|
||||
self.CheckStatus = false
|
||||
|
||||
self:ClearTargetDistance()
|
||||
AIGroup:ClearTasks()
|
||||
|
||||
@@ -466,11 +569,12 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
|
||||
|
||||
local ToAirbaseCoord = CurrentCoord:Translate( 5000, ToAirbaseAngle )
|
||||
if Distance < 5000 then
|
||||
self:E( "RTB and near the airbase!" )
|
||||
self:Home()
|
||||
return
|
||||
end
|
||||
--- Create a route point of type air.
|
||||
local ToPatrolRoutePoint = ToAirbaseCoord:RoutePointAir(
|
||||
local ToRTBRoutePoint = ToAirbaseCoord:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -481,7 +585,8 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
|
||||
self:F( { Angle = ToAirbaseAngle, ToTargetSpeed = ToTargetSpeed } )
|
||||
self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } )
|
||||
|
||||
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
|
||||
EngageRoute[#EngageRoute+1] = ToRTBRoutePoint
|
||||
EngageRoute[#EngageRoute+1] = ToRTBRoutePoint
|
||||
|
||||
AIGroup:OptionROEHoldFire()
|
||||
AIGroup:OptionROTEvadeFire()
|
||||
@@ -490,13 +595,11 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
|
||||
AIGroup:WayPointInitialize( EngageRoute )
|
||||
|
||||
local Tasks = {}
|
||||
Tasks[#Tasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A.RTBRoute" )
|
||||
EngageRoute[1].task = AIGroup:TaskCombo( Tasks )
|
||||
|
||||
AIGroup:SetState( AIGroup, "AI_A2A", self )
|
||||
Tasks[#Tasks+1] = AIGroup:TaskFunction( "AI_A2A.RTBRoute", self )
|
||||
EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( Tasks )
|
||||
|
||||
--- NOW ROUTE THE GROUP!
|
||||
AIGroup:WayPointExecute( 1, 0 )
|
||||
AIGroup:Route( EngageRoute, 0.5 )
|
||||
|
||||
end
|
||||
|
||||
@@ -513,6 +616,89 @@ function AI_A2A:onafterHome( AIGroup, From, Event, To )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #AI_A2A self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_A2A:onafterHold( AIGroup, From, Event, To, HoldTime )
|
||||
self:F( { AIGroup, From, Event, To } )
|
||||
|
||||
self:E( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" )
|
||||
|
||||
if AIGroup and AIGroup:IsAlive() then
|
||||
local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
||||
local TimedOrbitTask = AIGroup:TaskControlled( OrbitTask, AIGroup:TaskCondition( nil, nil, nil, nil, HoldTime , nil ) )
|
||||
|
||||
local RTBTask = AIGroup:TaskFunction( "AI_A2A.RTBHold", self )
|
||||
|
||||
local OrbitHoldTask = AIGroup:TaskOrbitCircle( 4000, self.PatrolMinSpeed )
|
||||
|
||||
--AIGroup:SetState( AIGroup, "AI_A2A", self )
|
||||
|
||||
AIGroup:SetTask( AIGroup:TaskCombo( { TimedOrbitTask, RTBTask, OrbitHoldTask } ), 1 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_A2A.Resume( AIGroup, Fsm )
|
||||
|
||||
AIGroup:F( { "AI_A2A.Resume:", AIGroup:GetName() } )
|
||||
if AIGroup:IsAlive() then
|
||||
Fsm:__RTB( 0.5 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_A2A self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_A2A:onafterRefuel( 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
|
||||
local Tanker = GROUP:FindByName( self.TankerName )
|
||||
if Tanker:IsAlive() and Tanker:IsAirPlane() then
|
||||
|
||||
local RefuelRoute = {}
|
||||
|
||||
--- Calculate the target route point.
|
||||
|
||||
local CurrentCoord = AIGroup:GetCoordinate()
|
||||
local ToRefuelCoord = Tanker:GetCoordinate()
|
||||
local ToRefuelSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToRefuelRoutePoint = ToRefuelCoord:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
ToRefuelSpeed,
|
||||
true
|
||||
)
|
||||
|
||||
self:F( { ToRefuelSpeed = ToRefuelSpeed } )
|
||||
|
||||
RefuelRoute[#RefuelRoute+1] = ToRefuelRoutePoint
|
||||
RefuelRoute[#RefuelRoute+1] = ToRefuelRoutePoint
|
||||
|
||||
AIGroup:OptionROEHoldFire()
|
||||
AIGroup:OptionROTEvadeFire()
|
||||
|
||||
local Tasks = {}
|
||||
Tasks[#Tasks+1] = AIGroup:TaskRefueling()
|
||||
Tasks[#Tasks+1] = AIGroup:TaskFunction( self:GetClassName() .. ".Resume", self )
|
||||
RefuelRoute[#RefuelRoute].task = AIGroup:TaskCombo( Tasks )
|
||||
|
||||
AIGroup:Route( RefuelRoute, 0.5 )
|
||||
else
|
||||
self:RTB()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- AI CAP classes makes AI Controllables execute a Combat Air Patrol.
|
||||
-- AI CAP classes makes AI Groups execute a Combat Air Patrol.
|
||||
--
|
||||
-- There are the following types of CAP classes defined:
|
||||
--
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
--- # AI_A2A_CAP class, extends @{AI_CAP#AI_PATROL_ZONE}
|
||||
--
|
||||
-- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group}
|
||||
-- The AI_A2A_CAP class implements the core functions to patrol a @{Zone} by an AI @{Group} or @{Group}
|
||||
-- and automatically engage any airborne enemies that are within a certain range or within a certain zone.
|
||||
--
|
||||
-- 
|
||||
@@ -120,20 +120,20 @@ AI_A2A_CAP = {
|
||||
|
||||
--- Creates a new AI_A2A_CAP object
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
-- @param Wrapper.Group#GROUP AICap
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
|
||||
-- @param Dcs.DCSTypes#Speed EngageMinSpeed The minimum speed of the @{Controllable} in km/h when engaging a target.
|
||||
-- @param Dcs.DCSTypes#Speed EngageMaxSpeed The maximum speed of the @{Controllable} in km/h when engaging a target.
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
|
||||
-- @param Dcs.DCSTypes#Speed EngageMinSpeed The minimum speed of the @{Group} in km/h when engaging a target.
|
||||
-- @param Dcs.DCSTypes#Speed EngageMaxSpeed The maximum speed of the @{Group} in km/h when engaging a target.
|
||||
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
||||
-- @return #AI_A2A_CAP
|
||||
function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType )
|
||||
function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, EngageMinSpeed, EngageMaxSpeed, PatrolAltType )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2A_CAP
|
||||
local self = BASE:Inherit( self, AI_A2A_PATROL:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType ) ) -- #AI_A2A_CAP
|
||||
|
||||
self.Accomplished = false
|
||||
self.Engaging = false
|
||||
@@ -141,12 +141,12 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
self.EngageMinSpeed = EngageMinSpeed
|
||||
self.EngageMaxSpeed = EngageMaxSpeed
|
||||
|
||||
self:AddTransition( { "Patrolling", "Engaging", "Returning" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP.
|
||||
self:AddTransition( { "Patrolling", "Engaging", "Returning", "Airborne" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_CAP.
|
||||
|
||||
--- OnBefore Transition Handler for Event Engage.
|
||||
-- @function [parent=#AI_A2A_CAP] OnBeforeEngage
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -155,7 +155,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
--- OnAfter Transition Handler for Event Engage.
|
||||
-- @function [parent=#AI_A2A_CAP] OnAfterEngage
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -172,7 +172,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
--- OnLeave Transition Handler for State Engaging.
|
||||
-- @function [parent=#AI_A2A_CAP] OnLeaveEngaging
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -181,7 +181,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
--- OnEnter Transition Handler for State Engaging.
|
||||
-- @function [parent=#AI_A2A_CAP] OnEnterEngaging
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -191,7 +191,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
--- OnBefore Transition Handler for Event Fired.
|
||||
-- @function [parent=#AI_A2A_CAP] OnBeforeFired
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -200,7 +200,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
--- OnAfter Transition Handler for Event Fired.
|
||||
-- @function [parent=#AI_A2A_CAP] OnAfterFired
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -219,7 +219,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
--- OnBefore Transition Handler for Event Destroy.
|
||||
-- @function [parent=#AI_A2A_CAP] OnBeforeDestroy
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -228,7 +228,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
--- OnAfter Transition Handler for Event Destroy.
|
||||
-- @function [parent=#AI_A2A_CAP] OnAfterDestroy
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -248,7 +248,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
--- OnBefore Transition Handler for Event Abort.
|
||||
-- @function [parent=#AI_A2A_CAP] OnBeforeAbort
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -257,7 +257,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
--- OnAfter Transition Handler for Event Abort.
|
||||
-- @function [parent=#AI_A2A_CAP] OnAfterAbort
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -276,7 +276,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
--- OnBefore Transition Handler for Event Accomplish.
|
||||
-- @function [parent=#AI_A2A_CAP] OnBeforeAccomplish
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -285,7 +285,7 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
--- OnAfter Transition Handler for Event Accomplish.
|
||||
-- @function [parent=#AI_A2A_CAP] OnAfterAccomplish
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -302,6 +302,17 @@ function AI_A2A_CAP:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeiling
|
||||
return self
|
||||
end
|
||||
|
||||
--- onafter State Transition for Event Patrol.
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AICap The AI Group 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_A2A_CAP:onafterStart( AICap, From, Event, To )
|
||||
|
||||
AICap:HandleEvent( EVENTS.Takeoff, nil, self )
|
||||
|
||||
end
|
||||
|
||||
--- Set the Engage Zone which defines where the AI will engage bogies.
|
||||
-- @param #AI_A2A_CAP self
|
||||
@@ -333,33 +344,36 @@ end
|
||||
|
||||
--- onafter State Transition for Event Patrol.
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE AIGroup The AI Group managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The AI Group 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_A2A_CAP:onafterPatrol( AIGroup, From, Event, To )
|
||||
function AI_A2A_CAP:onafterPatrol( AICap, From, Event, To )
|
||||
|
||||
-- Call the parent Start event handler
|
||||
self:GetParent(self).onafterPatrol( self, AIGroup, From, Event, To )
|
||||
self:GetParent(self).onafterPatrol( self, AICap, From, Event, To )
|
||||
self:HandleEvent( EVENTS.Dead )
|
||||
|
||||
end
|
||||
|
||||
-- todo: need to fix this global function
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIGroup
|
||||
function AI_A2A_CAP.AttackRoute( AIGroup )
|
||||
--- @param Wrapper.Group#GROUP AICap
|
||||
function AI_A2A_CAP.AttackRoute( AICap, Fsm )
|
||||
|
||||
local EngageZone = AIGroup:GetState( AIGroup, "AI_A2A_CAP" ) -- AI.AI_Cap#AI_A2A_CAP
|
||||
EngageZone:__Engage( 0.5 )
|
||||
AICap:F( { "AI_A2A_CAP.AttackRoute:", AICap:GetName() } )
|
||||
|
||||
if AICap:IsAlive() then
|
||||
Fsm:__Engage( 0.5 )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE AIGroup The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object 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_A2A_CAP:onbeforeEngage( AIGroup, From, Event, To )
|
||||
function AI_A2A_CAP:onbeforeEngage( AICap, From, Event, To )
|
||||
|
||||
if self.Accomplished == true then
|
||||
return false
|
||||
@@ -367,43 +381,43 @@ function AI_A2A_CAP:onbeforeEngage( AIGroup, From, Event, To )
|
||||
end
|
||||
|
||||
--- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE AIGroup The AI Group managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The AI Group 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_A2A_CAP:onafterAbort( AIGroup, From, Event, To )
|
||||
AIGroup:ClearTasks()
|
||||
function AI_A2A_CAP:onafterAbort( AICap, From, Event, To )
|
||||
AICap:ClearTasks()
|
||||
self:__Route( 0.5 )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE AIGroup The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The AICap Object 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_A2A_CAP:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
|
||||
function AI_A2A_CAP:onafterEngage( AICap, From, Event, To, AttackSetUnit )
|
||||
|
||||
self:F( { AIGroup, From, Event, To, AttackSetUnit} )
|
||||
self:F( { AICap, From, Event, To, AttackSetUnit} )
|
||||
|
||||
self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT
|
||||
|
||||
local FirstAttackUnit = self.AttackSetUnit:GetFirst()
|
||||
local FirstAttackUnit = self.AttackSetUnit:GetFirst() -- Wrapper.Unit#UNIT
|
||||
|
||||
if FirstAttackUnit then
|
||||
if FirstAttackUnit and FirstAttackUnit:IsAlive() then -- If there is no attacker anymore, stop the engagement.
|
||||
|
||||
if AIGroup:IsAlive() then
|
||||
if AICap:IsAlive() then
|
||||
|
||||
local EngageRoute = {}
|
||||
|
||||
--- Calculate the target route point.
|
||||
local CurrentCoord = AIGroup:GetCoordinate()
|
||||
local CurrentCoord = AICap:GetCoordinate()
|
||||
local ToTargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
|
||||
local ToTargetSpeed = math.random( self.EngageMinSpeed, self.EngageMaxSpeed )
|
||||
local ToInterceptAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToPatrolRoutePoint = CurrentCoord:Translate( 5000, ToInterceptAngle ):RoutePointAir(
|
||||
local ToPatrolRoutePoint = CurrentCoord:Translate( 5000, ToInterceptAngle ):WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -414,40 +428,31 @@ function AI_A2A_CAP:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
|
||||
self:F( { Angle = ToInterceptAngle, ToTargetSpeed = ToTargetSpeed } )
|
||||
self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } )
|
||||
|
||||
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
|
||||
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
|
||||
|
||||
AIGroup:OptionROEOpenFire()
|
||||
AIGroup:OptionROTPassiveDefense()
|
||||
|
||||
local AttackTasks = {}
|
||||
|
||||
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
|
||||
local AttackUnit = AttackUnit -- Wrapper.Unit#UNIT
|
||||
self:T( { "Attacking Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } )
|
||||
if AttackUnit:IsAlive() and AttackUnit:IsAir() then
|
||||
AttackTasks[#AttackTasks+1] = AIGroup:TaskAttackUnit( AttackUnit )
|
||||
AttackTasks[#AttackTasks+1] = AICap:TaskAttackUnit( AttackUnit )
|
||||
end
|
||||
end
|
||||
|
||||
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
|
||||
self.Controllable:WayPointInitialize( EngageRoute )
|
||||
|
||||
|
||||
if #AttackTasks == 0 then
|
||||
self:E("No targets found -> Going back to Patrolling")
|
||||
self:__Abort( 0.5 )
|
||||
else
|
||||
AttackTasks[#AttackTasks+1] = AIGroup:TaskFunction( 1, #AttackTasks, "AI_A2A_CAP.AttackRoute" )
|
||||
AttackTasks[#AttackTasks+1] = AIGroup:TaskOrbitCircle( 4000, self.PatrolMinSpeed )
|
||||
|
||||
EngageRoute[1].task = AIGroup:TaskCombo( AttackTasks )
|
||||
|
||||
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
|
||||
AIGroup:SetState( AIGroup, "AI_A2A_CAP", self )
|
||||
AICap:OptionROEOpenFire()
|
||||
AICap:OptionROTEvadeFire()
|
||||
|
||||
AttackTasks[#AttackTasks+1] = AICap:TaskFunction( "AI_A2A_CAP.AttackRoute", self )
|
||||
EngageRoute[#EngageRoute].task = AICap:TaskCombo( AttackTasks )
|
||||
end
|
||||
|
||||
--- NOW ROUTE THE GROUP!
|
||||
AIGroup:WayPointExecute( 1, 0 )
|
||||
AICap:Route( EngageRoute, 0.5 )
|
||||
end
|
||||
else
|
||||
self:E("No targets found -> Going back to Patrolling")
|
||||
@@ -456,22 +461,22 @@ function AI_A2A_CAP:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
|
||||
end
|
||||
|
||||
--- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object 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_A2A_CAP:onafterAccomplish( Controllable, From, Event, To )
|
||||
function AI_A2A_CAP:onafterAccomplish( AICap, From, Event, To )
|
||||
self.Accomplished = true
|
||||
self:SetDetectionOff()
|
||||
end
|
||||
|
||||
--- @param #AI_A2A_CAP self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AICap The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_A2A_CAP:onafterDestroy( Controllable, From, Event, To, EventData )
|
||||
function AI_A2A_CAP:onafterDestroy( AICap, From, Event, To, EventData )
|
||||
|
||||
if EventData.IniUnit then
|
||||
self.AttackUnits[EventData.IniUnit] = nil
|
||||
@@ -489,3 +494,15 @@ function AI_A2A_CAP:OnEventDead( EventData )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AICap
|
||||
function AI_A2A_CAP.Resume( AICap )
|
||||
|
||||
AICap:F( { "AI_A2A_CAP.Resume:", AICap:GetName() } )
|
||||
if AICap:IsAlive() then
|
||||
local _AI_A2A = AICap:GetState( AICap, "AI_A2A" ) -- #AI_A2A
|
||||
_AI_A2A:__Reset( 1 )
|
||||
_AI_A2A:__Route( 5 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -117,12 +117,12 @@ AI_A2A_GCI = {
|
||||
|
||||
--- Creates a new AI_A2A_GCI object
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
-- @param Wrapper.Group#GROUP AIIntercept
|
||||
-- @return #AI_A2A_GCI
|
||||
function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, AI_A2A:New( AIGroup ) ) -- #AI_A2A_GCI
|
||||
local self = BASE:Inherit( self, AI_A2A:New( AIIntercept ) ) -- #AI_A2A_GCI
|
||||
|
||||
self.Accomplished = false
|
||||
self.Engaging = false
|
||||
@@ -134,12 +134,12 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
|
||||
self.PatrolAltType = "RADIO"
|
||||
|
||||
self:AddTransition( { "Started", "Engaging", "Returning" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI.
|
||||
self:AddTransition( { "Started", "Engaging", "Returning", "Airborne" }, "Engage", "Engaging" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_GCI.
|
||||
|
||||
--- OnBefore Transition Handler for Event Engage.
|
||||
-- @function [parent=#AI_A2A_GCI] OnBeforeEngage
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -148,7 +148,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
--- OnAfter Transition Handler for Event Engage.
|
||||
-- @function [parent=#AI_A2A_GCI] OnAfterEngage
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -165,7 +165,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
--- OnLeave Transition Handler for State Engaging.
|
||||
-- @function [parent=#AI_A2A_GCI] OnLeaveEngaging
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -174,7 +174,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
--- OnEnter Transition Handler for State Engaging.
|
||||
-- @function [parent=#AI_A2A_GCI] OnEnterEngaging
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -184,7 +184,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
--- OnBefore Transition Handler for Event Fired.
|
||||
-- @function [parent=#AI_A2A_GCI] OnBeforeFired
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -193,7 +193,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
--- OnAfter Transition Handler for Event Fired.
|
||||
-- @function [parent=#AI_A2A_GCI] OnAfterFired
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -212,7 +212,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
--- OnBefore Transition Handler for Event Destroy.
|
||||
-- @function [parent=#AI_A2A_GCI] OnBeforeDestroy
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -221,7 +221,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
--- OnAfter Transition Handler for Event Destroy.
|
||||
-- @function [parent=#AI_A2A_GCI] OnAfterDestroy
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -241,7 +241,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
--- OnBefore Transition Handler for Event Abort.
|
||||
-- @function [parent=#AI_A2A_GCI] OnBeforeAbort
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -250,7 +250,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
--- OnAfter Transition Handler for Event Abort.
|
||||
-- @function [parent=#AI_A2A_GCI] OnAfterAbort
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -269,7 +269,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
--- OnBefore Transition Handler for Event Accomplish.
|
||||
-- @function [parent=#AI_A2A_GCI] OnBeforeAccomplish
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -278,7 +278,7 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
--- OnAfter Transition Handler for Event Accomplish.
|
||||
-- @function [parent=#AI_A2A_GCI] OnAfterAccomplish
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -295,14 +295,27 @@ function AI_A2A_GCI:New( AIGroup, EngageMinSpeed, EngageMaxSpeed )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- onafter State Transition for Event Patrol.
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AI Group managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The AI Group 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_A2A_GCI:onafterEngage( AIGroup, From, Event, To )
|
||||
function AI_A2A_GCI:onafterStart( AIIntercept, From, Event, To )
|
||||
|
||||
AIIntercept:HandleEvent( EVENTS.Takeoff, nil, self )
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- onafter State Transition for Event Patrol.
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The AI Group 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_A2A_GCI:onafterEngage( AIIntercept, From, Event, To )
|
||||
|
||||
self:HandleEvent( EVENTS.Dead )
|
||||
|
||||
@@ -311,19 +324,24 @@ end
|
||||
-- todo: need to fix this global function
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIControllable
|
||||
function AI_A2A_GCI.InterceptRoute( AIControllable )
|
||||
function AI_A2A_GCI.InterceptRoute( AIIntercept, Fsm )
|
||||
|
||||
AIControllable:T( "NewEngageRoute" )
|
||||
local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cap#AI_A2A_GCI
|
||||
EngageZone:__Engage( 0.5 )
|
||||
AIIntercept:F( { "AI_A2A_GCI.InterceptRoute:", AIIntercept:GetName() } )
|
||||
|
||||
if AIIntercept:IsAlive() then
|
||||
Fsm:__Engage( 0.5 )
|
||||
|
||||
--local Task = AIIntercept:TaskOrbitCircle( 4000, 400 )
|
||||
--AIIntercept:SetTask( Task )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object 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_A2A_GCI:onbeforeEngage( AIGroup, From, Event, To )
|
||||
function AI_A2A_GCI:onbeforeEngage( AIIntercept, From, Event, To )
|
||||
|
||||
if self.Accomplished == true then
|
||||
return false
|
||||
@@ -331,39 +349,41 @@ function AI_A2A_GCI:onbeforeEngage( AIGroup, From, Event, To )
|
||||
end
|
||||
|
||||
--- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AI Group managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The AI Group 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_A2A_GCI:onafterAbort( AIGroup, From, Event, To )
|
||||
AIGroup:ClearTasks()
|
||||
function AI_A2A_GCI:onafterAbort( AIIntercept, From, Event, To )
|
||||
AIIntercept:ClearTasks()
|
||||
self:Return()
|
||||
self:__RTB( 0.5 )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept 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_A2A_GCI:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
|
||||
function AI_A2A_GCI:onafterEngage( AIIntercept, From, Event, To, AttackSetUnit )
|
||||
|
||||
self:F( { AIGroup, From, Event, To, AttackSetUnit} )
|
||||
self:F( { AIIntercept, From, Event, To, AttackSetUnit} )
|
||||
|
||||
self.AttackSetUnit = AttackSetUnit or self.AttackSetUnit -- Core.Set#SET_UNIT
|
||||
|
||||
local FirstAttackUnit = self.AttackSetUnit:GetFirst()
|
||||
|
||||
if FirstAttackUnit then
|
||||
if FirstAttackUnit and FirstAttackUnit:IsAlive() then
|
||||
|
||||
if AIGroup:IsAlive() then
|
||||
if AIIntercept:IsAlive() then
|
||||
|
||||
local EngageRoute = {}
|
||||
|
||||
local CurrentCoord = AIIntercept:GetCoordinate()
|
||||
|
||||
--- Calculate the target route point.
|
||||
|
||||
local CurrentCoord = AIGroup:GetCoordinate()
|
||||
local CurrentCoord = AIIntercept:GetCoordinate()
|
||||
|
||||
local ToTargetCoord = self.AttackSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
|
||||
@@ -372,7 +392,7 @@ function AI_A2A_GCI:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
|
||||
local ToInterceptAngle = CurrentCoord:GetAngleDegrees( CurrentCoord:GetDirectionVec3( ToTargetCoord ) )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToPatrolRoutePoint = CurrentCoord:Translate( 5000, ToInterceptAngle ):RoutePointAir(
|
||||
local ToPatrolRoutePoint = CurrentCoord:Translate( 15000, ToInterceptAngle ):WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -381,42 +401,34 @@ function AI_A2A_GCI:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
|
||||
)
|
||||
|
||||
self:F( { Angle = ToInterceptAngle, ToTargetSpeed = ToTargetSpeed } )
|
||||
self:T2( { self.EngageMinSpeed, self.EngageMaxSpeed, ToTargetSpeed } )
|
||||
self:F( { self.EngageMinSpeed, self.EngageMaxSpeed, ToTargetSpeed } )
|
||||
|
||||
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
|
||||
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
|
||||
|
||||
AIGroup:OptionROEOpenFire()
|
||||
AIGroup:OptionROTPassiveDefense()
|
||||
|
||||
local AttackTasks = {}
|
||||
|
||||
for AttackUnitID, AttackUnit in pairs( self.AttackSetUnit:GetSet() ) do
|
||||
local AttackUnit = AttackUnit -- Wrapper.Unit#UNIT
|
||||
self:T( { "Intercepting Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } )
|
||||
if AttackUnit:IsAlive() and AttackUnit:IsAir() then
|
||||
AttackTasks[#AttackTasks+1] = AIGroup:TaskAttackUnit( AttackUnit )
|
||||
self:T( { "Intercepting Unit:", AttackUnit:GetName(), AttackUnit:IsAlive(), AttackUnit:IsAir() } )
|
||||
AttackTasks[#AttackTasks+1] = AIIntercept:TaskAttackUnit( AttackUnit )
|
||||
end
|
||||
end
|
||||
|
||||
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
|
||||
AIGroup:WayPointInitialize( EngageRoute )
|
||||
|
||||
|
||||
|
||||
if #AttackTasks == 0 then
|
||||
self:E("No targets found -> Going RTB")
|
||||
self:Return()
|
||||
self:__RTB( 0.5 )
|
||||
else
|
||||
AttackTasks[#AttackTasks+1] = AIGroup:TaskFunction( 1, #AttackTasks, "AI_A2A_GCI.InterceptRoute" )
|
||||
AttackTasks[#AttackTasks+1] = AIGroup:TaskOrbitCircle( 4000, self.EngageMinSpeed )
|
||||
EngageRoute[1].task = AIGroup:TaskCombo( AttackTasks )
|
||||
|
||||
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
|
||||
AIGroup:SetState( AIGroup, "EngageZone", self )
|
||||
AIIntercept:OptionROEOpenFire()
|
||||
AIIntercept:OptionROTEvadeFire()
|
||||
|
||||
AttackTasks[#AttackTasks+1] = AIIntercept:TaskFunction( "AI_A2A_GCI.InterceptRoute", self )
|
||||
EngageRoute[#EngageRoute].task = AIIntercept:TaskCombo( AttackTasks )
|
||||
end
|
||||
|
||||
--- NOW ROUTE THE GROUP!
|
||||
AIGroup:WayPointExecute( 1, 0 )
|
||||
AIIntercept:Route( EngageRoute, 0.5 )
|
||||
|
||||
end
|
||||
else
|
||||
@@ -427,22 +439,22 @@ function AI_A2A_GCI:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
|
||||
end
|
||||
|
||||
--- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object 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_A2A_GCI:onafterAccomplish( AIGroup, From, Event, To )
|
||||
function AI_A2A_GCI:onafterAccomplish( AIIntercept, From, Event, To )
|
||||
self.Accomplished = true
|
||||
self:SetDetectionOff()
|
||||
end
|
||||
|
||||
--- @param #AI_A2A_GCI self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIIntercept The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function AI_A2A_GCI:onafterDestroy( AIGroup, From, Event, To, EventData )
|
||||
function AI_A2A_GCI:onafterDestroy( AIIntercept, From, Event, To, EventData )
|
||||
|
||||
if EventData.IniUnit then
|
||||
self.AttackUnits[EventData.IniUnit] = nil
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- AI PATROL classes makes AI Controllables execute an Patrol.
|
||||
-- AI PATROL classes makes AI Groups execute an Patrol.
|
||||
--
|
||||
-- There are the following types of PATROL classes defined:
|
||||
--
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
--- # AI_A2A_PATROL class, extends @{Fsm#FSM_CONTROLLABLE}
|
||||
--
|
||||
-- The AI_A2A_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Controllable} or @{Group}.
|
||||
-- The AI_A2A_PATROL class implements the core functions to patrol a @{Zone} by an AI @{Group} or @{Group}.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
@@ -120,7 +120,7 @@
|
||||
-- * @{#AI_A2A_PATROL.SetDetectionOn}(): Set the detection on. The AI will detect for targets.
|
||||
-- * @{#AI_A2A_PATROL.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased.
|
||||
--
|
||||
-- The detection frequency can be set with @{#AI_A2A_PATROL.SetDetectionInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
|
||||
-- The detection frequency can be set with @{#AI_A2A_PATROL.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
|
||||
-- Use the method @{#AI_A2A_PATROL.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI.
|
||||
--
|
||||
-- The detection can be filtered to potential targets in a specific zone.
|
||||
@@ -139,7 +139,7 @@
|
||||
--
|
||||
-- ## 7. Manage "damage" behaviour of the AI in the AI_A2A_PATROL
|
||||
--
|
||||
-- When the AI is damaged, it is required that a new AIControllable is started. However, damage cannon be foreseen early on.
|
||||
-- When the AI is damaged, it is required that a new Patrol is started. However, damage cannon be foreseen early on.
|
||||
-- Therefore, when the damage treshold is reached, the AI will return immediately to the home base (RTB).
|
||||
-- Use the method @{#AI_A2A_PATROL.ManageDamage}() to have this proces in place.
|
||||
--
|
||||
@@ -152,23 +152,23 @@ AI_A2A_PATROL = {
|
||||
|
||||
--- Creates a new AI_A2A_PATROL object
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIGroup
|
||||
-- @param Wrapper.Group#GROUP AIPatrol
|
||||
-- @param Core.Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
|
||||
-- @param Dcs.DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
|
||||
-- @param Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
|
||||
-- @param Dcs.DCSTypes#AltitudeType PatrolAltType The altitude type ("RADIO"=="AGL", "BARO"=="ASL"). Defaults to RADIO
|
||||
-- @return #AI_A2A_PATROL self
|
||||
-- @usage
|
||||
-- -- Define a new AI_A2A_PATROL Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
|
||||
-- -- Define a new AI_A2A_PATROL Object. This PatrolArea will patrol a Group within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
|
||||
-- PatrolZone = ZONE:New( 'PatrolZone' )
|
||||
-- PatrolSpawn = SPAWN:New( 'Patrol Group' )
|
||||
-- PatrolArea = AI_A2A_PATROL:New( PatrolZone, 3000, 6000, 600, 900 )
|
||||
function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
function AI_A2A_PATROL:New( AIPatrol, PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed, PatrolAltType )
|
||||
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, AI_A2A:New( AIGroup ) ) -- #AI_A2A_PATROL
|
||||
local self = BASE:Inherit( self, AI_A2A:New( AIPatrol ) ) -- #AI_A2A_PATROL
|
||||
|
||||
self.PatrolZone = PatrolZone
|
||||
self.PatrolFloorAltitude = PatrolFloorAltitude
|
||||
@@ -179,12 +179,12 @@ function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeil
|
||||
-- defafult PatrolAltType to "RADIO" if not specified
|
||||
self.PatrolAltType = PatrolAltType or "RADIO"
|
||||
|
||||
self:AddTransition( "Started", "Patrol", "Patrolling" )
|
||||
self:AddTransition( { "Started", "Airborne", "Refuelling" }, "Patrol", "Patrolling" )
|
||||
|
||||
--- OnBefore Transition Handler for Event Patrol.
|
||||
-- @function [parent=#AI_A2A_PATROL] OnBeforePatrol
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -193,7 +193,7 @@ function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeil
|
||||
--- OnAfter Transition Handler for Event Patrol.
|
||||
-- @function [parent=#AI_A2A_PATROL] OnAfterPatrol
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -210,7 +210,7 @@ function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeil
|
||||
--- OnLeave Transition Handler for State Patrolling.
|
||||
-- @function [parent=#AI_A2A_PATROL] OnLeavePatrolling
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -219,7 +219,7 @@ function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeil
|
||||
--- OnEnter Transition Handler for State Patrolling.
|
||||
-- @function [parent=#AI_A2A_PATROL] OnEnterPatrolling
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -229,7 +229,7 @@ function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeil
|
||||
--- OnBefore Transition Handler for Event Route.
|
||||
-- @function [parent=#AI_A2A_PATROL] OnBeforeRoute
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -238,7 +238,7 @@ function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeil
|
||||
--- OnAfter Transition Handler for Event Route.
|
||||
-- @function [parent=#AI_A2A_PATROL] OnAfterRoute
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
@@ -252,6 +252,8 @@ function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeil
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
|
||||
|
||||
self:AddTransition( "*", "Reset", "Patrolling" ) -- FSM_CONTROLLABLE Transition for type #AI_A2A_PATROL.
|
||||
|
||||
return self
|
||||
@@ -262,8 +264,8 @@ end
|
||||
|
||||
--- Sets (modifies) the minimum and maximum speed of the patrol.
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
|
||||
-- @param Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
|
||||
-- @return #AI_A2A_PATROL self
|
||||
function AI_A2A_PATROL:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
|
||||
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
|
||||
@@ -290,18 +292,18 @@ end
|
||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @return #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group Object 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_A2A_PATROL:onafterPatrol( Controllable, From, Event, To )
|
||||
function AI_A2A_PATROL:onafterPatrol( AIPatrol, From, Event, To )
|
||||
self:F2()
|
||||
|
||||
self:ClearTargetDistance()
|
||||
|
||||
self:__Route( 1 )
|
||||
|
||||
self.Controllable:OnReSpawn(
|
||||
AIPatrol:OnReSpawn(
|
||||
function( PatrolGroup )
|
||||
self:E( "ReSpawn" )
|
||||
self:__Reset( 1 )
|
||||
@@ -312,23 +314,27 @@ end
|
||||
|
||||
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIGroup
|
||||
-- This statis method is called from the route path within the last task at the last waaypoint of the Controllable.
|
||||
-- Note that this method is required, as triggers the next route when patrolling for the Controllable.
|
||||
function AI_A2A_PATROL.PatrolRoute( AIGroup )
|
||||
--- @param Wrapper.Group#GROUP AIPatrol
|
||||
-- This statis method is called from the route path within the last task at the last waaypoint of the AIPatrol.
|
||||
-- Note that this method is required, as triggers the next route when patrolling for the AIPatrol.
|
||||
function AI_A2A_PATROL.PatrolRoute( AIPatrol, Fsm )
|
||||
|
||||
local _AI_A2A_Patrol = AIGroup:GetState( AIGroup, "AI_A2A_PATROL" ) -- #AI_A2A_PATROL
|
||||
_AI_A2A_Patrol:Route()
|
||||
AIPatrol:F( { "AI_A2A_PATROL.PatrolRoute:", AIPatrol:GetName() } )
|
||||
|
||||
if AIPatrol:IsAlive() then
|
||||
Fsm:Route()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
||||
-- @param #AI_A2A_PATROL self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The AIGroup managed by the FSM.
|
||||
-- @param Wrapper.Group#GROUP AIPatrol The Group 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_A2A_PATROL:onafterRoute( AIGroup, From, Event, To )
|
||||
function AI_A2A_PATROL:onafterRoute( AIPatrol, From, Event, To )
|
||||
|
||||
self:F2()
|
||||
|
||||
@@ -338,22 +344,22 @@ function AI_A2A_PATROL:onafterRoute( AIGroup, From, Event, To )
|
||||
end
|
||||
|
||||
|
||||
if AIGroup:IsAlive() then
|
||||
if AIPatrol:IsAlive() then
|
||||
|
||||
local PatrolRoute = {}
|
||||
|
||||
--- Calculate the target route point.
|
||||
|
||||
local CurrentCoord = AIGroup:GetCoordinate()
|
||||
local CurrentCoord = AIPatrol:GetCoordinate()
|
||||
|
||||
local ToTargetCoord = self.PatrolZone:GetRandomPointVec2()
|
||||
ToTargetCoord:SetAlt(math.random( self.PatrolFloorAltitude,self.PatrolCeilingAltitude ) )
|
||||
ToTargetCoord:SetAlt( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ) )
|
||||
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
|
||||
|
||||
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToPatrolRoutePoint = ToTargetCoord:RoutePointAir(
|
||||
local ToPatrolRoutePoint = ToTargetCoord:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -361,22 +367,29 @@ function AI_A2A_PATROL:onafterRoute( AIGroup, From, Event, To )
|
||||
true
|
||||
)
|
||||
|
||||
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
|
||||
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
|
||||
|
||||
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
|
||||
AIGroup:WayPointInitialize( PatrolRoute )
|
||||
|
||||
local Tasks = {}
|
||||
Tasks[#Tasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A_PATROL.PatrolRoute" )
|
||||
Tasks[#Tasks+1] = AIPatrol:TaskFunction( "AI_A2A_PATROL.PatrolRoute", self )
|
||||
PatrolRoute[#PatrolRoute].task = AIPatrol:TaskCombo( Tasks )
|
||||
|
||||
PatrolRoute[1].task = AIGroup:TaskCombo( Tasks )
|
||||
|
||||
--- Do a trick, link the NewPatrolRoute function of the PATROLGROUP object to the AIControllable in a temporary variable ...
|
||||
AIGroup:SetState( AIGroup, "AI_A2A_PATROL", self )
|
||||
AIPatrol:OptionROEReturnFire()
|
||||
AIPatrol:OptionROTEvadeFire()
|
||||
|
||||
--- NOW ROUTE THE GROUP!
|
||||
AIGroup:WayPointExecute( 1, 2 )
|
||||
AIPatrol:Route( PatrolRoute, 0.5 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIPatrol
|
||||
function AI_A2A_PATROL.Resume( AIPatrol )
|
||||
|
||||
AIPatrol:F( { "AI_A2A_PATROL.Resume:", AIPatrol:GetName() } )
|
||||
if AIPatrol:IsAlive() then
|
||||
local _AI_A2A = AIPatrol:GetState( AIPatrol, "AI_A2A" ) -- #AI_A2A
|
||||
_AI_A2A:__Reset( 1 )
|
||||
_AI_A2A:__Route( 5 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -531,7 +531,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -588,7 +588,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -612,7 +612,7 @@ function AI_BAI_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
--- NOW ROUTE THE GROUP!
|
||||
Controllable:WayPointExecute( 1 )
|
||||
|
||||
self:SetDetectionInterval( 2 )
|
||||
self:SetRefreshTimeInterval( 2 )
|
||||
self:SetDetectionActivated()
|
||||
self:__Target( -2 ) -- Start Targetting
|
||||
end
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
--- @type AI_BALANCER
|
||||
-- @field Core.Set#SET_CLIENT SetClient
|
||||
-- @field Functional.Spawn#SPAWN SpawnAI
|
||||
-- @field Core.Spawn#SPAWN SpawnAI
|
||||
-- @field Wrapper.Group#GROUP Test
|
||||
-- @extends Core.Fsm#FSM_SET
|
||||
|
||||
@@ -106,7 +106,7 @@ AI_BALANCER = {
|
||||
--- Creates a new AI_BALANCER object
|
||||
-- @param #AI_BALANCER self
|
||||
-- @param Core.Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player).
|
||||
-- @param Functional.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed.
|
||||
-- @param Core.Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed.
|
||||
-- @return #AI_BALANCER
|
||||
function AI_BALANCER:New( SetClient, SpawnAI )
|
||||
|
||||
@@ -151,22 +151,22 @@ end
|
||||
|
||||
--- Returns the AI to the nearest friendly @{Airbase#AIRBASE}.
|
||||
-- @param #AI_BALANCER self
|
||||
-- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
|
||||
-- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
|
||||
-- @param Core.Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Set#SET_AIRBASE}s to evaluate where to return to.
|
||||
function AI_BALANCER:ReturnToNearestAirbases( ReturnTresholdRange, ReturnAirbaseSet )
|
||||
function AI_BALANCER:ReturnToNearestAirbases( ReturnThresholdRange, ReturnAirbaseSet )
|
||||
|
||||
self.ToNearestAirbase = true
|
||||
self.ReturnTresholdRange = ReturnTresholdRange
|
||||
self.ReturnThresholdRange = ReturnThresholdRange
|
||||
self.ReturnAirbaseSet = ReturnAirbaseSet
|
||||
end
|
||||
|
||||
--- Returns the AI to the home @{Airbase#AIRBASE}.
|
||||
-- @param #AI_BALANCER self
|
||||
-- @param Dcs.DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
|
||||
function AI_BALANCER:ReturnToHomeAirbase( ReturnTresholdRange )
|
||||
-- @param Dcs.DCSTypes#Distance ReturnThresholdRange If there is an enemy @{Client#CLIENT} within the ReturnThresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}.
|
||||
function AI_BALANCER:ReturnToHomeAirbase( ReturnThresholdRange )
|
||||
|
||||
self.ToHomeAirbase = true
|
||||
self.ReturnTresholdRange = ReturnTresholdRange
|
||||
self.ReturnThresholdRange = ReturnThresholdRange
|
||||
end
|
||||
|
||||
--- @param #AI_BALANCER self
|
||||
@@ -246,12 +246,12 @@ function AI_BALANCER:onenterMonitoring( SetGroup )
|
||||
if self.ToNearestAirbase == false and self.ToHomeAirbase == false then
|
||||
self:Destroy( Client.UnitName, AIGroup )
|
||||
else
|
||||
-- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group.
|
||||
-- We test if there is no other CLIENT within the self.ReturnThresholdRange of the first unit of the AI group.
|
||||
-- If there is a CLIENT, the AI stays engaged and will not return.
|
||||
-- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected.
|
||||
-- If there is no CLIENT within the self.ReturnThresholdRange, then the unit will return to the Airbase return method selected.
|
||||
|
||||
local PlayerInRange = { Value = false }
|
||||
local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange )
|
||||
local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnThresholdRange )
|
||||
|
||||
self:T2( RangeZone )
|
||||
|
||||
|
||||
@@ -358,16 +358,20 @@ function AI_CAP_ZONE:onafterStart( Controllable, From, Event, To )
|
||||
|
||||
end
|
||||
|
||||
-- todo: need to fix this global function
|
||||
|
||||
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
|
||||
function _NewEngageCapRoute( AIControllable )
|
||||
--- @param AI.AI_CAP#AI_CAP_ZONE
|
||||
-- @param Wrapper.Group#GROUP EngageGroup
|
||||
function AI_CAP_ZONE.EngageRoute( EngageGroup, Fsm )
|
||||
|
||||
AIControllable:T( "NewEngageRoute" )
|
||||
local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cap#AI_CAP_ZONE
|
||||
EngageZone:__Engage( 1 )
|
||||
EngageGroup:F( { "AI_CAP_ZONE.EngageRoute:", EngageGroup:GetName() } )
|
||||
|
||||
if EngageGroup:IsAlive() then
|
||||
Fsm:__Engage( 1 )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #AI_CAP_ZONE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable The Controllable Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
@@ -402,7 +406,7 @@ function AI_CAP_ZONE:onafterDetected( Controllable, From, Event, To )
|
||||
end
|
||||
|
||||
if Engage == true then
|
||||
self:E( 'Detected -> Engaging' )
|
||||
self:F( 'Detected -> Engaging' )
|
||||
self:__Engage( 1 )
|
||||
end
|
||||
end
|
||||
@@ -440,7 +444,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -464,7 +468,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToPatrolRoutePoint = ToTargetPointVec3:RoutePointAir(
|
||||
local ToPatrolRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -475,7 +479,7 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
||||
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
|
||||
|
||||
Controllable:OptionROEOpenFire()
|
||||
Controllable:OptionROTPassiveDefense()
|
||||
Controllable:OptionROTEvadeFire()
|
||||
|
||||
local AttackTasks = {}
|
||||
|
||||
@@ -485,13 +489,13 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
||||
if DetectedUnit:IsAlive() and DetectedUnit:IsAir() then
|
||||
if self.EngageZone then
|
||||
if DetectedUnit:IsInZone( self.EngageZone ) then
|
||||
self:E( {"Within Zone and Engaging ", DetectedUnit } )
|
||||
self:F( {"Within Zone and Engaging ", DetectedUnit } )
|
||||
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit )
|
||||
end
|
||||
else
|
||||
if self.EngageRange then
|
||||
if DetectedUnit:GetPointVec3():Get2DDistance(Controllable:GetPointVec3() ) <= self.EngageRange then
|
||||
self:E( {"Within Range and Engaging", DetectedUnit } )
|
||||
self:F( {"Within Range and Engaging", DetectedUnit } )
|
||||
AttackTasks[#AttackTasks+1] = Controllable:TaskAttackUnit( DetectedUnit )
|
||||
end
|
||||
else
|
||||
@@ -503,28 +507,20 @@ function AI_CAP_ZONE:onafterEngage( Controllable, From, Event, To )
|
||||
end
|
||||
end
|
||||
|
||||
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
|
||||
self.Controllable:WayPointInitialize( EngageRoute )
|
||||
|
||||
|
||||
if #AttackTasks == 0 then
|
||||
self:E("No targets found -> Going back to Patrolling")
|
||||
self:F("No targets found -> Going back to Patrolling")
|
||||
self:__Abort( 1 )
|
||||
self:__Route( 1 )
|
||||
self:SetDetectionActivated()
|
||||
else
|
||||
|
||||
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAP_ZONE.EngageRoute", self )
|
||||
EngageRoute[1].task = Controllable:TaskCombo( AttackTasks )
|
||||
|
||||
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
|
||||
self.Controllable:SetState( self.Controllable, "EngageZone", self )
|
||||
|
||||
self.Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageCapRoute" )
|
||||
|
||||
self:SetDetectionDeactivated()
|
||||
end
|
||||
|
||||
--- NOW ROUTE THE GROUP!
|
||||
self.Controllable:WayPointExecute( 1, 2 )
|
||||
Controllable:Route( EngageRoute, 0.5 )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -373,12 +373,15 @@ function AI_CAS_ZONE:onafterStart( Controllable, From, Event, To )
|
||||
self:SetDetectionDeactivated() -- When not engaging, set the detection off.
|
||||
end
|
||||
|
||||
--- @param Wrapper.Controllable#CONTROLLABLE AIControllable
|
||||
function _NewEngageRoute( AIControllable )
|
||||
--- @param AI.AI_CAS#AI_CAS_ZONE
|
||||
-- @param Wrapper.Group#GROUP EngageGroup
|
||||
function AI_CAS_ZONE.EngageRoute( EngageGroup, Fsm )
|
||||
|
||||
AIControllable:T( "NewEngageRoute" )
|
||||
local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cas#AI_CAS_ZONE
|
||||
EngageZone:__Engage( 1, EngageZone.EngageSpeed, EngageZone.EngageAltitude, EngageZone.EngageWeaponExpend, EngageZone.EngageAttackQty, EngageZone.EngageDirection )
|
||||
EngageGroup:F( { "AI_CAS_ZONE.EngageRoute:", EngageGroup:GetName() } )
|
||||
|
||||
if EngageGroup:IsAlive() then
|
||||
Fsm:__Engage( 1, Fsm.EngageSpeed, Fsm.EngageAltitude, Fsm.EngageWeaponExpend, Fsm.EngageAttackQty, Fsm.EngageDirection )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -464,6 +467,9 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
|
||||
if Controllable:IsAlive() then
|
||||
|
||||
Controllable:OptionROEOpenFire()
|
||||
Controllable:OptionROTVertical()
|
||||
|
||||
local EngageRoute = {}
|
||||
|
||||
--- Calculate the current route point.
|
||||
@@ -473,7 +479,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToEngageZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -485,7 +491,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
|
||||
local AttackTasks = {}
|
||||
|
||||
for DetectedUnitID, DetectedUnit in pairs( self.DetectedUnits ) do
|
||||
for DetectedUnit, Detected in pairs( self.DetectedUnits ) do
|
||||
local DetectedUnit = DetectedUnit -- Wrapper.Unit#UNIT
|
||||
self:T( DetectedUnit )
|
||||
if DetectedUnit:IsAlive() then
|
||||
@@ -503,7 +509,8 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
end
|
||||
end
|
||||
|
||||
EngageRoute[1].task = Controllable:TaskCombo( AttackTasks )
|
||||
AttackTasks[#AttackTasks+1] = Controllable:TaskFunction( "AI_CAS_ZONE.EngageRoute", self )
|
||||
EngageRoute[#EngageRoute].task = Controllable:TaskCombo( AttackTasks )
|
||||
|
||||
--- Define a random point in the @{Zone}. The AI will fly to that point within the zone.
|
||||
|
||||
@@ -515,7 +522,7 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, self.EngageAltitude, ToTargetVec2.y )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -524,22 +531,10 @@ function AI_CAS_ZONE:onafterEngage( Controllable, From, Event, To,
|
||||
)
|
||||
|
||||
EngageRoute[#EngageRoute+1] = ToTargetRoutePoint
|
||||
|
||||
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
|
||||
Controllable:WayPointInitialize( EngageRoute )
|
||||
|
||||
Controllable:Route( EngageRoute, 0.5 )
|
||||
|
||||
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
|
||||
Controllable:SetState( Controllable, "EngageZone", self )
|
||||
|
||||
Controllable:WayPointFunction( #EngageRoute, 1, "_NewEngageRoute" )
|
||||
|
||||
--- NOW ROUTE THE GROUP!
|
||||
Controllable:WayPointExecute( 1 )
|
||||
|
||||
Controllable:OptionROEOpenFire()
|
||||
Controllable:OptionROTVertical()
|
||||
|
||||
self:SetDetectionInterval( 2 )
|
||||
self:SetRefreshTimeInterval( 2 )
|
||||
self:SetDetectionActivated()
|
||||
self:__Target( -2 ) -- Start Targetting
|
||||
end
|
||||
|
||||
@@ -958,7 +958,7 @@ function AI_FORMATION:onenterFollowing( FollowGroupSet ) --R2.1
|
||||
-- @param Wrapper.Unit#UNIT ClientUnit
|
||||
function( FollowGroup, Formation, ClientUnit, CT1, CV1, CT2, CV2 )
|
||||
|
||||
FollowGroup:OptionROTPassiveDefense()
|
||||
FollowGroup:OptionROTEvadeFire()
|
||||
FollowGroup:OptionROEReturnFire()
|
||||
|
||||
local GroupUnit = FollowGroup:GetUnit( 1 )
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
-- @field Dcs.DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
|
||||
-- @field Dcs.DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
|
||||
-- @field Dcs.DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
|
||||
-- @field Functional.Spawn#SPAWN CoordTest
|
||||
-- @field Core.Spawn#SPAWN CoordTest
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
|
||||
--- # AI_PATROL_ZONE class, extends @{Fsm#FSM_CONTROLLABLE}
|
||||
@@ -128,7 +128,7 @@
|
||||
-- * @{#AI_PATROL_ZONE.SetDetectionOn}(): Set the detection on. The AI will detect for targets.
|
||||
-- * @{#AI_PATROL_ZONE.SetDetectionOff}(): Set the detection off, the AI will not detect for targets. The existing target list will NOT be erased.
|
||||
--
|
||||
-- The detection frequency can be set with @{#AI_PATROL_ZONE.SetDetectionInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
|
||||
-- The detection frequency can be set with @{#AI_PATROL_ZONE.SetRefreshTimeInterval}( seconds ), where the amount of seconds specify how much seconds will be waited before the next detection.
|
||||
-- Use the method @{#AI_PATROL_ZONE.GetDetectedUnits}() to obtain a list of the @{Unit}s detected by the AI.
|
||||
--
|
||||
-- The detection can be filtered to potential targets in a specific zone.
|
||||
@@ -187,7 +187,7 @@ function AI_PATROL_ZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltit
|
||||
-- defafult PatrolAltType to "RADIO" if not specified
|
||||
self.PatrolAltType = PatrolAltType or "RADIO"
|
||||
|
||||
self:SetDetectionInterval( 30 )
|
||||
self:SetRefreshTimeInterval( 30 )
|
||||
|
||||
self.CheckStatus = true
|
||||
|
||||
@@ -544,7 +544,7 @@ end
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @param #number Seconds The interval in seconds.
|
||||
-- @return #AI_PATROL_ZONE self
|
||||
function AI_PATROL_ZONE:SetDetectionInterval( Seconds )
|
||||
function AI_PATROL_ZONE:SetRefreshTimeInterval( Seconds )
|
||||
self:F2()
|
||||
|
||||
if Seconds then
|
||||
@@ -591,13 +591,13 @@ end
|
||||
-- When the fuel treshold is reached, the AI will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI_PATROL_ZONE.
|
||||
-- Once the time is finished, the old AI will return to the base.
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
||||
-- @param #number PatrolFuelThresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
|
||||
-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
|
||||
-- @return #AI_PATROL_ZONE self
|
||||
function AI_PATROL_ZONE:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime )
|
||||
function AI_PATROL_ZONE:ManageFuel( PatrolFuelThresholdPercentage, PatrolOutOfFuelOrbitTime )
|
||||
|
||||
self.PatrolManageFuel = true
|
||||
self.PatrolFuelTresholdPercentage = PatrolFuelTresholdPercentage
|
||||
self.PatrolFuelThresholdPercentage = PatrolFuelThresholdPercentage
|
||||
self.PatrolOutOfFuelOrbitTime = PatrolOutOfFuelOrbitTime
|
||||
|
||||
return self
|
||||
@@ -610,12 +610,12 @@ end
|
||||
-- Note that for groups, the average damage of the complete group will be calculated.
|
||||
-- So, in a group of 4 airplanes, 2 lost and 2 with damage 0.2, the damage treshold will be 0.25.
|
||||
-- @param #AI_PATROL_ZONE self
|
||||
-- @param #number PatrolDamageTreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
|
||||
-- @param #number PatrolDamageThreshold The treshold in percentage (between 0 and 1) when the AI is considered to be damaged.
|
||||
-- @return #AI_PATROL_ZONE self
|
||||
function AI_PATROL_ZONE:ManageDamage( PatrolDamageTreshold )
|
||||
function AI_PATROL_ZONE:ManageDamage( PatrolDamageThreshold )
|
||||
|
||||
self.PatrolManageDamage = true
|
||||
self.PatrolDamageTreshold = PatrolDamageTreshold
|
||||
self.PatrolDamageThreshold = PatrolDamageThreshold
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -748,7 +748,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TakeOffParking,
|
||||
POINT_VEC3.RoutePointAction.FromParkingArea,
|
||||
@@ -763,7 +763,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -789,7 +789,7 @@ function AI_PATROL_ZONE:onafterRoute( Controllable, From, Event, To )
|
||||
local ToTargetPointVec3 = POINT_VEC3:New( ToTargetVec2.x, ToTargetAltitude, ToTargetVec2.y )
|
||||
|
||||
--- Create a route point of type air.
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:RoutePointAir(
|
||||
local ToTargetRoutePoint = ToTargetPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
@@ -831,10 +831,9 @@ function AI_PATROL_ZONE:onafterStatus()
|
||||
local RTB = false
|
||||
|
||||
local Fuel = self.Controllable:GetUnit(1):GetFuel()
|
||||
if Fuel < self.PatrolFuelTresholdPercentage then
|
||||
if Fuel < self.PatrolFuelThresholdPercentage then
|
||||
self:E( self.Controllable:GetName() .. " is out of fuel:" .. Fuel .. ", RTB!" )
|
||||
local OldAIControllable = self.Controllable
|
||||
local AIControllableTemplate = self.Controllable:GetTemplate()
|
||||
|
||||
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
|
||||
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) )
|
||||
@@ -846,7 +845,7 @@ function AI_PATROL_ZONE:onafterStatus()
|
||||
|
||||
-- TODO: Check GROUP damage function.
|
||||
local Damage = self.Controllable:GetLife()
|
||||
if Damage <= self.PatrolDamageTreshold then
|
||||
if Damage <= self.PatrolDamageThreshold then
|
||||
self:E( self.Controllable:GetName() .. " is damaged:" .. Damage .. ", RTB!" )
|
||||
RTB = true
|
||||
end
|
||||
@@ -877,7 +876,7 @@ function AI_PATROL_ZONE:onafterRTB()
|
||||
local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
|
||||
local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
|
||||
local ToPatrolZoneSpeed = self.PatrolMaxSpeed
|
||||
local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
|
||||
local CurrentRoutePoint = CurrentPointVec3:WaypointAir(
|
||||
self.PatrolAltType,
|
||||
POINT_VEC3.RoutePointType.TurningPoint,
|
||||
POINT_VEC3.RoutePointAction.TurningPoint,
|
||||
|
||||
@@ -91,7 +91,7 @@ do -- ACT_ACCOUNT
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ACCOUNT self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
@@ -107,7 +107,7 @@ do -- ACT_ACCOUNT
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ACCOUNT self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
@@ -125,7 +125,7 @@ do -- ACT_ACCOUNT
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ACCOUNT self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
@@ -155,7 +155,6 @@ do -- ACT_ACCOUNT_DEADS
|
||||
-- @extends #ACT_ACCOUNT
|
||||
ACT_ACCOUNT_DEADS = {
|
||||
ClassName = "ACT_ACCOUNT_DEADS",
|
||||
TargetSetUnit = nil,
|
||||
}
|
||||
|
||||
|
||||
@@ -163,13 +162,10 @@ do -- ACT_ACCOUNT_DEADS
|
||||
-- @param #ACT_ACCOUNT_DEADS self
|
||||
-- @param Set#SET_UNIT TargetSetUnit
|
||||
-- @param #string TaskName
|
||||
function ACT_ACCOUNT_DEADS:New( TargetSetUnit, TaskName )
|
||||
function ACT_ACCOUNT_DEADS:New()
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, ACT_ACCOUNT:New() ) -- #ACT_ACCOUNT_DEADS
|
||||
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
self.TaskName = TaskName
|
||||
|
||||
self.DisplayInterval = 30
|
||||
self.DisplayCount = 30
|
||||
self.DisplayMessage = true
|
||||
@@ -181,38 +177,39 @@ do -- ACT_ACCOUNT_DEADS
|
||||
|
||||
function ACT_ACCOUNT_DEADS:Init( FsmAccount )
|
||||
|
||||
self.TargetSetUnit = FsmAccount.TargetSetUnit
|
||||
self.TaskName = FsmAccount.TaskName
|
||||
self.Task = self:GetTask()
|
||||
self.TaskName = self.Task:GetName()
|
||||
end
|
||||
|
||||
--- Process Events
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ACCOUNT_DEADS self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function ACT_ACCOUNT_DEADS:onenterReport( ProcessUnit, Task, From, Event, To )
|
||||
self:E( { ProcessUnit, From, Event, To } )
|
||||
|
||||
self:Message( "Your group with assigned " .. self.TaskName .. " task has " .. self.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed." )
|
||||
local MessageText = "Your group with assigned " .. self.TaskName .. " task has " .. Task.TargetSetUnit:GetUnitTypesText() .. " targets left to be destroyed."
|
||||
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
||||
end
|
||||
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ACCOUNT_DEADS self
|
||||
-- @param Wrapper.Client#CLIENT ProcessClient
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param Tasking.Task#TASK Task
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function ACT_ACCOUNT_DEADS:onafterEvent( ProcessClient, Task, From, Event, To, EventData )
|
||||
self:T( { ProcessClient:GetName(), Task:GetName(), From, Event, To, EventData } )
|
||||
function ACT_ACCOUNT_DEADS:onafterEvent( ProcessUnit, Task, From, Event, To, EventData )
|
||||
self:T( { ProcessUnit:GetName(), Task:GetName(), From, Event, To, EventData } )
|
||||
|
||||
if self.TargetSetUnit:FindUnit( EventData.IniUnitName ) then
|
||||
local PlayerName = ProcessClient:GetPlayerName()
|
||||
if Task.TargetSetUnit:FindUnit( EventData.IniUnitName ) then
|
||||
local PlayerName = ProcessUnit:GetPlayerName()
|
||||
local PlayerHit = self.PlayerHits and self.PlayerHits[EventData.IniUnitName]
|
||||
if PlayerHit == PlayerName then
|
||||
self:Player( EventData )
|
||||
@@ -224,24 +221,26 @@ do -- ACT_ACCOUNT_DEADS
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ACCOUNT_DEADS self
|
||||
-- @param Wrapper.Client#CLIENT ProcessClient
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param Tasking.Task#TASK Task
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function ACT_ACCOUNT_DEADS:onenterAccountForPlayer( ProcessClient, Task, From, Event, To, EventData )
|
||||
self:T( { ProcessClient:GetName(), Task:GetName(), From, Event, To, EventData } )
|
||||
function ACT_ACCOUNT_DEADS:onenterAccountForPlayer( ProcessUnit, Task, From, Event, To, EventData )
|
||||
self:T( { ProcessUnit:GetName(), Task:GetName(), From, Event, To, EventData } )
|
||||
|
||||
local TaskGroup = ProcessClient:GetGroup()
|
||||
local TaskGroup = ProcessUnit:GetGroup()
|
||||
|
||||
self.TargetSetUnit:Remove( EventData.IniUnitName )
|
||||
self:Message( "You have destroyed a target. Your group assigned with task " .. self.TaskName .. " has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed." )
|
||||
|
||||
local PlayerName = ProcessClient:GetPlayerName()
|
||||
Task.TargetSetUnit:Remove( EventData.IniUnitName )
|
||||
|
||||
local MessageText = "You have destroyed a target.\nYour group assigned with task " .. self.TaskName .. " has\n" .. Task.TargetSetUnit:Count() .. " targets ( " .. Task.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed."
|
||||
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
||||
|
||||
local PlayerName = ProcessUnit:GetPlayerName()
|
||||
Task:AddProgress( PlayerName, "Destroyed " .. EventData.IniTypeName, timer.getTime(), 1 )
|
||||
|
||||
if self.TargetSetUnit:Count() > 0 then
|
||||
if Task.TargetSetUnit:Count() > 0 then
|
||||
self:__More( 1 )
|
||||
else
|
||||
self:__NoMore( 1 )
|
||||
@@ -250,20 +249,22 @@ do -- ACT_ACCOUNT_DEADS
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ACCOUNT_DEADS self
|
||||
-- @param Wrapper.Client#CLIENT ProcessClient
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param Tasking.Task#TASK Task
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function ACT_ACCOUNT_DEADS:onenterAccountForOther( ProcessClient, Task, From, Event, To, EventData )
|
||||
self:T( { ProcessClient:GetName(), Task:GetName(), From, Event, To, EventData } )
|
||||
function ACT_ACCOUNT_DEADS:onenterAccountForOther( ProcessUnit, Task, From, Event, To, EventData )
|
||||
self:T( { ProcessUnit:GetName(), Task:GetName(), From, Event, To, EventData } )
|
||||
|
||||
local TaskGroup = ProcessClient:GetGroup()
|
||||
self.TargetSetUnit:Remove( EventData.IniUnitName )
|
||||
self:Message( "One of the task targets has been destroyed. Your group assigned with task " .. self.TaskName .. " has " .. self.TargetSetUnit:Count() .. " targets ( " .. self.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed." )
|
||||
local TaskGroup = ProcessUnit:GetGroup()
|
||||
Task.TargetSetUnit:Remove( EventData.IniUnitName )
|
||||
|
||||
local MessageText = "One of the task targets has been destroyed.\nYour group assigned with task " .. self.TaskName .. " has\n" .. Task.TargetSetUnit:Count() .. " targets ( " .. Task.TargetSetUnit:GetUnitTypesText() .. " ) left to be destroyed."
|
||||
self:GetCommandCenter():MessageTypeToGroup( MessageText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
||||
|
||||
if self.TargetSetUnit:Count() > 0 then
|
||||
if Task.TargetSetUnit:Count() > 0 then
|
||||
self:__More( 1 )
|
||||
else
|
||||
self:__NoMore( 1 )
|
||||
|
||||
@@ -229,14 +229,14 @@ do -- ACT_ASSIGN_MENU_ACCEPT
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ASSIGN_MENU_ACCEPT self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function ACT_ASSIGN_MENU_ACCEPT:onafterStart( ProcessUnit, From, Event, To )
|
||||
self:E( { ProcessUnit, From, Event, To } )
|
||||
|
||||
self:Message( "Access the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled." )
|
||||
self:GetCommandCenter():MessageTypeToGroup( "Access the radio menu to accept the task. You have 30 seconds or the assignment will be cancelled.", ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
||||
|
||||
local ProcessGroup = ProcessUnit:GetGroup()
|
||||
|
||||
@@ -263,7 +263,7 @@ do -- ACT_ASSIGN_MENU_ACCEPT
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ASSIGN_MENU_ACCEPT self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
@@ -275,7 +275,7 @@ do -- ACT_ASSIGN_MENU_ACCEPT
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ASSIGN_MENU_ACCEPT self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
|
||||
@@ -154,7 +154,7 @@ do -- ACT_ROUTE
|
||||
--- Get the routing text to be displayed.
|
||||
-- The route mode determines the text displayed.
|
||||
-- @param #ACT_ROUTE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
-- @param Wrapper.Unit#UNIT Controllable
|
||||
-- @return #string
|
||||
function ACT_ROUTE:GetRouteText( Controllable )
|
||||
|
||||
@@ -174,6 +174,7 @@ do -- ACT_ROUTE
|
||||
end
|
||||
|
||||
|
||||
local Task = self:GetTask() -- This is to dermine that the coordinates are for a specific task mode (A2A or A2G).
|
||||
local CC = self:GetTask():GetMission():GetCommandCenter()
|
||||
if CC then
|
||||
if CC:IsModeWWII() then
|
||||
@@ -198,7 +199,7 @@ do -- ACT_ROUTE
|
||||
RouteText = Coordinate:ToStringFromRP( ShortestReferencePoint, ShortestReferenceName, Controllable )
|
||||
end
|
||||
else
|
||||
RouteText = Coordinate:ToString( Controllable )
|
||||
RouteText = Coordinate:ToString( Controllable, nil, Task )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -214,7 +215,7 @@ do -- ACT_ROUTE
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ROUTE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
@@ -226,7 +227,7 @@ do -- ACT_ROUTE
|
||||
|
||||
--- Check if the controllable has arrived.
|
||||
-- @param #ACT_ROUTE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @return #boolean
|
||||
function ACT_ROUTE:onfuncHasArrived( ProcessUnit )
|
||||
return false
|
||||
@@ -234,7 +235,7 @@ do -- ACT_ROUTE
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ROUTE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
@@ -351,7 +352,7 @@ do -- ACT_ROUTE_POINT
|
||||
|
||||
--- Method override to check if the controllable has arrived.
|
||||
-- @param #ACT_ROUTE_POINT self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @return #boolean
|
||||
function ACT_ROUTE_POINT:onfuncHasArrived( ProcessUnit )
|
||||
|
||||
@@ -360,7 +361,7 @@ do -- ACT_ROUTE_POINT
|
||||
|
||||
if Distance <= self.Range then
|
||||
local RouteText = "You have arrived."
|
||||
self:Message( RouteText )
|
||||
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
||||
return true
|
||||
end
|
||||
end
|
||||
@@ -372,14 +373,15 @@ do -- ACT_ROUTE_POINT
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ROUTE_POINT self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function ACT_ROUTE_POINT:onafterReport( ProcessUnit, From, Event, To )
|
||||
|
||||
local RouteText = self:GetRouteText( ProcessUnit )
|
||||
self:Message( RouteText )
|
||||
|
||||
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Update )
|
||||
end
|
||||
|
||||
end -- ACT_ROUTE_POINT
|
||||
@@ -444,13 +446,13 @@ do -- ACT_ROUTE_ZONE
|
||||
|
||||
--- Method override to check if the controllable has arrived.
|
||||
-- @param #ACT_ROUTE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @return #boolean
|
||||
function ACT_ROUTE_ZONE:onfuncHasArrived( ProcessUnit )
|
||||
|
||||
if ProcessUnit:IsInZone( self.Zone ) then
|
||||
local RouteText = "You have arrived within the zone."
|
||||
self:Message( RouteText )
|
||||
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Information )
|
||||
end
|
||||
|
||||
return ProcessUnit:IsInZone( self.Zone )
|
||||
@@ -460,7 +462,7 @@ do -- ACT_ROUTE_ZONE
|
||||
|
||||
--- StateMachine callback function
|
||||
-- @param #ACT_ROUTE_ZONE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE ProcessUnit
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
@@ -468,7 +470,7 @@ do -- ACT_ROUTE_ZONE
|
||||
self:E( { ProcessUnit = ProcessUnit } )
|
||||
|
||||
local RouteText = self:GetRouteText( ProcessUnit )
|
||||
self:Message( RouteText )
|
||||
self:GetCommandCenter():MessageTypeToGroup( RouteText, ProcessUnit:GetGroup(), MESSAGE.Type.Update )
|
||||
end
|
||||
|
||||
end -- ACT_ROUTE_ZONE
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- The @{#BASE} class is the core root class from where every other class in moose is derived.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
-- ### Contributions:
|
||||
--
|
||||
@@ -202,7 +198,15 @@ BASE = {
|
||||
ClassID = 0,
|
||||
Events = {},
|
||||
States = {},
|
||||
_ = {},
|
||||
}
|
||||
|
||||
|
||||
--- @field #BASE.__
|
||||
BASE.__ = {}
|
||||
|
||||
--- @field #BASE._
|
||||
BASE._ = {
|
||||
Schedules = {} --- Contains the Schedulers Active
|
||||
}
|
||||
|
||||
--- The Formation Class
|
||||
@@ -228,47 +232,19 @@ FORMATION = {
|
||||
-- @return #BASE
|
||||
function BASE:New()
|
||||
local self = routines.utils.deepCopy( self ) -- Create a new self instance
|
||||
local MetaTable = {}
|
||||
setmetatable( self, MetaTable )
|
||||
self.__index = self
|
||||
|
||||
_ClassID = _ClassID + 1
|
||||
self.ClassID = _ClassID
|
||||
|
||||
|
||||
-- This is for "private" methods...
|
||||
-- When a __ is passed to a method as "self", the __index will search for the method on the public method list too!
|
||||
-- if rawget( self, "__" ) then
|
||||
--setmetatable( self, { __index = self.__ } )
|
||||
-- end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function BASE:_Destructor()
|
||||
--self:E("_Destructor")
|
||||
|
||||
--self:EventRemoveAll()
|
||||
end
|
||||
|
||||
|
||||
-- THIS IS WHY WE NEED LUA 5.2 ...
|
||||
function BASE:_SetDestructor()
|
||||
|
||||
-- TODO: Okay, this is really technical...
|
||||
-- When you set a proxy to a table to catch __gc, weak tables don't behave like weak...
|
||||
-- Therefore, I am parking this logic until I've properly discussed all this with the community.
|
||||
|
||||
local proxy = newproxy(true)
|
||||
local proxyMeta = getmetatable(proxy)
|
||||
|
||||
proxyMeta.__gc = function ()
|
||||
env.info("In __gc for " .. self:GetClassNameAndID() )
|
||||
if self._Destructor then
|
||||
self:_Destructor()
|
||||
end
|
||||
end
|
||||
|
||||
-- keep the userdata from newproxy reachable until the object
|
||||
-- table is about to be garbage-collected - then the __gc hook
|
||||
-- will be invoked and the destructor called
|
||||
rawset( self, '__proxy', proxy )
|
||||
|
||||
end
|
||||
|
||||
--- This is the worker method to inherit from a parent class.
|
||||
-- @param #BASE self
|
||||
-- @param Child is the Child class that inherits.
|
||||
@@ -276,18 +252,40 @@ end
|
||||
-- @return #BASE Child
|
||||
function BASE:Inherit( Child, Parent )
|
||||
local Child = routines.utils.deepCopy( Child )
|
||||
--local Parent = routines.utils.deepCopy( Parent )
|
||||
--local Parent = Parent
|
||||
|
||||
if Child ~= nil then
|
||||
setmetatable( Child, Parent )
|
||||
Child.__index = Child
|
||||
|
||||
|
||||
-- This is for "private" methods...
|
||||
-- When a __ is passed to a method as "self", the __index will search for the method on the public method list of the same object too!
|
||||
if rawget( Child, "__" ) then
|
||||
setmetatable( Child, { __index = Child.__ } )
|
||||
setmetatable( Child.__, { __index = Parent } )
|
||||
else
|
||||
setmetatable( Child, { __index = Parent } )
|
||||
end
|
||||
|
||||
--Child:_SetDestructor()
|
||||
end
|
||||
--self:T( 'Inherited from ' .. Parent.ClassName )
|
||||
return Child
|
||||
end
|
||||
|
||||
|
||||
local function getParent( Child )
|
||||
local Parent = nil
|
||||
|
||||
if Child.ClassName == 'BASE' then
|
||||
Parent = nil
|
||||
else
|
||||
if rawget( Child, "__" ) then
|
||||
Parent = getmetatable( Child.__ ).__index
|
||||
else
|
||||
Parent = getmetatable( Child ).__index
|
||||
end
|
||||
end
|
||||
return Parent
|
||||
end
|
||||
|
||||
|
||||
--- This is the worker method to retrieve the Parent class.
|
||||
-- Note that the Parent class must be passed to call the parent class method.
|
||||
--
|
||||
@@ -297,12 +295,91 @@ end
|
||||
-- @param #BASE self
|
||||
-- @param #BASE Child is the Child class from which the Parent class needs to be retrieved.
|
||||
-- @return #BASE
|
||||
function BASE:GetParent( Child )
|
||||
local Parent = getmetatable( Child )
|
||||
-- env.info('Inherited class of ' .. Child.ClassName .. ' is ' .. Parent.ClassName )
|
||||
return Parent
|
||||
function BASE:GetParent( Child, FromClass )
|
||||
|
||||
|
||||
local Parent
|
||||
-- BASE class has no parent
|
||||
if Child.ClassName == 'BASE' then
|
||||
Parent = nil
|
||||
else
|
||||
|
||||
self:E({FromClass = FromClass})
|
||||
self:E({Child = Child.ClassName})
|
||||
if FromClass then
|
||||
while( Child.ClassName ~= "BASE" and Child.ClassName ~= FromClass.ClassName ) do
|
||||
Child = getParent( Child )
|
||||
self:E({Child.ClassName})
|
||||
end
|
||||
end
|
||||
if Child.ClassName == 'BASE' then
|
||||
Parent = nil
|
||||
else
|
||||
Parent = getParent( Child )
|
||||
end
|
||||
end
|
||||
self:E({Parent.ClassName})
|
||||
return Parent
|
||||
end
|
||||
|
||||
--- This is the worker method to check if an object is an (sub)instance of a class.
|
||||
--
|
||||
-- ### Examples:
|
||||
--
|
||||
-- * ZONE:New( 'some zone' ):IsInstanceOf( ZONE ) will return true
|
||||
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'ZONE' ) will return true
|
||||
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'zone' ) will return true
|
||||
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'BASE' ) will return true
|
||||
--
|
||||
-- * ZONE:New( 'some zone' ):IsInstanceOf( 'GROUP' ) will return false
|
||||
--
|
||||
-- @param #BASE self
|
||||
-- @param ClassName is the name of the class or the class itself to run the check against
|
||||
-- @return #boolean
|
||||
function BASE:IsInstanceOf( ClassName )
|
||||
|
||||
-- Is className NOT a string ?
|
||||
if type( ClassName ) ~= 'string' then
|
||||
|
||||
-- Is className a Moose class ?
|
||||
if type( ClassName ) == 'table' and ClassName.ClassName ~= nil then
|
||||
|
||||
-- Get the name of the Moose class as a string
|
||||
ClassName = ClassName.ClassName
|
||||
|
||||
-- className is neither a string nor a Moose class, throw an error
|
||||
else
|
||||
|
||||
-- I'm not sure if this should take advantage of MOOSE logging function, or throw an error for pcall
|
||||
local err_str = 'className parameter should be a string; parameter received: '..type( ClassName )
|
||||
self:E( err_str )
|
||||
-- error( err_str )
|
||||
return false
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
ClassName = string.upper( ClassName )
|
||||
|
||||
if string.upper( self.ClassName ) == ClassName then
|
||||
return true
|
||||
end
|
||||
|
||||
local Parent = getParent(self)
|
||||
|
||||
while Parent do
|
||||
|
||||
if string.upper( Parent.ClassName ) == ClassName then
|
||||
return true
|
||||
end
|
||||
|
||||
Parent = getParent( Parent )
|
||||
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
--- Get the ClassName + ClassID of the class instance.
|
||||
-- The ClassName + ClassID is formatted as '%s#%09d'.
|
||||
-- @param #BASE self
|
||||
@@ -383,7 +460,7 @@ do -- Event Handling
|
||||
-- @return #BASE
|
||||
function BASE:UnHandleEvent( Event )
|
||||
|
||||
self:EventDispatcher():Remove( self, Event )
|
||||
self:EventDispatcher():RemoveEvent( self, Event )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -566,6 +643,22 @@ function BASE:CreateEventCrash( EventTime, Initiator )
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a Takeoff Event.
|
||||
-- @param #BASE self
|
||||
-- @param Dcs.DCSTypes#Time EventTime The time stamp of the event.
|
||||
-- @param Dcs.DCSWrapper.Object#Object Initiator The initiating object of the event.
|
||||
function BASE:CreateEventTakeoff( EventTime, Initiator )
|
||||
self:F( { EventTime, Initiator } )
|
||||
|
||||
local Event = {
|
||||
id = world.event.S_EVENT_TAKEOFF,
|
||||
time = EventTime,
|
||||
initiator = Initiator,
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
-- TODO: Complete Dcs.DCSTypes#Event structure.
|
||||
--- The main event handling function... This function captures all events generated for the class.
|
||||
-- @param #BASE self
|
||||
@@ -596,6 +689,86 @@ function BASE:onEvent(event)
|
||||
end
|
||||
end
|
||||
|
||||
do -- Scheduling
|
||||
|
||||
--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also.
|
||||
-- @param #BASE self
|
||||
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
||||
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
||||
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
||||
-- @return #number The ScheduleID of the planned schedule.
|
||||
function BASE:ScheduleOnce( Start, SchedulerFunction, ... )
|
||||
self:F2( { Start } )
|
||||
self:T3( { ... } )
|
||||
|
||||
local ObjectName = "-"
|
||||
ObjectName = self.ClassName .. self.ClassID
|
||||
|
||||
self:F3( { "ScheduleOnce: ", ObjectName, Start } )
|
||||
self.SchedulerObject = self
|
||||
|
||||
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
||||
self,
|
||||
SchedulerFunction,
|
||||
{ ... },
|
||||
Start,
|
||||
nil,
|
||||
nil,
|
||||
nil
|
||||
)
|
||||
|
||||
self._.Schedules[#self.Schedules+1] = ScheduleID
|
||||
|
||||
return self._.Schedules
|
||||
end
|
||||
|
||||
--- Schedule a new time event. Note that the schedule will only take place if the scheduler is *started*. Even for a single schedule event, the scheduler needs to be started also.
|
||||
-- @param #BASE self
|
||||
-- @param #number Start Specifies the amount of seconds that will be waited before the scheduling is started, and the event function is called.
|
||||
-- @param #number Repeat Specifies the interval in seconds when the scheduler will call the event function.
|
||||
-- @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 #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
||||
-- @param #table ... Optional arguments that can be given as part of scheduler. The arguments need to be given as a table { param1, param 2, ... }.
|
||||
-- @return #number The ScheduleID of the planned schedule.
|
||||
function BASE:ScheduleRepeat( Start, Repeat, RandomizeFactor, Stop, SchedulerFunction, ... )
|
||||
self:F2( { Start } )
|
||||
self:T3( { ... } )
|
||||
|
||||
local ObjectName = "-"
|
||||
ObjectName = self.ClassName .. self.ClassID
|
||||
|
||||
self:F3( { "ScheduleRepeat: ", ObjectName, Start, Repeat, RandomizeFactor, Stop } )
|
||||
self.SchedulerObject = self
|
||||
|
||||
local ScheduleID = _SCHEDULEDISPATCHER:AddSchedule(
|
||||
self,
|
||||
SchedulerFunction,
|
||||
{ ... },
|
||||
Start,
|
||||
Repeat,
|
||||
RandomizeFactor,
|
||||
Stop
|
||||
)
|
||||
|
||||
self._.Schedules[SchedulerFunction] = ScheduleID
|
||||
|
||||
return self._.Schedules
|
||||
end
|
||||
|
||||
--- Stops the Schedule.
|
||||
-- @param #BASE self
|
||||
-- @param #function SchedulerFunction The event function to be called when a timer event occurs. The event function needs to accept the parameters specified in SchedulerArguments.
|
||||
function BASE:ScheduleStop( SchedulerFunction )
|
||||
|
||||
self:F3( { "ScheduleStop:" } )
|
||||
|
||||
_SCHEDULEDISPATCHER:Stop( self, self._.Schedules[SchedulerFunction] )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Set a state or property of the Object given a Key and a Value.
|
||||
-- Note that if the Object is destroyed, nillified or garbage collected, then the Values and Keys will also be gone.
|
||||
-- @param #BASE self
|
||||
@@ -610,7 +783,6 @@ function BASE:SetState( Object, Key, Value )
|
||||
|
||||
self.States[ClassNameAndID] = self.States[ClassNameAndID] or {}
|
||||
self.States[ClassNameAndID][Key] = Value
|
||||
self:T2( { ClassNameAndID, Key, Value } )
|
||||
|
||||
return self.States[ClassNameAndID][Key]
|
||||
end
|
||||
@@ -628,7 +800,6 @@ function BASE:GetState( Object, Key )
|
||||
|
||||
if self.States[ClassNameAndID] then
|
||||
local Value = self.States[ClassNameAndID][Key] or false
|
||||
self:T2( { ClassNameAndID, Key, Value } )
|
||||
return Value
|
||||
end
|
||||
|
||||
@@ -899,3 +1070,35 @@ end
|
||||
|
||||
|
||||
|
||||
--- old stuff
|
||||
|
||||
--function BASE:_Destructor()
|
||||
-- --self:E("_Destructor")
|
||||
--
|
||||
-- --self:EventRemoveAll()
|
||||
--end
|
||||
|
||||
|
||||
-- THIS IS WHY WE NEED LUA 5.2 ...
|
||||
--function BASE:_SetDestructor()
|
||||
--
|
||||
-- -- TODO: Okay, this is really technical...
|
||||
-- -- When you set a proxy to a table to catch __gc, weak tables don't behave like weak...
|
||||
-- -- Therefore, I am parking this logic until I've properly discussed all this with the community.
|
||||
--
|
||||
-- local proxy = newproxy(true)
|
||||
-- local proxyMeta = getmetatable(proxy)
|
||||
--
|
||||
-- proxyMeta.__gc = function ()
|
||||
-- env.info("In __gc for " .. self:GetClassNameAndID() )
|
||||
-- if self._Destructor then
|
||||
-- self:_Destructor()
|
||||
-- end
|
||||
-- end
|
||||
--
|
||||
-- -- keep the userdata from newproxy reachable until the object
|
||||
-- -- table is about to be garbage-collected - then the __gc hook
|
||||
-- -- will be invoked and the destructor called
|
||||
-- rawset( self, '__proxy', proxy )
|
||||
--
|
||||
--end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,19 @@
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- 1) @{#DATABASE} class, extends @{Base#BASE}
|
||||
-- ===================================================
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module Database
|
||||
|
||||
|
||||
--- @type DATABASE
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
--- # DATABASE class, extends @{Base#BASE}
|
||||
--
|
||||
-- Mission designers can use the DATABASE class to refer to:
|
||||
--
|
||||
-- * STATICS
|
||||
@@ -17,35 +28,10 @@
|
||||
--
|
||||
-- On top, for internal MOOSE administration purposes, the DATBASE administers the Unit and Group TEMPLATES as defined within the Mission Editor.
|
||||
--
|
||||
-- Moose will automatically create one instance of the DATABASE class into the **global** object _DATABASE.
|
||||
-- Moose refers to _DATABASE within the framework extensively, but you can also refer to the _DATABASE object within your missions if required.
|
||||
-- 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.
|
||||
--
|
||||
-- 1.1) DATABASE iterators
|
||||
-- -----------------------
|
||||
-- You can iterate the database with the available iterator methods.
|
||||
-- The iterator methods will walk the DATABASE set, and call for each element within the set a function that you provide.
|
||||
-- The following iterator methods are currently available within the DATABASE:
|
||||
--
|
||||
-- * @{#DATABASE.ForEachUnit}: Calls a function for each @{UNIT} it finds within the DATABASE.
|
||||
-- * @{#DATABASE.ForEachGroup}: Calls a function for each @{GROUP} it finds within the DATABASE.
|
||||
-- * @{#DATABASE.ForEachPlayer}: Calls a function for each alive player it finds within the DATABASE.
|
||||
-- * @{#DATABASE.ForEachPlayerJoined}: Calls a function for each joined player it finds within the DATABASE.
|
||||
-- * @{#DATABASE.ForEachClient}: Calls a function for each @{CLIENT} it finds within the DATABASE.
|
||||
-- * @{#DATABASE.ForEachClientAlive}: Calls a function for each alive @{CLIENT} it finds within the DATABASE.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- ====
|
||||
-- @module Database
|
||||
|
||||
|
||||
--- DATABASE class
|
||||
-- @type DATABASE
|
||||
-- @extends Core.Base#BASE
|
||||
-- @field #DATABASE
|
||||
DATABASE = {
|
||||
ClassName = "DATABASE",
|
||||
Templates = {
|
||||
@@ -70,6 +56,8 @@ DATABASE = {
|
||||
NavPoints = {},
|
||||
PLAYERSETTINGS = {},
|
||||
ZONENAMES = {},
|
||||
HITS = {},
|
||||
DESTROYS = {},
|
||||
}
|
||||
|
||||
local _DATABASECoalition =
|
||||
@@ -104,6 +92,7 @@ function DATABASE:New()
|
||||
self:HandleEvent( EVENTS.Birth, self._EventOnBirth )
|
||||
self:HandleEvent( EVENTS.Dead, self._EventOnDeadOrCrash )
|
||||
self:HandleEvent( EVENTS.Crash, self._EventOnDeadOrCrash )
|
||||
self:HandleEvent( EVENTS.Hit, self.AccountHits )
|
||||
self:HandleEvent( EVENTS.NewCargo )
|
||||
self:HandleEvent( EVENTS.DeleteCargo )
|
||||
|
||||
@@ -214,6 +203,16 @@ function DATABASE:FindStatic( StaticName )
|
||||
return StaticFound
|
||||
end
|
||||
|
||||
--- Finds a AIRBASE based on the AirbaseName.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string AirbaseName
|
||||
-- @return Wrapper.Airbase#AIRBASE The found AIRBASE.
|
||||
function DATABASE:FindAirbase( AirbaseName )
|
||||
|
||||
local AirbaseFound = self.AIRBASES[AirbaseName]
|
||||
return AirbaseFound
|
||||
end
|
||||
|
||||
--- Adds a Airbase based on the Airbase Name in the DATABASE.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string AirbaseName The name of the airbase
|
||||
@@ -375,7 +374,12 @@ function DATABASE:Spawn( SpawnTemplate )
|
||||
SpawnTemplate.CountryID = SpawnCountryID
|
||||
SpawnTemplate.CategoryID = SpawnCategoryID
|
||||
|
||||
-- Ensure that for the spawned group and its units, there are GROUP and UNIT objects created in the DATABASE.
|
||||
local SpawnGroup = self:AddGroup( SpawnTemplate.name )
|
||||
for UnitID, UnitData in pairs( SpawnTemplate.units ) do
|
||||
self:AddUnit( UnitData.name )
|
||||
end
|
||||
|
||||
return SpawnGroup
|
||||
end
|
||||
|
||||
@@ -400,10 +404,13 @@ end
|
||||
--- Private method that registers new Group Templates within the DATABASE Object.
|
||||
-- @param #DATABASE self
|
||||
-- @param #table GroupTemplate
|
||||
-- @param Dcs.DCScoalition#coalition.side CoalitionSide The coalition.side of the object.
|
||||
-- @param Dcs.DCSObject#Object.Category CategoryID The Object.category of the object.
|
||||
-- @param Dcs.DCScountry#country.id CountryID the country.id of the object
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID, CountryID )
|
||||
function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName )
|
||||
|
||||
local GroupTemplateName = env.getValueDictByKey(GroupTemplate.name)
|
||||
local GroupTemplateName = GroupName or env.getValueDictByKey( GroupTemplate.name )
|
||||
|
||||
local TraceTable = {}
|
||||
|
||||
@@ -418,7 +425,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID
|
||||
end
|
||||
|
||||
GroupTemplate.CategoryID = CategoryID
|
||||
GroupTemplate.CoalitionID = CoalitionID
|
||||
GroupTemplate.CoalitionID = CoalitionSide
|
||||
GroupTemplate.CountryID = CountryID
|
||||
|
||||
self.Templates.Groups[GroupTemplateName].GroupName = GroupTemplateName
|
||||
@@ -427,7 +434,7 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID
|
||||
self.Templates.Groups[GroupTemplateName].UnitCount = #GroupTemplate.units
|
||||
self.Templates.Groups[GroupTemplateName].Units = GroupTemplate.units
|
||||
self.Templates.Groups[GroupTemplateName].CategoryID = CategoryID
|
||||
self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionID
|
||||
self.Templates.Groups[GroupTemplateName].CoalitionID = CoalitionSide
|
||||
self.Templates.Groups[GroupTemplateName].CountryID = CountryID
|
||||
|
||||
|
||||
@@ -454,13 +461,13 @@ function DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionID, CategoryID
|
||||
self.Templates.Units[UnitTemplate.name].GroupTemplate = GroupTemplate
|
||||
self.Templates.Units[UnitTemplate.name].GroupId = GroupTemplate.groupId
|
||||
self.Templates.Units[UnitTemplate.name].CategoryID = CategoryID
|
||||
self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionID
|
||||
self.Templates.Units[UnitTemplate.name].CoalitionID = CoalitionSide
|
||||
self.Templates.Units[UnitTemplate.name].CountryID = CountryID
|
||||
|
||||
if UnitTemplate.skill and (UnitTemplate.skill == "Client" or UnitTemplate.skill == "Player") then
|
||||
self.Templates.ClientsByName[UnitTemplate.name] = UnitTemplate
|
||||
self.Templates.ClientsByName[UnitTemplate.name].CategoryID = CategoryID
|
||||
self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionID
|
||||
self.Templates.ClientsByName[UnitTemplate.name].CoalitionID = CoalitionSide
|
||||
self.Templates.ClientsByName[UnitTemplate.name].CountryID = CountryID
|
||||
self.Templates.ClientsByID[UnitTemplate.unitId] = UnitTemplate
|
||||
end
|
||||
@@ -504,7 +511,7 @@ function DATABASE:_RegisterStaticTemplate( StaticTemplate, CoalitionID, Category
|
||||
|
||||
|
||||
TraceTable[#TraceTable+1] = "Static"
|
||||
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].GroupName
|
||||
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].StaticName
|
||||
|
||||
TraceTable[#TraceTable+1] = "Coalition"
|
||||
TraceTable[#TraceTable+1] = self.Templates.Statics[StaticTemplateName].CoalitionID
|
||||
@@ -631,6 +638,7 @@ end
|
||||
function DATABASE:_RegisterStatics()
|
||||
|
||||
local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ) }
|
||||
self:E( { Statics = CoalitionsData } )
|
||||
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
|
||||
for DCSStaticId, DCSStatic in pairs( CoalitionData ) do
|
||||
|
||||
@@ -707,6 +715,8 @@ function DATABASE:_EventOnDeadOrCrash( Event )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:AccountDestroys( Event )
|
||||
end
|
||||
|
||||
|
||||
@@ -929,7 +939,7 @@ end
|
||||
-- @param #string PlayerName
|
||||
-- @return Core.Settings#SETTINGS
|
||||
function DATABASE:GetPlayerSettings( PlayerName )
|
||||
self:E({PlayerName})
|
||||
self:F2( { PlayerName } )
|
||||
return self.PLAYERSETTINGS[PlayerName]
|
||||
end
|
||||
|
||||
@@ -940,7 +950,7 @@ end
|
||||
-- @param Core.Settings#SETTINGS Settings
|
||||
-- @return Core.Settings#SETTINGS
|
||||
function DATABASE:SetPlayerSettings( PlayerName, Settings )
|
||||
self:E({PlayerName, Settings})
|
||||
self:F2( { PlayerName, Settings } )
|
||||
self.PLAYERSETTINGS[PlayerName] = Settings
|
||||
end
|
||||
|
||||
@@ -1038,6 +1048,101 @@ function DATABASE:_RegisterTemplates()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Account the Hits of the Players.
|
||||
-- @param #DATABASE self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
function DATABASE:AccountHits( Event )
|
||||
self:F( { Event } )
|
||||
|
||||
if Event.IniPlayerName ~= nil then -- It is a player that is hitting something
|
||||
self:T( "Hitting Something" )
|
||||
|
||||
-- What is he hitting?
|
||||
if Event.TgtCategory then
|
||||
|
||||
-- A target got hit
|
||||
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
|
||||
local Hit = self.HITS[Event.TgtUnitName]
|
||||
|
||||
Hit.Players = Hit.Players or {}
|
||||
Hit.Players[Event.IniPlayerName] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- It is a weapon initiated by a player, that is hitting something
|
||||
-- This seems to occur only with scenery and static objects.
|
||||
if Event.WeaponPlayerName ~= nil then
|
||||
self:T( "Hitting Scenery" )
|
||||
|
||||
-- What is he hitting?
|
||||
if Event.TgtCategory then
|
||||
|
||||
if Event.IniCoalition then -- A coalition object was hit, probably a static.
|
||||
-- A target got hit
|
||||
self.HITS[Event.TgtUnitName] = self.HITS[Event.TgtUnitName] or {}
|
||||
local Hit = self.HITS[Event.TgtUnitName]
|
||||
|
||||
Hit.Players = Hit.Players or {}
|
||||
Hit.Players[Event.WeaponPlayerName] = true
|
||||
else -- A scenery object was hit.
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Account the destroys.
|
||||
-- @param #DATABASE self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
function DATABASE:AccountDestroys( Event )
|
||||
self:F( { Event } )
|
||||
|
||||
local TargetUnit = nil
|
||||
local TargetGroup = nil
|
||||
local TargetUnitName = ""
|
||||
local TargetGroupName = ""
|
||||
local TargetPlayerName = ""
|
||||
local TargetCoalition = nil
|
||||
local TargetCategory = nil
|
||||
local TargetType = nil
|
||||
local TargetUnitCoalition = nil
|
||||
local TargetUnitCategory = nil
|
||||
local TargetUnitType = nil
|
||||
|
||||
if Event.IniDCSUnit then
|
||||
|
||||
TargetUnit = Event.IniUnit
|
||||
TargetUnitName = Event.IniDCSUnitName
|
||||
TargetGroup = Event.IniDCSGroup
|
||||
TargetGroupName = Event.IniDCSGroupName
|
||||
TargetPlayerName = Event.IniPlayerName
|
||||
|
||||
TargetCoalition = Event.IniCoalition
|
||||
--TargetCategory = TargetUnit:getCategory()
|
||||
--TargetCategory = TargetUnit:getDesc().category -- Workaround
|
||||
TargetCategory = Event.IniCategory
|
||||
TargetType = Event.IniTypeName
|
||||
|
||||
TargetUnitType = TargetType
|
||||
|
||||
self:T( { TargetUnitName, TargetGroupName, TargetPlayerName, TargetCoalition, TargetCategory, TargetType } )
|
||||
end
|
||||
|
||||
self:T( "Something got destroyed" )
|
||||
|
||||
local Destroyed = false
|
||||
|
||||
-- What is the player destroying?
|
||||
if self.HITS[Event.IniUnitName] then -- Was there a hit for this unit for this player before registered???
|
||||
|
||||
|
||||
self.DESTROYS[Event.IniUnitName] = self.DESTROYS[Event.IniUnitName] or {}
|
||||
|
||||
self.DESTROYS[Event.IniUnitName] = true
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -450,16 +450,16 @@ end
|
||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||
-- @param Dcs.DCSWorld#world.event EventID
|
||||
-- @return #EVENT.Events
|
||||
function EVENT:Remove( EventClass, EventID )
|
||||
function EVENT:RemoveEvent( EventClass, EventID )
|
||||
|
||||
self:E( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } )
|
||||
self:F2( { "Removing subscription for class: ", EventClass:GetClassNameAndID() } )
|
||||
|
||||
local EventPriority = EventClass:GetEventPriority()
|
||||
|
||||
self.EventsDead = self.EventsDead or {}
|
||||
self.EventsDead[EventID] = self.EventsDead[EventID] or {}
|
||||
self.EventsDead[EventID][EventPriority] = self.EventsDead[EventID][EventPriority] or {}
|
||||
self.EventsDead[EventID][EventPriority][EventClass] = self.Events[EventID][EventPriority][EventClass]
|
||||
self.Events = self.Events or {}
|
||||
self.Events[EventID] = self.Events[EventID] or {}
|
||||
self.Events[EventID][EventPriority] = self.Events[EventID][EventPriority] or {}
|
||||
self.Events[EventID][EventPriority][EventClass] = self.Events[EventID][EventPriority][EventClass]
|
||||
|
||||
self.Events[EventID][EventPriority][EventClass] = nil
|
||||
|
||||
@@ -561,12 +561,13 @@ end
|
||||
-- @param Core.Base#BASE EventClass The self instance of the class for which the event is.
|
||||
-- @param EventID
|
||||
-- @return #EVENT
|
||||
function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID )
|
||||
self:F2( GroupName )
|
||||
function EVENT:OnEventForGroup( GroupName, EventFunction, EventClass, EventID, ... )
|
||||
self:E( GroupName )
|
||||
|
||||
local Event = self:Init( EventID, EventClass )
|
||||
Event.EventGroup = true
|
||||
Event.EventFunction = EventFunction
|
||||
Event.Params = arg
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -743,10 +744,15 @@ function EVENT:onEvent( Event )
|
||||
|
||||
local EventMeta = _EVENTMETA[Event.id]
|
||||
|
||||
if self and self.Events and self.Events[Event.id] then
|
||||
--self:E( { EventMeta.Text, Event } ) -- Activate the see all incoming events ...
|
||||
|
||||
if self and
|
||||
self.Events and
|
||||
self.Events[Event.id] and
|
||||
( Event.initiator ~= nil or ( Event.initiator == nil and Event.id ~= EVENTS.PlayerLeaveUnit ) ) then
|
||||
|
||||
if Event.initiator then
|
||||
|
||||
|
||||
Event.IniObjectCategory = Event.initiator:getCategory()
|
||||
|
||||
if Event.IniObjectCategory == Object.Category.UNIT then
|
||||
@@ -868,9 +874,9 @@ function EVENT:onEvent( Event )
|
||||
-- Okay, we got the event from DCS. Now loop the SORTED self.EventSorted[] table for the received Event.id, and for each EventData registered, check if a function needs to be called.
|
||||
for EventClass, EventData in pairs( self.Events[Event.id][EventPriority] ) do
|
||||
|
||||
if Event.IniObjectCategory ~= Object.Category.STATIC then
|
||||
--self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
|
||||
end
|
||||
--if Event.IniObjectCategory ~= Object.Category.STATIC then
|
||||
-- self:E( { "Evaluating: ", EventClass:GetClassNameAndID() } )
|
||||
--end
|
||||
|
||||
Event.IniGroup = GROUP:FindByName( Event.IniDCSGroupName )
|
||||
Event.TgtGroup = GROUP:FindByName( Event.TgtDCSGroupName )
|
||||
@@ -920,7 +926,7 @@ function EVENT:onEvent( Event )
|
||||
end
|
||||
else
|
||||
-- The EventClass is not alive anymore, we remove it from the EventHandlers...
|
||||
self:Remove( EventClass, Event.id )
|
||||
self:RemoveEvent( EventClass, Event.id )
|
||||
end
|
||||
else
|
||||
|
||||
@@ -947,7 +953,7 @@ function EVENT:onEvent( Event )
|
||||
|
||||
local Result, Value = xpcall(
|
||||
function()
|
||||
return EventData.EventFunction( EventClass, Event )
|
||||
return EventData.EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
||||
end, ErrorHandler )
|
||||
|
||||
else
|
||||
@@ -963,14 +969,14 @@ function EVENT:onEvent( Event )
|
||||
|
||||
local Result, Value = xpcall(
|
||||
function()
|
||||
return EventFunction( EventClass, Event )
|
||||
return EventFunction( EventClass, Event, unpack( EventData.Params ) )
|
||||
end, ErrorHandler )
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- The EventClass is not alive anymore, we remove it from the EventHandlers...
|
||||
self:Remove( EventClass, Event.id )
|
||||
--self:RemoveEvent( EventClass, Event.id )
|
||||
end
|
||||
else
|
||||
|
||||
@@ -1015,7 +1021,7 @@ function EVENT:onEvent( Event )
|
||||
end
|
||||
end
|
||||
else
|
||||
self:E( { EventMeta.Text, Event } )
|
||||
self:T( { EventMeta.Text, Event } )
|
||||
end
|
||||
|
||||
Event = nil
|
||||
|
||||
@@ -418,7 +418,7 @@ do -- FSM
|
||||
-- @param #table ReturnEvents A table indicating for which returned events of the SubFSM which Event must be triggered in the FSM.
|
||||
-- @return Core.Fsm#FSM_PROCESS The SubFSM.
|
||||
function FSM:AddProcess( From, Event, Process, ReturnEvents )
|
||||
self:T( { From, Event, Process, ReturnEvents } )
|
||||
self:T( { From, Event } )
|
||||
|
||||
local Sub = {}
|
||||
Sub.From = From
|
||||
@@ -541,7 +541,7 @@ do -- FSM
|
||||
end
|
||||
|
||||
function FSM:_submap( subs, sub, name )
|
||||
self:F( { sub = sub, name = name } )
|
||||
--self:F( { sub = sub, name = name } )
|
||||
subs[sub.From] = subs[sub.From] or {}
|
||||
subs[sub.From][sub.Event] = subs[sub.From][sub.Event] or {}
|
||||
|
||||
@@ -844,7 +844,7 @@ do -- FSM_CONTROLLABLE
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE FSMControllable
|
||||
-- @return #FSM_CONTROLLABLE
|
||||
function FSM_CONTROLLABLE:SetControllable( FSMControllable )
|
||||
self:F( FSMControllable )
|
||||
--self:F( FSMControllable:GetName() )
|
||||
self.Controllable = FSMControllable
|
||||
end
|
||||
|
||||
@@ -904,7 +904,7 @@ do -- FSM_PROCESS
|
||||
|
||||
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- Core.Fsm#FSM_PROCESS
|
||||
|
||||
self:F( Controllable, Task )
|
||||
--self:F( Controllable )
|
||||
|
||||
self:Assign( Controllable, Task )
|
||||
|
||||
@@ -960,7 +960,7 @@ do -- FSM_PROCESS
|
||||
|
||||
-- Copy Processes
|
||||
for ProcessID, Process in pairs( self:GetProcesses() ) do
|
||||
self:E( { Process} )
|
||||
--self:E( { Process:GetName() } )
|
||||
local FsmProcess = NewFsm:AddProcess( Process.From, Process.Event, Process.fsm:Copy( Controllable, Task ), Process.ReturnEvents )
|
||||
end
|
||||
|
||||
@@ -990,7 +990,6 @@ do -- FSM_PROCESS
|
||||
|
||||
-- Copy Processes
|
||||
for ProcessID, Process in pairs( self:GetProcesses() ) do
|
||||
self:E( { Process} )
|
||||
if Process.fsm then
|
||||
Process.fsm:Remove()
|
||||
Process.fsm = nil
|
||||
@@ -1063,7 +1062,7 @@ end
|
||||
-- @param Wrapper.Unit#UNIT ProcessUnit
|
||||
-- @return #FSM_PROCESS self
|
||||
function FSM_PROCESS:Assign( ProcessUnit, Task )
|
||||
self:T( { Task, ProcessUnit } )
|
||||
--self:T( { Task:GetName(), ProcessUnit:GetName() } )
|
||||
|
||||
self:SetControllable( ProcessUnit )
|
||||
self:SetTask( Task )
|
||||
@@ -1093,7 +1092,7 @@ end
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
function FSM_PROCESS:onstatechange( ProcessUnit, Task, From, Event, To, Dummy )
|
||||
self:T( { ProcessUnit, From, Event, To, Dummy, self:IsTrace() } )
|
||||
self:T( { ProcessUnit:GetName(), From, Event, To, Dummy, self:IsTrace() } )
|
||||
|
||||
if self:IsTrace() then
|
||||
--MESSAGE:New( "@ Process " .. self:GetClassNameAndID() .. " : " .. Event .. " changed to state " .. To, 2 ):ToAll()
|
||||
|
||||
146
Moose Development/Moose/Core/Goal.lua
Normal file
146
Moose Development/Moose/Core/Goal.lua
Normal file
@@ -0,0 +1,146 @@
|
||||
--- **Core (WIP)** -- Base class to allow the modeling of processes to achieve Goals.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- GOAL models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module Goal
|
||||
|
||||
do -- Goal
|
||||
|
||||
--- @type GOAL
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
|
||||
--- # GOAL class, extends @{Fsm#FSM}
|
||||
--
|
||||
-- GOAL models processes that have an objective with a defined achievement. Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- ## 1. GOAL constructor
|
||||
--
|
||||
-- * @{#GOAL.New}(): Creates a new GOAL object.
|
||||
--
|
||||
-- ## 2. GOAL is a finite state machine (FSM).
|
||||
--
|
||||
-- ### 2.1 GOAL States
|
||||
--
|
||||
-- * **Pending**: The goal object is in progress.
|
||||
-- * **Achieved**: The goal objective is Achieved.
|
||||
--
|
||||
-- ### 2.2 GOAL Events
|
||||
--
|
||||
-- * **Achieved**: Set the goal objective to Achieved.
|
||||
--
|
||||
-- @field #GOAL
|
||||
GOAL = {
|
||||
ClassName = "GOAL",
|
||||
}
|
||||
|
||||
--- @field #table GOAL.Players
|
||||
GOAL.Players = {}
|
||||
|
||||
--- @field #number GOAL.TotalContributions
|
||||
GOAL.TotalContributions = 0
|
||||
|
||||
--- GOAL Constructor.
|
||||
-- @param #GOAL self
|
||||
-- @return #GOAL
|
||||
function GOAL:New()
|
||||
|
||||
local self = BASE:Inherit( self, FSM:New() ) -- #GOAL
|
||||
self:F( {} )
|
||||
|
||||
--- Achieved State for GOAL
|
||||
-- @field GOAL.Achieved
|
||||
|
||||
--- Achieved State Handler OnLeave for GOAL
|
||||
-- @function [parent=#GOAL] OnLeaveAchieved
|
||||
-- @param #GOAL self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Achieved State Handler OnEnter for GOAL
|
||||
-- @function [parent=#GOAL] OnEnterAchieved
|
||||
-- @param #GOAL self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
|
||||
self:SetStartState( "Pending" )
|
||||
self:AddTransition( "*", "Achieved", "Achieved" )
|
||||
|
||||
--- Achieved Handler OnBefore for GOAL
|
||||
-- @function [parent=#GOAL] OnBeforeAchieved
|
||||
-- @param #GOAL self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Achieved Handler OnAfter for GOAL
|
||||
-- @function [parent=#GOAL] OnAfterAchieved
|
||||
-- @param #GOAL self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- Achieved Trigger for GOAL
|
||||
-- @function [parent=#GOAL] Achieved
|
||||
-- @param #GOAL self
|
||||
|
||||
--- Achieved Asynchronous Trigger for GOAL
|
||||
-- @function [parent=#GOAL] __Achieved
|
||||
-- @param #GOAL self
|
||||
-- @param #number Delay
|
||||
|
||||
self:SetEventPriority( 5 )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @param #GOAL self
|
||||
-- @param #string PlayerName
|
||||
function GOAL:AddPlayerContribution( PlayerName )
|
||||
self.Players[PlayerName] = self.Players[PlayerName] or 0
|
||||
self.Players[PlayerName] = self.Players[PlayerName] + 1
|
||||
self.TotalContributions = self.TotalContributions + 1
|
||||
end
|
||||
|
||||
|
||||
--- @param #GOAL self
|
||||
-- @param #number Player contribution.
|
||||
function GOAL:GetPlayerContribution( PlayerName )
|
||||
return self.Players[PlayerName] or 0
|
||||
end
|
||||
|
||||
|
||||
--- @param #GOAL self
|
||||
function GOAL:GetPlayerContributions()
|
||||
return self.Players or {}
|
||||
end
|
||||
|
||||
|
||||
--- @param #GOAL self
|
||||
function GOAL:GetTotalContributions()
|
||||
return self.TotalContributions or 0
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #GOAL self
|
||||
-- @return #boolean true if the goal is Achieved
|
||||
function GOAL:IsAchieved()
|
||||
return self:Is( "Achieved" )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -103,6 +103,15 @@ do -- MENU_BASE
|
||||
return self
|
||||
end
|
||||
|
||||
--- Sets a tag for later selection of menu refresh.
|
||||
-- @param #MENU_BASE self
|
||||
-- @param #string MenuTag A Tag or Key that will filter only menu items set with this key.
|
||||
-- @return #MENU_BASE
|
||||
function MENU_BASE:SetTag( MenuTag )
|
||||
self.MenuTag = MenuTag
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do -- MENU_COMMAND_BASE
|
||||
@@ -115,6 +124,7 @@ do -- MENU_COMMAND_BASE
|
||||
-- ----------------------------------------------------------
|
||||
-- The MENU_COMMAND_BASE class defines the main MENU class where other MENU COMMAND_
|
||||
-- classes are derived from, in order to set commands.
|
||||
--
|
||||
-- @field #MENU_COMMAND_BASE
|
||||
MENU_COMMAND_BASE = {
|
||||
ClassName = "MENU_COMMAND_BASE",
|
||||
@@ -128,15 +138,51 @@ do -- MENU_COMMAND_BASE
|
||||
-- @return #MENU_COMMAND_BASE
|
||||
function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments )
|
||||
|
||||
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) )
|
||||
local self = BASE:Inherit( self, MENU_BASE:New( MenuText, ParentMenu ) ) -- #MENU_COMMAND_BASE
|
||||
|
||||
-- When a menu function goes into error, DCS displays an obscure menu message.
|
||||
-- This error handler catches the menu error and displays the full call stack.
|
||||
local ErrorHandler = function( errmsg )
|
||||
env.info( "MOOSE error in MENU COMMAND function: " .. errmsg )
|
||||
if debug ~= nil then
|
||||
env.info( debug.traceback() )
|
||||
end
|
||||
return errmsg
|
||||
end
|
||||
|
||||
self.CommandMenuFunction = CommandMenuFunction
|
||||
self.MenuCallHandler = function( CommandMenuArguments )
|
||||
self.CommandMenuFunction( unpack( CommandMenuArguments ) )
|
||||
self:SetCommandMenuFunction( CommandMenuFunction )
|
||||
self:SetCommandMenuArguments( CommandMenuArguments )
|
||||
self.MenuCallHandler = function()
|
||||
local function MenuFunction()
|
||||
return self.CommandMenuFunction( unpack( self.CommandMenuArguments ) )
|
||||
end
|
||||
local Status, Result = xpcall( MenuFunction, ErrorHandler )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- This sets the new command function of a menu,
|
||||
-- so that if a menu is regenerated, or if command function changes,
|
||||
-- that the function set for the menu is loosely coupled with the menu itself!!!
|
||||
-- If the function changes, no new menu needs to be generated if the menu text is the same!!!
|
||||
-- @param #MENU_COMMAND_BASE
|
||||
-- @return #MENU_COMMAND_BASE
|
||||
function MENU_COMMAND_BASE:SetCommandMenuFunction( CommandMenuFunction )
|
||||
self.CommandMenuFunction = CommandMenuFunction
|
||||
return self
|
||||
end
|
||||
|
||||
--- This sets the new command arguments of a menu,
|
||||
-- so that if a menu is regenerated, or if command arguments change,
|
||||
-- that the arguments set for the menu are loosely coupled with the menu itself!!!
|
||||
-- If the arguments change, no new menu needs to be generated if the menu text is the same!!!
|
||||
-- @param #MENU_COMMAND_BASE
|
||||
-- @return #MENU_COMMAND_BASE
|
||||
function MENU_COMMAND_BASE:SetCommandMenuArguments( CommandMenuArguments )
|
||||
self.CommandMenuArguments = CommandMenuArguments
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -247,7 +293,7 @@ do -- MENU_MISSION_COMMAND
|
||||
self:T( { MenuText, CommandMenuFunction, arg } )
|
||||
|
||||
|
||||
self.MenuPath = missionCommands.addCommand( MenuText, self.MenuParentPath, self.MenuCallHandler, arg )
|
||||
self.MenuPath = missionCommands.addCommand( MenuText, self.MenuParentPath, self.MenuCallHandler )
|
||||
|
||||
ParentMenu.Menus[self.MenuPath] = self
|
||||
|
||||
@@ -420,7 +466,7 @@ do -- MENU_COALITION_COMMAND
|
||||
self:T( { MenuText, CommandMenuFunction, arg } )
|
||||
|
||||
|
||||
self.MenuPath = missionCommands.addCommandForCoalition( self.MenuCoalition, MenuText, self.MenuParentPath, self.MenuCallHandler, arg )
|
||||
self.MenuPath = missionCommands.addCommandForCoalition( self.MenuCoalition, MenuText, self.MenuParentPath, self.MenuCallHandler )
|
||||
|
||||
ParentMenu.Menus[self.MenuPath] = self
|
||||
|
||||
@@ -653,7 +699,7 @@ do -- MENU_CLIENT
|
||||
missionCommands.removeItemForGroup( self.MenuClient:GetClientGroupID(), MenuPath[MenuPathID] )
|
||||
end
|
||||
|
||||
self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, self.MenuCallHandler, arg )
|
||||
self.MenuPath = missionCommands.addCommandForGroup( self.MenuClient:GetClientGroupID(), MenuText, MenuParentPath, self.MenuCallHandler )
|
||||
MenuPath[MenuPathID] = self.MenuPath
|
||||
|
||||
if ParentMenu and ParentMenu.Menus then
|
||||
@@ -805,13 +851,14 @@ do
|
||||
--- Removes the sub menus recursively of this MENU_GROUP.
|
||||
-- @param #MENU_GROUP self
|
||||
-- @param MenuTime
|
||||
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
||||
-- @return #MENU_GROUP self
|
||||
function MENU_GROUP:RemoveSubMenus( MenuTime )
|
||||
function MENU_GROUP:RemoveSubMenus( MenuTime, MenuTag )
|
||||
--self:F2( { self.MenuPath, MenuTime, self.MenuTime } )
|
||||
|
||||
--self:T( { "Removing Group SubMenus:", self.MenuGroup:GetName(), self.MenuPath } )
|
||||
self:T( { "Removing Group SubMenus:", MenuTime, MenuTag, self.MenuGroup:GetName(), self.MenuPath } )
|
||||
for MenuText, Menu in pairs( self.Menus ) do
|
||||
Menu:Remove( MenuTime )
|
||||
Menu:Remove( MenuTime, MenuTag )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -820,28 +867,31 @@ do
|
||||
--- Removes the main menu and sub menus recursively of this MENU_GROUP.
|
||||
-- @param #MENU_GROUP self
|
||||
-- @param MenuTime
|
||||
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
||||
-- @return #nil
|
||||
function MENU_GROUP:Remove( MenuTime )
|
||||
function MENU_GROUP:Remove( MenuTime, MenuTag )
|
||||
--self:F2( { self.MenuGroupID, self.MenuPath, MenuTime, self.MenuTime } )
|
||||
|
||||
self:RemoveSubMenus( MenuTime )
|
||||
self:RemoveSubMenus( MenuTime, MenuTag )
|
||||
|
||||
if not MenuTime or self.MenuTime ~= MenuTime then
|
||||
if self.MenuGroup._Menus[self.Path] then
|
||||
self = self.MenuGroup._Menus[self.Path]
|
||||
|
||||
missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath )
|
||||
if self.ParentMenu then
|
||||
self.ParentMenu.Menus[self.MenuText] = nil
|
||||
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1
|
||||
if self.ParentMenu.MenuCount == 0 then
|
||||
if self.MenuRemoveParent == true then
|
||||
self:T2( "Removing Parent Menu " )
|
||||
self.ParentMenu:Remove()
|
||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||
if self.MenuGroup._Menus[self.Path] then
|
||||
self = self.MenuGroup._Menus[self.Path]
|
||||
|
||||
missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath )
|
||||
if self.ParentMenu then
|
||||
self.ParentMenu.Menus[self.MenuText] = nil
|
||||
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1
|
||||
if self.ParentMenu.MenuCount == 0 then
|
||||
if self.MenuRemoveParent == true then
|
||||
self:T2( "Removing Parent Menu " )
|
||||
self.ParentMenu:Remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self:T( { "Removing Group Menu:", MenuGroup = self.MenuGroup:GetName(), MenuPath = self.MenuGroup._Menus[self.Path].Path } )
|
||||
self:T( { "Removing Group Menu:", MenuGroup = self.MenuGroup:GetName() } )
|
||||
self.MenuGroup._Menus[self.Path] = nil
|
||||
self = nil
|
||||
end
|
||||
@@ -852,7 +902,7 @@ do
|
||||
|
||||
|
||||
--- @type MENU_GROUP_COMMAND
|
||||
-- @extends Core.Menu#MENU_BASE
|
||||
-- @extends Core.Menu#MENU_COMMAND_BASE
|
||||
|
||||
--- # MENU_GROUP_COMMAND class, extends @{Menu#MENU_COMMAND_BASE}
|
||||
--
|
||||
@@ -876,32 +926,37 @@ do
|
||||
function MENU_GROUP_COMMAND:New( MenuGroup, MenuText, ParentMenu, CommandMenuFunction, ... )
|
||||
|
||||
MenuGroup._Menus = MenuGroup._Menus or {}
|
||||
local Path = ( ParentMenu and ( table.concat( ParentMenu.MenuPath or {}, "@" ) .. "@" .. MenuText ) ) or MenuText
|
||||
local Path = ( ParentMenu and ( table.concat( ParentMenu.MenuPath or {}, "@" ) .. "@" .. MenuText ) ) or MenuText
|
||||
if MenuGroup._Menus[Path] then
|
||||
self = MenuGroup._Menus[Path]
|
||||
self:F2( { "Re-using Group Command Menu:", MenuGroup:GetName(), MenuText } )
|
||||
else
|
||||
self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) )
|
||||
|
||||
--if MenuGroup:IsAlive() then
|
||||
MenuGroup._Menus[Path] = self
|
||||
--end
|
||||
|
||||
self.Path = Path
|
||||
self.MenuGroup = MenuGroup
|
||||
self.MenuGroupID = MenuGroup:GetID()
|
||||
self.MenuText = MenuText
|
||||
self.ParentMenu = ParentMenu
|
||||
|
||||
self:F( { "Adding Group Command Menu:", MenuGroup = MenuGroup:GetName(), MenuText = MenuText, MenuPath = self.MenuParentPath } )
|
||||
self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroupID, MenuText, self.MenuParentPath, self.MenuCallHandler, arg )
|
||||
|
||||
if self.ParentMenu and self.ParentMenu.Menus then
|
||||
self.ParentMenu.Menus[MenuText] = self
|
||||
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount + 1
|
||||
self:F2( { ParentMenu.Menus, MenuText } )
|
||||
end
|
||||
--self:E( { Path=Path } )
|
||||
--self:E( { self.MenuTag, self.MenuTime, "Re-using Group Command Menu:", MenuGroup:GetName(), MenuText } )
|
||||
self:SetCommandMenuFunction( CommandMenuFunction )
|
||||
self:SetCommandMenuArguments( arg )
|
||||
return self
|
||||
end
|
||||
self = BASE:Inherit( self, MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, arg ) )
|
||||
|
||||
--if MenuGroup:IsAlive() then
|
||||
MenuGroup._Menus[Path] = self
|
||||
--end
|
||||
|
||||
--self:E({Path=Path})
|
||||
self.Path = Path
|
||||
self.MenuGroup = MenuGroup
|
||||
self.MenuGroupID = MenuGroup:GetID()
|
||||
self.MenuText = MenuText
|
||||
self.ParentMenu = ParentMenu
|
||||
|
||||
self:F( { "Adding Group Command Menu:", MenuGroup = MenuGroup:GetName(), MenuText = MenuText, MenuPath = self.MenuParentPath } )
|
||||
self.MenuPath = missionCommands.addCommandForGroup( self.MenuGroupID, MenuText, self.MenuParentPath, self.MenuCallHandler )
|
||||
|
||||
if self.ParentMenu and self.ParentMenu.Menus then
|
||||
self.ParentMenu.Menus[MenuText] = self
|
||||
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount + 1
|
||||
self:F2( { ParentMenu.Menus, MenuText } )
|
||||
end
|
||||
-- end
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -909,28 +964,32 @@ do
|
||||
--- Removes a menu structure for a group.
|
||||
-- @param #MENU_GROUP_COMMAND self
|
||||
-- @param MenuTime
|
||||
-- @param MenuTag A Tag or Key to filter the menus to be refreshed with the Tag set.
|
||||
-- @return #nil
|
||||
function MENU_GROUP_COMMAND:Remove( MenuTime )
|
||||
function MENU_GROUP_COMMAND:Remove( MenuTime, MenuTag )
|
||||
--self:F2( { self.MenuGroupID, self.MenuPath, MenuTime, self.MenuTime } )
|
||||
|
||||
--self:E( { MenuTag = MenuTag, MenuTime = self.MenuTime, Path = self.Path } )
|
||||
if not MenuTime or self.MenuTime ~= MenuTime then
|
||||
if self.MenuGroup._Menus[self.Path] then
|
||||
self = self.MenuGroup._Menus[self.Path]
|
||||
|
||||
missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath )
|
||||
self:T( { "Removing Group Command Menu:", MenuGroup = self.MenuGroup:GetName(), MenuText = self.MenuText, MenuPath = self.Path } )
|
||||
|
||||
self.ParentMenu.Menus[self.MenuText] = nil
|
||||
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1
|
||||
if self.ParentMenu.MenuCount == 0 then
|
||||
if self.MenuRemoveParent == true then
|
||||
self:T2( "Removing Parent Menu " )
|
||||
self.ParentMenu:Remove()
|
||||
if ( not MenuTag ) or ( MenuTag and self.MenuTag and MenuTag == self.MenuTag ) then
|
||||
if self.MenuGroup._Menus[self.Path] then
|
||||
self = self.MenuGroup._Menus[self.Path]
|
||||
|
||||
missionCommands.removeItemForGroup( self.MenuGroupID, self.MenuPath )
|
||||
--self:E( { "Removing Group Command Menu:", MenuGroup = self.MenuGroup:GetName(), MenuText = self.MenuText, MenuPath = self.Path } )
|
||||
|
||||
self.ParentMenu.Menus[self.MenuText] = nil
|
||||
self.ParentMenu.MenuCount = self.ParentMenu.MenuCount - 1
|
||||
if self.ParentMenu.MenuCount == 0 then
|
||||
if self.MenuRemoveParent == true then
|
||||
self:T2( "Removing Parent Menu " )
|
||||
self.ParentMenu:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
self.MenuGroup._Menus[self.Path] = nil
|
||||
self = nil
|
||||
end
|
||||
|
||||
self.MenuGroup._Menus[self.Path] = nil
|
||||
self = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -53,6 +53,16 @@ MESSAGE = {
|
||||
MessageID = 0,
|
||||
}
|
||||
|
||||
--- Message Types
|
||||
-- @type MESSAGE.Type
|
||||
MESSAGE.Type = {
|
||||
Update = "Update",
|
||||
Information = "Information",
|
||||
Briefing = "Briefing Report",
|
||||
Overview = "Overview Report",
|
||||
Detailed = "Detailed Report"
|
||||
}
|
||||
|
||||
|
||||
--- Creates a new MESSAGE object. Note that these MESSAGE objects are not yet displayed on the display panel. You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
|
||||
-- @param self
|
||||
@@ -74,6 +84,9 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
self:F( { MessageText, MessageDuration, MessageCategory } )
|
||||
|
||||
|
||||
self.MessageType = nil
|
||||
|
||||
-- When no MessageCategory is given, we don't show it as a title...
|
||||
if MessageCategory and MessageCategory ~= "" then
|
||||
if MessageCategory:sub(-1) ~= "\n" then
|
||||
@@ -96,6 +109,37 @@ function MESSAGE:New( MessageText, MessageDuration, MessageCategory )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Creates a new MESSAGE object of a certain type.
|
||||
-- Note that these MESSAGE objects are not yet displayed on the display panel.
|
||||
-- You must use the functions @{ToClient} or @{ToCoalition} or @{ToAll} to send these Messages to the respective recipients.
|
||||
-- The message display times are automatically defined based on the timing settings in the @{Settings} menu.
|
||||
-- @param self
|
||||
-- @param #string MessageText is the text of the Message.
|
||||
-- @param #MESSAGE.Type MessageType The type of the message.
|
||||
-- @return #MESSAGE
|
||||
-- @usage
|
||||
-- MessageAll = MESSAGE:NewType( "To all Players: BLUE has won! Each player of BLUE wins 50 points!", MESSAGE.Type.Information )
|
||||
-- MessageRED = MESSAGE:NewType( "To the RED Players: You receive a penalty because you've killed one of your own units", MESSAGE.Type.Information )
|
||||
-- MessageClient1 = MESSAGE:NewType( "Congratulations, you've just hit a target", MESSAGE.Type.Update )
|
||||
-- MessageClient2 = MESSAGE:NewType( "Congratulations, you've just killed a target", MESSAGE.Type.Update )
|
||||
function MESSAGE:NewType( MessageText, MessageType )
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
self:F( { MessageText } )
|
||||
|
||||
self.MessageType = MessageType
|
||||
|
||||
self.MessageTime = timer.getTime()
|
||||
self.MessageText = MessageText:gsub("^\n","",1):gsub("\n$","",1)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- Sends a MESSAGE to a Client Group. Note that the Group needs to be defined within the ME with the skillset "Client" or "Player".
|
||||
-- @param #MESSAGE self
|
||||
-- @param Wrapper.Client#CLIENT Client is the Group of the Client.
|
||||
@@ -115,14 +159,22 @@ end
|
||||
-- MessageClient2 = MESSAGE:New( "Congratulations, you've just killed a target", "Score", 25, "Score" )
|
||||
-- MessageClient1:ToClient( ClientGroup )
|
||||
-- MessageClient2:ToClient( ClientGroup )
|
||||
function MESSAGE:ToClient( Client )
|
||||
function MESSAGE:ToClient( Client, Settings )
|
||||
self:F( Client )
|
||||
|
||||
if Client and Client:GetClientGroupID() then
|
||||
|
||||
local ClientGroupID = Client:GetClientGroupID()
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
|
||||
if self.MessageType then
|
||||
local Settings = Settings or ( Client and _DATABASE:GetPlayerSettings( Client:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||
end
|
||||
|
||||
if self.MessageDuration ~= 0 then
|
||||
local ClientGroupID = Client:GetClientGroupID()
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForGroup( ClientGroupID, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -132,13 +184,21 @@ end
|
||||
-- @param #MESSAGE self
|
||||
-- @param Wrapper.Group#GROUP Group is the Group.
|
||||
-- @return #MESSAGE
|
||||
function MESSAGE:ToGroup( Group )
|
||||
function MESSAGE:ToGroup( Group, Settings )
|
||||
self:F( Group.GroupName )
|
||||
|
||||
if Group then
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or ( Group and _DATABASE:GetPlayerSettings( Group:GetPlayerName() ) ) or _SETTINGS -- Core.Settings#SETTINGS
|
||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||
end
|
||||
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
|
||||
if self.MessageDuration ~= 0 then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForGroup( Group:GetID(), self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -193,12 +253,20 @@ end
|
||||
-- or
|
||||
-- MessageRED = MESSAGE:New( "To the RED Players: You receive a penalty because you've killed one of your own units", "Penalty", 25, "Score" )
|
||||
-- MessageRED:ToCoalition( coalition.side.RED )
|
||||
function MESSAGE:ToCoalition( CoalitionSide )
|
||||
function MESSAGE:ToCoalition( CoalitionSide, Settings )
|
||||
self:F( CoalitionSide )
|
||||
|
||||
if self.MessageType then
|
||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||
end
|
||||
|
||||
if CoalitionSide then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForCoalition( CoalitionSide, self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
|
||||
if self.MessageDuration ~= 0 then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outTextForCoalition( CoalitionSide, self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -232,8 +300,16 @@ end
|
||||
function MESSAGE:ToAll()
|
||||
self:F()
|
||||
|
||||
self:ToCoalition( coalition.side.RED )
|
||||
self:ToCoalition( coalition.side.BLUE )
|
||||
if self.MessageType then
|
||||
local Settings = Settings or _SETTINGS -- Core.Settings#SETTINGS
|
||||
self.MessageDuration = Settings:GetMessageTime( self.MessageType )
|
||||
self.MessageCategory = "" -- self.MessageType .. ": "
|
||||
end
|
||||
|
||||
if self.MessageDuration ~= 0 then
|
||||
self:T( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$","") .. " / " .. self.MessageDuration )
|
||||
trigger.action.outText( self.MessageCategory .. self.MessageText:gsub("\n$",""):gsub("\n$",""), self.MessageDuration )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -245,8 +321,7 @@ end
|
||||
function MESSAGE:ToAllIf( Condition )
|
||||
|
||||
if Condition and Condition == true then
|
||||
self:ToCoalition( coalition.side.RED )
|
||||
self:ToCoalition( coalition.side.BLUE )
|
||||
self:ToAll()
|
||||
end
|
||||
|
||||
return self
|
||||
|
||||
@@ -54,8 +54,8 @@ do -- COORDINATE
|
||||
--
|
||||
-- A COORDINATE can prepare waypoints for Ground and Air groups to be embedded into a Route.
|
||||
--
|
||||
-- * @{#COORDINATE.RoutePointAir}(): Build an air route point.
|
||||
-- * @{#COORDINATE.RoutePointGround}(): Build a ground route point.
|
||||
-- * @{#COORDINATE.WaypointAir}(): Build an air route point.
|
||||
-- * @{#COORDINATE.WaypointGround}(): Build a ground route point.
|
||||
--
|
||||
-- Route points can be used in the Route methods of the @{Group#GROUP} class.
|
||||
--
|
||||
@@ -90,6 +90,18 @@ do -- COORDINATE
|
||||
-- * @{#COORDINATE.IlluminationBomb}(): To illuminate the point.
|
||||
--
|
||||
--
|
||||
-- ## Markings
|
||||
--
|
||||
-- Place markers (text boxes with clarifications for briefings, target locations or any other reference point) on the map for all players, coalitions or specific groups:
|
||||
--
|
||||
-- * @{#COORDINATE.MarkToAll}(): Place a mark to all players.
|
||||
-- * @{#COORDINATE.MarkToCoalition}(): Place a mark to a coalition.
|
||||
-- * @{#COORDINATE.MarkToCoalitionRed}(): Place a mark to the red coalition.
|
||||
-- * @{#COORDINATE.MarkToCoalitionBlue}(): Place a mark to the blue coalition.
|
||||
-- * @{#COORDINATE.MarkToGroup}(): Place a mark to a group (needs to have a client in it or a CA group (CA group is bugged)).
|
||||
-- * @{#COORDINATE.RemoveMark}(): Removes a mark from the map.
|
||||
--
|
||||
--
|
||||
-- ## 3D calculation methods
|
||||
--
|
||||
-- Various calculation methods exist to use or manipulate 3D space. Find below a short description of each method:
|
||||
@@ -138,6 +150,31 @@ do -- COORDINATE
|
||||
ClassName = "COORDINATE",
|
||||
}
|
||||
|
||||
--- @field COORDINATE.WaypointAltType
|
||||
COORDINATE.WaypointAltType = {
|
||||
BARO = "BARO",
|
||||
RADIO = "RADIO",
|
||||
}
|
||||
|
||||
--- @field COORDINATE.WaypointAction
|
||||
COORDINATE.WaypointAction = {
|
||||
TurningPoint = "Turning Point",
|
||||
FlyoverPoint = "Fly Over Point",
|
||||
FromParkingArea = "From Parking Area",
|
||||
FromParkingAreaHot = "From Parking Area Hot",
|
||||
FromRunway = "From Runway",
|
||||
Landing = "Landing",
|
||||
}
|
||||
|
||||
--- @field COORDINATE.WaypointType
|
||||
COORDINATE.WaypointType = {
|
||||
TakeOffParking = "TakeOffParking",
|
||||
TakeOffParkingHot = "TakeOffParkingHot",
|
||||
TakeOff = "TakeOffParkingHot",
|
||||
TurningPoint = "Turning Point",
|
||||
Land = "Land",
|
||||
}
|
||||
|
||||
|
||||
--- COORDINATE constructor.
|
||||
-- @param #COORDINATE self
|
||||
@@ -279,11 +316,55 @@ do -- COORDINATE
|
||||
|
||||
return RandomVec3
|
||||
end
|
||||
|
||||
--- Return the height of the land at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number
|
||||
function COORDINATE:GetLandHeight()
|
||||
local Vec2 = { x = self.x, y = self.z }
|
||||
return land.getHeight( Vec2 )
|
||||
end
|
||||
|
||||
|
||||
--- Set the heading of the coordinate, if applicable.
|
||||
-- @param #COORDINATE self
|
||||
function COORDINATE:SetHeading( Heading )
|
||||
self.Heading = Heading
|
||||
end
|
||||
|
||||
|
||||
--- Get the heading of the coordinate, if applicable.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number or nil
|
||||
function COORDINATE:GetHeading()
|
||||
return self.Heading
|
||||
end
|
||||
|
||||
|
||||
--- Set the velocity of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #string Velocity Velocity in meters per second.
|
||||
function COORDINATE:SetVelocity( Velocity )
|
||||
self.Velocity = Velocity
|
||||
end
|
||||
|
||||
|
||||
--- Return the velocity of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number Velocity in meters per second.
|
||||
function COORDINATE:GetVelocity()
|
||||
local Velocity = self.Velocity
|
||||
return Velocity or 0
|
||||
end
|
||||
|
||||
|
||||
--- Return velocity text of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #string
|
||||
function COORDINATE:GetMovingText( Settings )
|
||||
|
||||
return self:GetVelocityText( Settings ) .. ", " .. self:GetHeadingText( Settings )
|
||||
end
|
||||
|
||||
|
||||
--- Return a direction vector Vec3 from COORDINATE to the COORDINATE.
|
||||
@@ -294,6 +375,7 @@ do -- COORDINATE
|
||||
return { x = TargetCoordinate.x - self.x, y = TargetCoordinate.y - self.y, z = TargetCoordinate.z - self.z }
|
||||
end
|
||||
|
||||
|
||||
--- Get a correction in radians of the real magnetic north of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number CorrectionRadians The correction in radians.
|
||||
@@ -339,6 +421,7 @@ do -- COORDINATE
|
||||
return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5
|
||||
end
|
||||
|
||||
|
||||
--- Return the 3D distance in meters between the target COORDINATE and the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE TargetCoordinate The target COORDINATE.
|
||||
@@ -405,6 +488,38 @@ do -- COORDINATE
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Return the velocity text of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #string Velocity text.
|
||||
function COORDINATE:GetVelocityText( Settings )
|
||||
local Velocity = self:GetVelocity()
|
||||
local Settings = Settings or _SETTINGS
|
||||
if Velocity then
|
||||
if Settings:IsMetric() then
|
||||
return string.format( " moving at %d km/h", UTILS.MpsToKmph( Velocity ) )
|
||||
else
|
||||
return string.format( " moving at %d mi/h", UTILS.MpsToKmph( Velocity ) / 1.852 )
|
||||
end
|
||||
else
|
||||
return " stationary"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Return the heading text of the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #string Heading text.
|
||||
function COORDINATE:GetHeadingText( Settings )
|
||||
local Heading = self:GetHeading()
|
||||
if Heading then
|
||||
return string.format( " bearing %3d°", Heading )
|
||||
else
|
||||
return " bearing unknown"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Provides a Bearing / Range string
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number AngleRadians The angle in randians
|
||||
@@ -463,25 +578,25 @@ do -- COORDINATE
|
||||
|
||||
--- Build an air type route point.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE.RoutePointAltType AltType The altitude type.
|
||||
-- @param #COORDINATE.RoutePointType Type The route point type.
|
||||
-- @param #COORDINATE.RoutePointAction Action The route point action.
|
||||
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
|
||||
-- @param #COORDINATE.WaypointType Type The route point type.
|
||||
-- @param #COORDINATE.WaypointAction Action The route point action.
|
||||
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
|
||||
-- @param #boolean SpeedLocked true means the speed is locked.
|
||||
-- @return #table The route point.
|
||||
function COORDINATE:RoutePointAir( AltType, Type, Action, Speed, SpeedLocked )
|
||||
function COORDINATE:WaypointAir( AltType, Type, Action, Speed, SpeedLocked )
|
||||
self:F2( { AltType, Type, Action, Speed, SpeedLocked } )
|
||||
|
||||
local RoutePoint = {}
|
||||
RoutePoint.x = self.x
|
||||
RoutePoint.y = self.z
|
||||
RoutePoint.alt = self.y
|
||||
RoutePoint.alt_type = AltType
|
||||
RoutePoint.alt_type = AltType or "RADIO"
|
||||
|
||||
RoutePoint.type = Type
|
||||
RoutePoint.action = Action
|
||||
RoutePoint.type = Type or nil
|
||||
RoutePoint.action = Action or nil
|
||||
|
||||
RoutePoint.speed = Speed / 3.6
|
||||
RoutePoint.speed = ( Speed and Speed / 3.6 ) or ( 500 / 3.6 )
|
||||
RoutePoint.speed_locked = true
|
||||
|
||||
-- ["task"] =
|
||||
@@ -505,12 +620,81 @@ do -- COORDINATE
|
||||
return RoutePoint
|
||||
end
|
||||
|
||||
|
||||
--- Build a Waypoint Air "Turning Point".
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
|
||||
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
|
||||
-- @return #table The route point.
|
||||
function COORDINATE:WaypointAirTurningPoint( AltType, Speed )
|
||||
return self:WaypointAir( AltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, Speed )
|
||||
end
|
||||
|
||||
|
||||
--- Build a Waypoint Air "Fly Over Point".
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
|
||||
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
|
||||
-- @return #table The route point.
|
||||
function COORDINATE:WaypointAirFlyOverPoint( AltType, Speed )
|
||||
return self:WaypointAir( AltType, COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.FlyoverPoint, Speed )
|
||||
end
|
||||
|
||||
|
||||
--- Build a Waypoint Air "Take Off Parking Hot".
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
|
||||
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
|
||||
-- @return #table The route point.
|
||||
function COORDINATE:WaypointAirTakeOffParkingHot( AltType, Speed )
|
||||
return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOffParkingHot, COORDINATE.WaypointAction.FromParkingAreaHot, Speed )
|
||||
end
|
||||
|
||||
|
||||
--- Build a Waypoint Air "Take Off Parking".
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
|
||||
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
|
||||
-- @return #table The route point.
|
||||
function COORDINATE:WaypointAirTakeOffParking( AltType, Speed )
|
||||
return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOffParking, COORDINATE.WaypointAction.FromParkingArea, Speed )
|
||||
end
|
||||
|
||||
|
||||
--- Build a Waypoint Air "Take Off Runway".
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE.WaypointAltType AltType The altitude type.
|
||||
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
|
||||
-- @return #table The route point.
|
||||
function COORDINATE:WaypointAirTakeOffRunway( AltType, Speed )
|
||||
return self:WaypointAir( AltType, COORDINATE.WaypointType.TakeOff, COORDINATE.WaypointAction.FromRunway, Speed )
|
||||
end
|
||||
|
||||
|
||||
--- Build a Waypoint Air "Landing".
|
||||
-- @param #COORDINATE self
|
||||
-- @param Dcs.DCSTypes#Speed Speed Airspeed in km/h.
|
||||
-- @return #table The route point.
|
||||
-- @usage
|
||||
--
|
||||
-- LandingZone = ZONE:New( "LandingZone" )
|
||||
-- LandingCoord = LandingZone:GetCoordinate()
|
||||
-- LandingWaypoint = LandingCoord:WaypointAirLanding( 60 )
|
||||
-- HeliGroup:Route( { LandWaypoint }, 1 ) -- Start landing the helicopter in one second.
|
||||
--
|
||||
function COORDINATE:WaypointAirLanding( Speed )
|
||||
return self:WaypointAir( nil, COORDINATE.WaypointType.Land, COORDINATE.WaypointAction.Landing, Speed )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Build an ground type route point.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Dcs.DCSTypes#Speed Speed Speed in km/h.
|
||||
-- @param #COORDINATE.RoutePointAction Formation The route point Formation.
|
||||
-- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h.
|
||||
-- @param #string Formation (optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right".
|
||||
-- @return #table The route point.
|
||||
function COORDINATE:RoutePointGround( Speed, Formation )
|
||||
function COORDINATE:WaypointGround( Speed, Formation )
|
||||
self:F2( { Formation, Speed } )
|
||||
|
||||
local RoutePoint = {}
|
||||
@@ -520,7 +704,7 @@ do -- COORDINATE
|
||||
RoutePoint.action = Formation or ""
|
||||
|
||||
|
||||
RoutePoint.speed = Speed / 3.6
|
||||
RoutePoint.speed = ( Speed or 999 ) / 3.6
|
||||
RoutePoint.speed_locked = true
|
||||
|
||||
-- ["task"] =
|
||||
@@ -642,6 +826,88 @@ do -- COORDINATE
|
||||
self:F2( Azimuth )
|
||||
self:Flare( FLARECOLOR.Red, Azimuth )
|
||||
end
|
||||
|
||||
do -- Markings
|
||||
|
||||
--- Mark to All
|
||||
-- @param #COORDINATE self
|
||||
-- @param #string MarkText Free format text that shows the marking clarification.
|
||||
-- @return #number The resulting Mark ID which is a number.
|
||||
-- @usage
|
||||
-- local TargetCoord = TargetGroup:GetCoordinate()
|
||||
-- local MarkID = TargetCoord:MarkToAll( "This is a target for all players" )
|
||||
function COORDINATE:MarkToAll( MarkText )
|
||||
local MarkID = UTILS.GetMarkID()
|
||||
trigger.action.markToAll( MarkID, MarkText, self:GetVec3() )
|
||||
return MarkID
|
||||
end
|
||||
|
||||
--- Mark to Coalition
|
||||
-- @param #COORDINATE self
|
||||
-- @param #string MarkText Free format text that shows the marking clarification.
|
||||
-- @param Coalition
|
||||
-- @return #number The resulting Mark ID which is a number.
|
||||
-- @usage
|
||||
-- local TargetCoord = TargetGroup:GetCoordinate()
|
||||
-- local MarkID = TargetCoord:MarkToCoalition( "This is a target for the red coalition", coalition.side.RED )
|
||||
function COORDINATE:MarkToCoalition( MarkText, Coalition )
|
||||
local MarkID = UTILS.GetMarkID()
|
||||
trigger.action.markToCoalition( MarkID, MarkText, self:GetVec3(), Coalition )
|
||||
return MarkID
|
||||
end
|
||||
|
||||
--- Mark to Red Coalition
|
||||
-- @param #COORDINATE self
|
||||
-- @param #string MarkText Free format text that shows the marking clarification.
|
||||
-- @return #number The resulting Mark ID which is a number.
|
||||
-- @usage
|
||||
-- local TargetCoord = TargetGroup:GetCoordinate()
|
||||
-- local MarkID = TargetCoord:MarkToCoalitionRed( "This is a target for the red coalition" )
|
||||
function COORDINATE:MarkToCoalitionRed( MarkText )
|
||||
return self:MarkToCoalition( MarkText, coalition.side.RED )
|
||||
end
|
||||
|
||||
--- Mark to Blue Coalition
|
||||
-- @param #COORDINATE self
|
||||
-- @param #string MarkText Free format text that shows the marking clarification.
|
||||
-- @return #number The resulting Mark ID which is a number.
|
||||
-- @usage
|
||||
-- local TargetCoord = TargetGroup:GetCoordinate()
|
||||
-- local MarkID = TargetCoord:MarkToCoalitionBlue( "This is a target for the blue coalition" )
|
||||
function COORDINATE:MarkToCoalitionBlue( MarkText )
|
||||
return self:MarkToCoalition( MarkText, coalition.side.BLUE )
|
||||
end
|
||||
|
||||
--- Mark to Group
|
||||
-- @param #COORDINATE self
|
||||
-- @param #string MarkText Free format text that shows the marking clarification.
|
||||
-- @param Wrapper.Group#GROUP MarkGroup The @{Group} that receives the mark.
|
||||
-- @return #number The resulting Mark ID which is a number.
|
||||
-- @usage
|
||||
-- local TargetCoord = TargetGroup:GetCoordinate()
|
||||
-- local MarkGroup = GROUP:FindByName( "AttackGroup" )
|
||||
-- local MarkID = TargetCoord:MarkToGroup( "This is a target for the attack group", AttackGroup )
|
||||
function COORDINATE:MarkToGroup( MarkText, MarkGroup )
|
||||
local MarkID = UTILS.GetMarkID()
|
||||
trigger.action.markToGroup( MarkID, MarkText, self:GetVec3(), MarkGroup:GetID() )
|
||||
return MarkID
|
||||
end
|
||||
|
||||
--- Remove a mark
|
||||
-- @param #COORDINATE self
|
||||
-- @param #number MarkID The ID of the mark to be removed.
|
||||
-- @usage
|
||||
-- local TargetCoord = TargetGroup:GetCoordinate()
|
||||
-- local MarkGroup = GROUP:FindByName( "AttackGroup" )
|
||||
-- local MarkID = TargetCoord:MarkToGroup( "This is a target for the attack group", AttackGroup )
|
||||
-- <<< logic >>>
|
||||
-- RemoveMark( MarkID ) -- The mark is now removed
|
||||
function COORDINATE:RemoveMark( MarkID )
|
||||
trigger.action.removeMark( MarkID )
|
||||
end
|
||||
|
||||
end -- Markings
|
||||
|
||||
|
||||
--- Returns if a Coordinate has Line of Sight (LOS) with the ToCoordinate.
|
||||
-- @param #COORDINATE self
|
||||
@@ -662,6 +928,39 @@ do -- COORDINATE
|
||||
end
|
||||
|
||||
|
||||
--- Returns if a Coordinate is in a certain Radius of this Coordinate in 2D plane using the X and Z axis.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE ToCoordinate The coordinate that will be tested if it is in the radius of this coordinate.
|
||||
-- @param #number Radius The radius of the circle on the 2D plane around this coordinate.
|
||||
-- @return #boolean true if in the Radius.
|
||||
function COORDINATE:IsInRadius( Coordinate, Radius )
|
||||
|
||||
local InVec2 = self:GetVec2()
|
||||
local Vec2 = Coordinate:GetVec2()
|
||||
|
||||
local InRadius = UTILS.IsInRadius( InVec2, Vec2, Radius)
|
||||
|
||||
return InRadius
|
||||
end
|
||||
|
||||
|
||||
--- Returns if a Coordinate is in a certain radius of this Coordinate in 3D space using the X, Y and Z axis.
|
||||
-- So Radius defines the radius of the a Sphere in 3D space around this coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE ToCoordinate The coordinate that will be tested if it is in the radius of this coordinate.
|
||||
-- @param #number Radius The radius of the sphere in the 3D space around this coordinate.
|
||||
-- @return #boolean true if in the Sphere.
|
||||
function COORDINATE:IsInSphere( Coordinate, Radius )
|
||||
|
||||
local InVec3 = self:GetVec3()
|
||||
local Vec3 = Coordinate:GetVec3()
|
||||
|
||||
local InSphere = UTILS.IsInSphere( InVec3, Vec3, Radius)
|
||||
|
||||
return InSphere
|
||||
end
|
||||
|
||||
|
||||
--- Return a BR string from a COORDINATE to the COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param #COORDINATE TargetCoordinate The target COORDINATE.
|
||||
@@ -725,16 +1024,26 @@ do -- COORDINATE
|
||||
return ""
|
||||
end
|
||||
|
||||
--- Provides a Lat Lon string
|
||||
--- Provides a Lat Lon string in Degree Minute Second format.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Core.Settings#SETTINGS Settings (optional) Settings
|
||||
-- @return #string The LL Text
|
||||
function COORDINATE:ToStringLL( Settings ) --R2.1 Fixes issue #424.
|
||||
-- @return #string The LL DMS Text
|
||||
function COORDINATE:ToStringLLDMS( Settings )
|
||||
|
||||
local LL_Accuracy = Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy
|
||||
local LL_DMS = Settings and Settings.LL_DMS or _SETTINGS.LL_DMS
|
||||
local lat, lon = coord.LOtoLL( self:GetVec3() )
|
||||
return "LL, " .. UTILS.tostringLL( lat, lon, LL_Accuracy, LL_DMS )
|
||||
return "LL DMS, " .. UTILS.tostringLL( lat, lon, LL_Accuracy, true )
|
||||
end
|
||||
|
||||
--- Provides a Lat Lon string in Degree Decimal Minute format.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Core.Settings#SETTINGS Settings (optional) Settings
|
||||
-- @return #string The LL DDM Text
|
||||
function COORDINATE:ToStringLLDDM( Settings )
|
||||
|
||||
local LL_Accuracy = Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy
|
||||
local lat, lon = coord.LOtoLL( self:GetVec3() )
|
||||
return "LL DDM, " .. UTILS.tostringLL( lat, lon, LL_Accuracy, false )
|
||||
end
|
||||
|
||||
--- Provides a MGRS string
|
||||
@@ -780,44 +1089,124 @@ do -- COORDINATE
|
||||
|
||||
end
|
||||
|
||||
--- Provides a coordinate string of the point, based on the A2G coordinate format system.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
-- @param Core.Settings#SETTINGS Settings
|
||||
-- @return #string The coordinate Text in the configured coordinate system.
|
||||
function COORDINATE:ToStringA2G( Controllable, Settings ) -- R2.2
|
||||
|
||||
self:F( { Controllable = Controllable and Controllable:GetName() } )
|
||||
|
||||
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
|
||||
|
||||
if Settings:IsA2G_BR() then
|
||||
-- If no Controllable is given to calculate the BR from, then MGRS will be used!!!
|
||||
if Controllable then
|
||||
local Coordinate = Controllable:GetCoordinate()
|
||||
return Controllable and self:ToStringBR( Coordinate, Settings ) or self:ToStringMGRS( Settings )
|
||||
else
|
||||
return self:ToStringMGRS( Settings )
|
||||
end
|
||||
end
|
||||
if Settings:IsA2G_LL_DMS() then
|
||||
return self:ToStringLLDMS( Settings )
|
||||
end
|
||||
if Settings:IsA2G_LL_DDM() then
|
||||
return self:ToStringLLDDM( Settings )
|
||||
end
|
||||
if Settings:IsA2G_MGRS() then
|
||||
return self:ToStringMGRS( Settings )
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Provides a coordinate string of the point, based on the A2A coordinate format system.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
-- @param Core.Settings#SETTINGS Settings
|
||||
-- @return #string The coordinate Text in the configured coordinate system.
|
||||
function COORDINATE:ToStringA2A( Controllable, Settings ) -- R2.2
|
||||
|
||||
self:F( { Controllable = Controllable and Controllable:GetName() } )
|
||||
|
||||
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
|
||||
|
||||
if Settings:IsA2A_BRAA() then
|
||||
if Controllable then
|
||||
local Coordinate = Controllable:GetCoordinate()
|
||||
return self:ToStringBRA( Coordinate, Settings )
|
||||
else
|
||||
return self:ToStringMGRS( Settings )
|
||||
end
|
||||
end
|
||||
if Settings:IsA2A_BULLS() then
|
||||
local Coalition = Controllable:GetCoalition()
|
||||
return self:ToStringBULLS( Coalition, Settings )
|
||||
end
|
||||
if Settings:IsA2A_LL_DMS() then
|
||||
return self:ToStringLLDMS( Settings )
|
||||
end
|
||||
if Settings:IsA2A_LL_DDM() then
|
||||
return self:ToStringLLDDM( Settings )
|
||||
end
|
||||
if Settings:IsA2A_MGRS() then
|
||||
return self:ToStringMGRS( Settings )
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
--- Provides a coordinate string of the point, based on a coordinate format system:
|
||||
-- * Uses default settings in COORDINATE.
|
||||
-- * Can be overridden if for a GROUP containing x clients, a menu was selected to override the default.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
-- @param Core.Settings#SETTINGS Settings
|
||||
-- @param Tasking.Task#TASK Task The task for which coordinates need to be calculated.
|
||||
-- @return #string The coordinate Text in the configured coordinate system.
|
||||
function COORDINATE:ToString( Controllable, Settings ) -- R2.2
|
||||
function COORDINATE:ToString( Controllable, Settings, Task ) -- R2.2
|
||||
|
||||
self:E( { Controllable = Controllable } )
|
||||
self:F( { Controllable = Controllable and Controllable:GetName() } )
|
||||
|
||||
local Settings = Settings or ( Controllable and _DATABASE:GetPlayerSettings( Controllable:GetPlayerName() ) ) or _SETTINGS
|
||||
|
||||
local IsAir = Controllable and Controllable:IsAirPlane() or false
|
||||
|
||||
if IsAir then
|
||||
if Settings:IsA2A_BRA() then
|
||||
local Coordinate = Controllable:GetCoordinate()
|
||||
return self:ToStringBRA( Coordinate, Settings )
|
||||
end
|
||||
|
||||
if Settings:IsA2A_BULLS() then
|
||||
local Coalition = Controllable:GetCoalition()
|
||||
return self:ToStringBULLS( Coalition, Settings )
|
||||
local ModeA2A = false
|
||||
|
||||
if Task then
|
||||
if Task:IsInstanceOf( TASK_A2A ) then
|
||||
ModeA2A = true
|
||||
else
|
||||
if Task:IsInstanceOf( TASK_A2G ) then
|
||||
ModeA2A = false
|
||||
else
|
||||
if Task:IsInstanceOf( TASK_CARGO ) then
|
||||
ModeA2A = false
|
||||
else
|
||||
ModeA2A = false
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if Settings:IsA2G_BRA() then
|
||||
local Coordinate = Controllable:GetCoordinate()
|
||||
return Controllable and self:ToStringBR( Coordinate, Settings ) or self:ToStringMGRS( Settings )
|
||||
end
|
||||
if Settings:IsA2G_LL() then
|
||||
return self:ToStringLL( Settings )
|
||||
end
|
||||
if Settings:IsA2G_MGRS() then
|
||||
return self:ToStringMGRS( Settings )
|
||||
local IsAir = Controllable and Controllable:IsAirPlane() or false
|
||||
if IsAir then
|
||||
ModeA2A = true
|
||||
else
|
||||
ModeA2A = false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if ModeA2A == true then
|
||||
return self:ToStringA2A( Controllable, Settings )
|
||||
else
|
||||
return self:ToStringA2G( Controllable, Settings )
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
86
Moose Development/Moose/Core/Report.lua
Normal file
86
Moose Development/Moose/Core/Report.lua
Normal file
@@ -0,0 +1,86 @@
|
||||
--- The REPORT class
|
||||
-- @type REPORT
|
||||
-- @extends Core.Base#BASE
|
||||
REPORT = {
|
||||
ClassName = "REPORT",
|
||||
Title = "",
|
||||
}
|
||||
|
||||
--- Create a new REPORT.
|
||||
-- @param #REPORT self
|
||||
-- @param #string Title
|
||||
-- @return #REPORT
|
||||
function REPORT:New( Title )
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #REPORT
|
||||
|
||||
self.Report = {}
|
||||
|
||||
self:SetTitle( Title or "" )
|
||||
self:SetIndent( 3 )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Has the REPORT Text?
|
||||
-- @param #REPORT self
|
||||
-- @return #boolean
|
||||
function REPORT:HasText() --R2.1
|
||||
|
||||
return #self.Report > 0
|
||||
end
|
||||
|
||||
|
||||
--- Set indent of a REPORT.
|
||||
-- @param #REPORT self
|
||||
-- @param #number Indent
|
||||
-- @return #REPORT
|
||||
function REPORT:SetIndent( Indent ) --R2.1
|
||||
self.Indent = Indent
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Add a new line to a REPORT.
|
||||
-- @param #REPORT self
|
||||
-- @param #string Text
|
||||
-- @return #REPORT
|
||||
function REPORT:Add( Text )
|
||||
self.Report[#self.Report+1] = Text
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a new line to a REPORT.
|
||||
-- @param #REPORT self
|
||||
-- @param #string Text
|
||||
-- @return #REPORT
|
||||
function REPORT:AddIndent( Text ) --R2.1
|
||||
self.Report[#self.Report+1] = string.rep(" ", self.Indent ) .. Text:gsub("\n","\n"..string.rep( " ", self.Indent ) )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Produces the text of the report, taking into account an optional delimeter, which is \n by default.
|
||||
-- @param #REPORT self
|
||||
-- @param #string Delimiter (optional) A delimiter text.
|
||||
-- @return #string The report text.
|
||||
function REPORT:Text( Delimiter )
|
||||
Delimiter = Delimiter or "\n"
|
||||
local ReportText = ( self.Title ~= "" and self.Title .. Delimiter or self.Title ) .. table.concat( self.Report, Delimiter ) or ""
|
||||
return ReportText
|
||||
end
|
||||
|
||||
--- Sets the title of the report.
|
||||
-- @param #REPORT self
|
||||
-- @param #string Title The title of the report.
|
||||
-- @return #REPORT
|
||||
function REPORT:SetTitle( Title )
|
||||
self.Title = Title
|
||||
return self
|
||||
end
|
||||
|
||||
--- Gets the amount of report items contained in the report.
|
||||
-- @param #REPORT self
|
||||
-- @return #number Returns the number of report items contained in the report. 0 is returned if no report items are contained in the report. The title is not counted for.
|
||||
function REPORT:GetCount()
|
||||
return #self.Report
|
||||
end
|
||||
@@ -55,6 +55,7 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
self:F2( { Scheduler, ScheduleFunction, ScheduleArguments, Start, Repeat, Randomize, Stop } )
|
||||
|
||||
self.CallID = self.CallID + 1
|
||||
local CallID = self.CallID .. "#" .. ( Scheduler.MasterObject and Scheduler.MasterObject.GetClassNameAndID and Scheduler.MasterObject:GetClassNameAndID() or "" ) or ""
|
||||
|
||||
-- Initialize the ObjectSchedulers array, which is a weakly coupled table.
|
||||
-- If the object used as the key is nil, then the garbage collector will remove the item from the Functions array.
|
||||
@@ -65,27 +66,27 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
self.ObjectSchedulers = self.ObjectSchedulers or setmetatable( {}, { __mode = "v" } )
|
||||
|
||||
if Scheduler.MasterObject then
|
||||
self.ObjectSchedulers[self.CallID] = Scheduler
|
||||
self:F3( { CallID = self.CallID, ObjectScheduler = tostring(self.ObjectSchedulers[self.CallID]), MasterObject = tostring(Scheduler.MasterObject) } )
|
||||
self.ObjectSchedulers[CallID] = Scheduler
|
||||
self:F3( { CallID = CallID, ObjectScheduler = tostring(self.ObjectSchedulers[CallID]), MasterObject = tostring(Scheduler.MasterObject) } )
|
||||
else
|
||||
self.PersistentSchedulers[self.CallID] = Scheduler
|
||||
self:F3( { CallID = self.CallID, PersistentScheduler = self.PersistentSchedulers[self.CallID] } )
|
||||
self.PersistentSchedulers[CallID] = Scheduler
|
||||
self:F3( { CallID = CallID, PersistentScheduler = self.PersistentSchedulers[CallID] } )
|
||||
end
|
||||
|
||||
self.Schedule = self.Schedule or setmetatable( {}, { __mode = "k" } )
|
||||
self.Schedule[Scheduler] = self.Schedule[Scheduler] or {}
|
||||
self.Schedule[Scheduler][self.CallID] = {}
|
||||
self.Schedule[Scheduler][self.CallID].Function = ScheduleFunction
|
||||
self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments
|
||||
self.Schedule[Scheduler][self.CallID].StartTime = timer.getTime() + ( Start or 0 )
|
||||
self.Schedule[Scheduler][self.CallID].Start = Start + .1
|
||||
self.Schedule[Scheduler][self.CallID].Repeat = Repeat
|
||||
self.Schedule[Scheduler][self.CallID].Randomize = Randomize
|
||||
self.Schedule[Scheduler][self.CallID].Stop = Stop
|
||||
self.Schedule[Scheduler][CallID] = {}
|
||||
self.Schedule[Scheduler][CallID].Function = ScheduleFunction
|
||||
self.Schedule[Scheduler][CallID].Arguments = ScheduleArguments
|
||||
self.Schedule[Scheduler][CallID].StartTime = timer.getTime() + ( Start or 0 )
|
||||
self.Schedule[Scheduler][CallID].Start = Start + .1
|
||||
self.Schedule[Scheduler][CallID].Repeat = Repeat or 0
|
||||
self.Schedule[Scheduler][CallID].Randomize = Randomize or 0
|
||||
self.Schedule[Scheduler][CallID].Stop = Stop
|
||||
|
||||
self:T3( self.Schedule[Scheduler][self.CallID] )
|
||||
self:T3( self.Schedule[Scheduler][CallID] )
|
||||
|
||||
self.Schedule[Scheduler][self.CallID].CallHandler = function( CallID )
|
||||
self.Schedule[Scheduler][CallID].CallHandler = function( CallID )
|
||||
self:F2( CallID )
|
||||
|
||||
local ErrorHandler = function( errmsg )
|
||||
@@ -100,11 +101,12 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
if not Scheduler then
|
||||
Scheduler = self.PersistentSchedulers[CallID]
|
||||
end
|
||||
|
||||
|
||||
--self:T3( { Scheduler = Scheduler } )
|
||||
|
||||
if Scheduler then
|
||||
|
||||
local MasterObject = tostring(Scheduler.MasterObject)
|
||||
local Schedule = self.Schedule[Scheduler][CallID]
|
||||
|
||||
--self:T3( { Schedule = Schedule } )
|
||||
@@ -133,10 +135,13 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
end
|
||||
|
||||
local CurrentTime = timer.getTime()
|
||||
local StartTime = CurrentTime + Start
|
||||
local StartTime = Schedule.StartTime
|
||||
|
||||
self:F3( { Master = MasterObject, CurrentTime = CurrentTime, StartTime = StartTime, Start = Start, Repeat = Repeat, Randomize = Randomize, Stop = Stop } )
|
||||
|
||||
|
||||
if Status and (( Result == nil ) or ( Result and Result ~= false ) ) then
|
||||
if Repeat ~= 0 and ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) then
|
||||
if Repeat ~= 0 and ( ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) ) then
|
||||
local ScheduleTime =
|
||||
CurrentTime +
|
||||
Repeat +
|
||||
@@ -160,9 +165,9 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
|
||||
return nil
|
||||
end
|
||||
|
||||
self:Start( Scheduler, self.CallID )
|
||||
self:Start( Scheduler, CallID )
|
||||
|
||||
return self.CallID
|
||||
return CallID
|
||||
end
|
||||
|
||||
function SCHEDULEDISPATCHER:RemoveSchedule( Scheduler, CallID )
|
||||
@@ -182,10 +187,11 @@ function SCHEDULEDISPATCHER:Start( Scheduler, CallID )
|
||||
-- Only start when there is no ScheduleID defined!
|
||||
-- This prevents to "Start" the scheduler twice with the same CallID...
|
||||
if not Schedule[CallID].ScheduleID then
|
||||
Schedule[CallID].StartTime = timer.getTime() -- Set the StartTime field to indicate when the scheduler started.
|
||||
Schedule[CallID].ScheduleID = timer.scheduleFunction(
|
||||
Schedule[CallID].CallHandler,
|
||||
CallID,
|
||||
timer.getTime() + Schedule[CallID].Start
|
||||
timer.getTime() + Schedule[CallID].Start
|
||||
)
|
||||
end
|
||||
else
|
||||
|
||||
@@ -210,7 +210,8 @@ SCHEDULER = {
|
||||
-- @return #SCHEDULER self.
|
||||
-- @return #number The ScheduleID of the planned schedule.
|
||||
function SCHEDULER:New( SchedulerObject, SchedulerFunction, SchedulerArguments, Start, Repeat, RandomizeFactor, Stop )
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #SCHEDULER
|
||||
self:F2( { Start, Repeat, RandomizeFactor, Stop } )
|
||||
|
||||
local ScheduleID = nil
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -55,11 +55,15 @@ do -- SETTINGS
|
||||
if PlayerName == nil then
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #SETTINGS
|
||||
self:SetMetric() -- Defaults
|
||||
self:SetA2G_MGRS() -- Defaults
|
||||
self:SetA2A_BRA() -- Defaults
|
||||
self:SetLL_Accuracy( 2 ) -- Defaults
|
||||
self:SetLL_DMS( true ) -- Defaults
|
||||
self:SetA2G_BR() -- Defaults
|
||||
self:SetA2A_BRAA() -- Defaults
|
||||
self:SetLL_Accuracy( 3 ) -- Defaults
|
||||
self:SetMGRS_Accuracy( 5 ) -- Defaults
|
||||
self:SetMessageTime( MESSAGE.Type.Briefing, 180 )
|
||||
self:SetMessageTime( MESSAGE.Type.Detailed, 60 )
|
||||
self:SetMessageTime( MESSAGE.Type.Information, 30 )
|
||||
self:SetMessageTime( MESSAGE.Type.Overview, 60 )
|
||||
self:SetMessageTime( MESSAGE.Type.Update, 15 )
|
||||
return self
|
||||
else
|
||||
local Settings = _DATABASE:GetPlayerSettings( PlayerName )
|
||||
@@ -82,7 +86,6 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if metric.
|
||||
function SETTINGS:IsMetric()
|
||||
self:E( {Metric = ( self.Metric ~= nil and self.Metric == true ) or ( self.Metric == nil and _SETTINGS:IsMetric() ) } )
|
||||
return ( self.Metric ~= nil and self.Metric == true ) or ( self.Metric == nil and _SETTINGS:IsMetric() )
|
||||
end
|
||||
|
||||
@@ -96,7 +99,6 @@ do -- SETTINGS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if imperial.
|
||||
function SETTINGS:IsImperial()
|
||||
self:E( {Metric = ( self.Metric ~= nil and self.Metric == false ) or ( self.Metric == nil and _SETTINGS:IsMetric() ) } )
|
||||
return ( self.Metric ~= nil and self.Metric == false ) or ( self.Metric == nil and _SETTINGS:IsMetric() )
|
||||
end
|
||||
|
||||
@@ -111,25 +113,10 @@ do -- SETTINGS
|
||||
--- Gets the SETTINGS LL accuracy.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #number
|
||||
function SETTINGS:GetLL_Accuracy()
|
||||
return self.LL_Accuracy or _SETTINGS:GetLL_Accuracy()
|
||||
function SETTINGS:GetLL_DDM_Accuracy()
|
||||
return self.LL_DDM_Accuracy or _SETTINGS:GetLL_DDM_Accuracy()
|
||||
end
|
||||
|
||||
--- Sets the SETTINGS LL DMS.
|
||||
-- @param #SETTINGS self
|
||||
-- @param #number LL_DMS
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetLL_DMS( LL_DMS )
|
||||
self.LL_DMS = LL_DMS
|
||||
end
|
||||
|
||||
--- Gets the SETTINGS LL DMS.
|
||||
-- @param #SETTINGS self
|
||||
-- @return #number
|
||||
function SETTINGS:GetLL_DMS()
|
||||
return self.LL_DMS or _SETTINGS:GetLL_DMS()
|
||||
end
|
||||
|
||||
--- Sets the SETTINGS MGRS accuracy.
|
||||
-- @param #SETTINGS self
|
||||
-- @param #number MGRS_Accuracy
|
||||
@@ -145,21 +132,50 @@ do -- SETTINGS
|
||||
return self.MGRS_Accuracy or _SETTINGS:GetMGRS_Accuracy()
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Sets A2G LL
|
||||
--- Sets the SETTINGS Message Display Timing of a MessageType
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetA2G_LL()
|
||||
self.A2GSystem = "LL"
|
||||
-- @param Core.Message#MESSAGE MessageType The type of the message.
|
||||
-- @param #number MessageTime The display time duration in seconds of the MessageType.
|
||||
function SETTINGS:SetMessageTime( MessageType, MessageTime )
|
||||
self.MessageTypeTimings = self.MessageTypeTimings or {}
|
||||
self.MessageTypeTimings[MessageType] = MessageTime
|
||||
end
|
||||
|
||||
|
||||
--- Gets the SETTINGS Message Display Timing of a MessageType
|
||||
-- @param #SETTINGS self
|
||||
-- @param Core.Message#MESSAGE MessageType The type of the message.
|
||||
-- @return #number
|
||||
function SETTINGS:GetMessageTime( MessageType )
|
||||
return ( self.MessageTypeTimings and self.MessageTypeTimings[MessageType] ) or _SETTINGS:GetMessageTime( MessageType )
|
||||
end
|
||||
|
||||
--- Is LL
|
||||
--- Sets A2G LL DMS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if LL
|
||||
function SETTINGS:IsA2G_LL()
|
||||
return ( self.A2GSystem and self.A2GSystem == "LL" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL() )
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetA2G_LL_DMS()
|
||||
self.A2GSystem = "LL DMS"
|
||||
end
|
||||
|
||||
--- Sets A2G LL DDM
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetA2G_LL_DDM()
|
||||
self.A2GSystem = "LL DDM"
|
||||
end
|
||||
|
||||
--- Is LL DMS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if LL DMS
|
||||
function SETTINGS:IsA2G_LL_DMS()
|
||||
return ( self.A2GSystem and self.A2GSystem == "LL DMS" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DMS() )
|
||||
end
|
||||
|
||||
--- Is LL DDM
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if LL DDM
|
||||
function SETTINGS:IsA2G_LL_DDM()
|
||||
return ( self.A2GSystem and self.A2GSystem == "LL DDM" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_LL_DDM() )
|
||||
end
|
||||
|
||||
--- Sets A2G MGRS
|
||||
@@ -179,31 +195,30 @@ do -- SETTINGS
|
||||
--- Sets A2G BRA
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetA2G_BRA()
|
||||
self.A2GSystem = "BRA"
|
||||
function SETTINGS:SetA2G_BR()
|
||||
self.A2GSystem = "BR"
|
||||
end
|
||||
|
||||
--- Is BRA
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if BRA
|
||||
function SETTINGS:IsA2G_BRA()
|
||||
self:E( { BRA = ( self.A2GSystem and self.A2GSystem == "BRA" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BRA() ) } )
|
||||
return ( self.A2GSystem and self.A2GSystem == "BRA" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BRA() )
|
||||
function SETTINGS:IsA2G_BR()
|
||||
return ( self.A2GSystem and self.A2GSystem == "BR" ) or ( not self.A2GSystem and _SETTINGS:IsA2G_BR() )
|
||||
end
|
||||
|
||||
--- Sets A2A BRA
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetA2A_BRA()
|
||||
self.A2ASystem = "BRA"
|
||||
function SETTINGS:SetA2A_BRAA()
|
||||
self.A2ASystem = "BRAA"
|
||||
end
|
||||
|
||||
--- Is BRA
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if BRA
|
||||
function SETTINGS:IsA2A_BRA()
|
||||
self:E( { BRA = ( self.A2ASystem and self.A2ASystem == "BRA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRA() ) } )
|
||||
return ( self.A2ASystem and self.A2ASystem == "BRA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRA() )
|
||||
function SETTINGS:IsA2A_BRAA()
|
||||
self:E( { BRA = ( self.A2ASystem and self.A2ASystem == "BRAA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRAA() ) } )
|
||||
return ( self.A2ASystem and self.A2ASystem == "BRAA" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BRAA() )
|
||||
end
|
||||
|
||||
--- Sets A2A BULLS
|
||||
@@ -220,69 +235,179 @@ do -- SETTINGS
|
||||
return ( self.A2ASystem and self.A2ASystem == "BULLS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_BULLS() )
|
||||
end
|
||||
|
||||
--- Sets A2A LL DMS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetA2A_LL_DMS()
|
||||
self.A2ASystem = "LL DMS"
|
||||
end
|
||||
|
||||
--- Sets A2A LL DDM
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetA2A_LL_DDM()
|
||||
self.A2ASystem = "LL DDM"
|
||||
end
|
||||
|
||||
--- Is LL DMS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if LL DMS
|
||||
function SETTINGS:IsA2A_LL_DMS()
|
||||
return ( self.A2ASystem and self.A2ASystem == "LL DMS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DMS() )
|
||||
end
|
||||
|
||||
--- Is LL DDM
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if LL DDM
|
||||
function SETTINGS:IsA2A_LL_DDM()
|
||||
return ( self.A2ASystem and self.A2ASystem == "LL DDM" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_LL_DDM() )
|
||||
end
|
||||
|
||||
--- Sets A2A MGRS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetA2A_MGRS()
|
||||
self.A2ASystem = "MGRS"
|
||||
end
|
||||
|
||||
--- Is MGRS
|
||||
-- @param #SETTINGS self
|
||||
-- @return #boolean true if MGRS
|
||||
function SETTINGS:IsA2A_MGRS()
|
||||
return ( self.A2ASystem and self.A2ASystem == "MGRS" ) or ( not self.A2ASystem and _SETTINGS:IsA2A_MGRS() )
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetSystemMenu( RootMenu, MenuText )
|
||||
function SETTINGS:SetSystemMenu( MenuGroup, RootMenu )
|
||||
|
||||
MenuText = MenuText or "System Settings"
|
||||
|
||||
if not self.SettingsMenu then
|
||||
self.SettingsMenu = MENU_MISSION:New( MenuText, RootMenu )
|
||||
end
|
||||
|
||||
if self.DefaultMenu then
|
||||
self.DefaultMenu:Remove()
|
||||
self.DefaultMenu = nil
|
||||
end
|
||||
self.DefaultMenu = MENU_MISSION:New( "Default Settings", self.SettingsMenu )
|
||||
local MenuText = "System Settings"
|
||||
|
||||
local A2GCoordinateMenu = MENU_MISSION:New( "A2G Coordinate System", self.DefaultMenu )
|
||||
local MenuTime = timer.getTime()
|
||||
|
||||
local SettingsMenu = MENU_GROUP:New( MenuGroup, MenuText, RootMenu ):SetTime( MenuTime )
|
||||
|
||||
local A2GCoordinateMenu = MENU_GROUP:New( MenuGroup, "A2G Coordinate System", SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
if self:IsA2G_LL() then
|
||||
MENU_MISSION_COMMAND:New( "Activate BRA", A2GCoordinateMenu, self.A2GMenuSystem, self, "BRA" )
|
||||
MENU_MISSION_COMMAND:New( "Activate MGRS", A2GCoordinateMenu, self.A2GMenuSystem, self, "MGRS" )
|
||||
MENU_MISSION_COMMAND:New( "LL Accuracy 1", A2GCoordinateMenu, self.MenuLL_Accuracy, self, 1 )
|
||||
MENU_MISSION_COMMAND:New( "LL Accuracy 2", A2GCoordinateMenu, self.MenuLL_Accuracy, self, 2 )
|
||||
MENU_MISSION_COMMAND:New( "LL Accuracy 3", A2GCoordinateMenu, self.MenuLL_Accuracy, self, 3 )
|
||||
MENU_MISSION_COMMAND:New( "LL Decimal On", A2GCoordinateMenu, self.MenuLL_DMS, self, true )
|
||||
MENU_MISSION_COMMAND:New( "LL Decimal Off", A2GCoordinateMenu, self.MenuLL_DMS, self, false )
|
||||
|
||||
if not self:IsA2G_LL_DMS() then
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
|
||||
if not self:IsA2G_LL_DDM() then
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if self:IsA2G_LL_DDM() then
|
||||
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 3", A2GCoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if not self:IsA2G_BR() then
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "BR" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if not self:IsA2G_MGRS() then
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.A2GMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if self:IsA2G_MGRS() then
|
||||
MENU_MISSION_COMMAND:New( "Activate BRA", A2GCoordinateMenu, self.A2GMenuSystem, self, "BRA" )
|
||||
MENU_MISSION_COMMAND:New( "Activate LL", A2GCoordinateMenu, self.A2GMenuSystem, self, "LL" )
|
||||
MENU_MISSION_COMMAND:New( "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, 1 )
|
||||
MENU_MISSION_COMMAND:New( "MGRS Accuracy 2", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, 2 )
|
||||
MENU_MISSION_COMMAND:New( "MGRS Accuracy 3", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, 3 )
|
||||
MENU_MISSION_COMMAND:New( "MGRS Accuracy 4", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, 4 )
|
||||
MENU_MISSION_COMMAND:New( "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, 5 )
|
||||
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 2", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 3", A2GCoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 3 ):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 )
|
||||
end
|
||||
|
||||
if self:IsA2G_BRA() then
|
||||
MENU_MISSION_COMMAND:New( "Activate MGRS", A2GCoordinateMenu, self.A2GMenuSystem, self, "MGRS" )
|
||||
MENU_MISSION_COMMAND:New( "Activate LL", A2GCoordinateMenu, self.A2GMenuSystem, self, "LL" )
|
||||
local A2ACoordinateMenu = MENU_GROUP:New( MenuGroup, "A2A Coordinate System", SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
if not self:IsA2A_LL_DMS() then
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DMS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
local A2ACoordinateMenu = MENU_MISSION:New( "A2A Coordinate System", self.DefaultMenu )
|
||||
|
||||
if self:IsA2A_BULLS() then
|
||||
MENU_MISSION_COMMAND:New( "Activate BRA", A2ACoordinateMenu, self.A2AMenuSystem, self, "BRA" )
|
||||
if not self:IsA2A_LL_DDM() then
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "LL DDM" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if self:IsA2A_BRA() then
|
||||
MENU_MISSION_COMMAND:New( "Activate BULLS", A2ACoordinateMenu, self.A2AMenuSystem, self, "BULLS" )
|
||||
|
||||
if self:IsA2A_LL_DDM() then
|
||||
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 3", A2ACoordinateMenu, self.MenuLL_DDM_Accuracy, self, MenuGroup, RootMenu, 3 ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if not self:IsA2A_BULLS() then
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Bullseye (BULLS)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BULLS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
local MetricsMenu = MENU_MISSION:New( "Measures and Weights System", self.DefaultMenu )
|
||||
if not self:IsA2A_BRAA() then
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "BRAA" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if not self:IsA2A_MGRS() then
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Military Grid (MGRS)", A2ACoordinateMenu, self.A2AMenuSystem, self, MenuGroup, RootMenu, "MGRS" ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if self:IsA2A_MGRS() then
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 1", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 1 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 2", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 2 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "MGRS Accuracy 3", A2ACoordinateMenu, self.MenuMGRS_Accuracy, self, MenuGroup, RootMenu, 3 ):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 )
|
||||
end
|
||||
|
||||
local MetricsMenu = MENU_GROUP:New( MenuGroup, "Measures and Weights System", SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
if self:IsMetric() then
|
||||
MENU_MISSION_COMMAND:New( "Activate Imperial", MetricsMenu, self.MenuMWSystem, self, false )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Imperial (Miles,Feet)", MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, false ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
if self:IsImperial() then
|
||||
MENU_MISSION_COMMAND:New( "Activate Metric", MetricsMenu, self.MenuMWSystem, self, true )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Metric (Kilometers,Meters)", MetricsMenu, self.MenuMWSystem, self, MenuGroup, RootMenu, true ):SetTime( MenuTime )
|
||||
end
|
||||
|
||||
local MessagesMenu = MENU_GROUP:New( MenuGroup, "Messages and Reports", SettingsMenu ):SetTime( MenuTime )
|
||||
|
||||
local UpdateMessagesMenu = MENU_GROUP:New( MenuGroup, "Update Messages", MessagesMenu ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "Off", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 0 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "5 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 5 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "10 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 10 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 15 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 30 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", UpdateMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Update, 60 ):SetTime( MenuTime )
|
||||
|
||||
local InformationMessagesMenu = MENU_GROUP:New( MenuGroup, "Information Messages", MessagesMenu ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "5 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 5 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "10 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 10 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 15 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 30 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 60 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", InformationMessagesMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Information, 120 ):SetTime( MenuTime )
|
||||
|
||||
local BriefingReportsMenu = MENU_GROUP:New( MenuGroup, "Briefing Reports", MessagesMenu ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 15 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 30 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 60 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 120 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", BriefingReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Briefing, 180 ):SetTime( MenuTime )
|
||||
|
||||
local OverviewReportsMenu = MENU_GROUP:New( MenuGroup, "Overview Reports", MessagesMenu ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 15 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 30 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "1 minute", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 60 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "2 minutes", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 120 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "3 minutes", OverviewReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.Overview, 180 ):SetTime( MenuTime )
|
||||
|
||||
local DetailedReportsMenu = MENU_GROUP:New( MenuGroup, "Detailed Reports", MessagesMenu ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "15 seconds", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 15 ):SetTime( MenuTime )
|
||||
MENU_GROUP_COMMAND:New( MenuGroup, "30 seconds", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 30 ):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, "3 minutes", DetailedReportsMenu, self.MenuMessageTimingsSystem, self, MenuGroup, RootMenu, MESSAGE.Type.DetailedReportsMenu, 180 ):SetTime( MenuTime )
|
||||
|
||||
|
||||
SettingsMenu:Remove( MenuTime )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -293,35 +418,39 @@ do -- SETTINGS
|
||||
-- @return #SETTINGS
|
||||
function SETTINGS:SetPlayerMenu( PlayerUnit )
|
||||
|
||||
local MenuText = "Player Settings"
|
||||
self.MenuText = MenuText
|
||||
|
||||
local SettingsMenu = _SETTINGS.SettingsMenu
|
||||
|
||||
local PlayerGroup = PlayerUnit:GetGroup()
|
||||
local PlayerName = PlayerUnit:GetPlayerName()
|
||||
local PlayerNames = PlayerGroup:GetPlayerNames()
|
||||
|
||||
local GroupMenu = MENU_GROUP:New( PlayerGroup, MenuText, SettingsMenu )
|
||||
local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"', GroupMenu )
|
||||
local PlayerMenu = MENU_GROUP:New( PlayerGroup, 'Settings "' .. PlayerName .. '"' )
|
||||
|
||||
self.PlayerMenu = PlayerMenu
|
||||
|
||||
local A2GCoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2G Coordinate System", PlayerMenu )
|
||||
|
||||
if self:IsA2G_LL() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Activate BRA", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRA" )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Activate MGRS", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL Decimal On", A2GCoordinateMenu, self.MenuGroupLL_DMSSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL Decimal Off", A2GCoordinateMenu, self.MenuGroupLL_DMSSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
|
||||
if not self:IsA2G_LL_DMS() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
|
||||
end
|
||||
|
||||
if not self:IsA2G_LL_DDM() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
|
||||
end
|
||||
|
||||
if self:IsA2G_LL_DDM() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||
end
|
||||
|
||||
if not self:IsA2G_BR() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing, Range (BR)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BR" )
|
||||
end
|
||||
|
||||
if not self:IsA2G_MGRS() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
||||
end
|
||||
|
||||
if self:IsA2G_MGRS() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Activate BRA", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRA" )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Activate LL", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL" )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 1", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 2", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 3", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||
@@ -329,30 +458,93 @@ do -- SETTINGS
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "MGRS Accuracy 5", A2GCoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
|
||||
end
|
||||
|
||||
if self:IsA2G_BRA() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Activate MGRS", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Activate LL", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL" )
|
||||
end
|
||||
|
||||
local A2ACoordinateMenu = MENU_GROUP:New( PlayerGroup, "A2A Coordinate System", PlayerMenu )
|
||||
|
||||
if self:IsA2A_BULLS() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Activate BRA", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRA" )
|
||||
|
||||
if not self:IsA2A_LL_DMS() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Min Sec (LL DMS)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DMS" )
|
||||
end
|
||||
|
||||
if self:IsA2A_BRA() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Activate BULLS", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
|
||||
if not self:IsA2A_LL_DDM() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Lat/Lon Degree Dec Min (LL DDM)", A2GCoordinateMenu, self.MenuGroupA2GSystem, self, PlayerUnit, PlayerGroup, PlayerName, "LL DDM" )
|
||||
end
|
||||
|
||||
if self:IsA2A_LL_DDM() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 1", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 2", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "LL DDM Accuracy 3", A2GCoordinateMenu, self.MenuGroupLL_DDM_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||
end
|
||||
|
||||
if not self:IsA2A_BULLS() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Bullseye (BULLS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BULLS" )
|
||||
end
|
||||
|
||||
if not self:IsA2A_BRAA() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Bearing Range Altitude Aspect (BRAA)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "BRAA" )
|
||||
end
|
||||
|
||||
if not self:IsA2A_MGRS() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS)", A2ACoordinateMenu, self.MenuGroupA2ASystem, self, PlayerUnit, PlayerGroup, PlayerName, "MGRS" )
|
||||
end
|
||||
|
||||
if self:IsA2A_MGRS() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 1", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 1 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 2", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 2 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 3", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 3 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 4", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 4 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Military Grid (MGRS) Accuracy 5", A2ACoordinateMenu, self.MenuGroupMGRS_AccuracySystem, self, PlayerUnit, PlayerGroup, PlayerName, 5 )
|
||||
end
|
||||
|
||||
local MetricsMenu = MENU_GROUP:New( PlayerGroup, "Measures and Weights System", PlayerMenu )
|
||||
|
||||
if self:IsMetric() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Activate Imperial", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Imperial (Miles,Feet)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, false )
|
||||
end
|
||||
|
||||
if self:IsImperial() then
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Activate Metric", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "Metric (Kilometers,Meters)", MetricsMenu, self.MenuGroupMWSystem, self, PlayerUnit, PlayerGroup, PlayerName, true )
|
||||
end
|
||||
|
||||
|
||||
local MessagesMenu = MENU_GROUP:New( PlayerGroup, "Messages and Reports", PlayerMenu )
|
||||
|
||||
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, "5 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 5 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "10 seconds", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 10 )
|
||||
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, "1 minute", UpdateMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Update, 60 )
|
||||
|
||||
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, "10 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 10 )
|
||||
MENU_GROUP_COMMAND:New( PlayerGroup, "15 seconds", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 15 )
|
||||
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, "2 minutes", InformationMessagesMenu, self.MenuGroupMessageTimingsSystem, self, PlayerUnit, PlayerGroup, PlayerName, MESSAGE.Type.Information, 120 )
|
||||
|
||||
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, "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, "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 )
|
||||
|
||||
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, "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, "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 )
|
||||
|
||||
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, "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, "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 )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -372,40 +564,44 @@ do -- SETTINGS
|
||||
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:A2GMenuSystem( A2GSystem )
|
||||
function SETTINGS:A2GMenuSystem( MenuGroup, RootMenu, A2GSystem )
|
||||
self.A2GSystem = A2GSystem
|
||||
self:SetSystemMenu()
|
||||
MESSAGE:New( string.format("Settings: Default A2G coordinate system set to %s for all players!", A2GSystem ), 5 ):ToAll()
|
||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:A2AMenuSystem( A2ASystem )
|
||||
function SETTINGS:A2AMenuSystem( MenuGroup, RootMenu, A2ASystem )
|
||||
self.A2ASystem = A2ASystem
|
||||
self:SetSystemMenu()
|
||||
MESSAGE:New( string.format("Settings: Default A2A coordinate system set to %s for all players!", A2ASystem ), 5 ):ToAll()
|
||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuLL_Accuracy( LL_Accuracy )
|
||||
function SETTINGS:MenuLL_DDM_Accuracy( MenuGroup, RootMenu, LL_Accuracy )
|
||||
self.LL_Accuracy = LL_Accuracy
|
||||
self:SetSystemMenu()
|
||||
MESSAGE:New( string.format("Settings: Default LL accuracy set to %s for all players!", LL_Accuracy ), 5 ):ToAll()
|
||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuLL_DMS( LL_DMS )
|
||||
self.LL_DMS = LL_DMS
|
||||
self:SetSystemMenu()
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuMGRS_Accuracy( MGRS_Accuracy )
|
||||
function SETTINGS:MenuMGRS_Accuracy( MenuGroup, RootMenu, MGRS_Accuracy )
|
||||
self.MGRS_Accuracy = MGRS_Accuracy
|
||||
self:SetSystemMenu()
|
||||
MESSAGE:New( string.format("Settings: Default MGRS accuracy set to %s for all players!", MGRS_Accuracy ), 5 ):ToAll()
|
||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuMWSystem( MW )
|
||||
function SETTINGS:MenuMWSystem( MenuGroup, RootMenu, MW )
|
||||
self.Metric = MW
|
||||
MESSAGE:New( string.format("Settings: Default measurement format set to %s for all players!.", MW and "Metric" or "Imperial" ), 5 ):ToAll()
|
||||
self:SetSystemMenu()
|
||||
MESSAGE:New( string.format("Settings: Default measurement format set to %s for all players!", MW and "Metric" or "Imperial" ), 5 ):ToAll()
|
||||
self:SetSystemMenu( MenuGroup, RootMenu )
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuMessageTimingsSystem( MenuGroup, RootMenu, MessageType, MessageTime )
|
||||
self:SetMessageTime( MessageType, MessageTime )
|
||||
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToAll()
|
||||
end
|
||||
|
||||
do
|
||||
@@ -413,7 +609,7 @@ do -- SETTINGS
|
||||
function SETTINGS:MenuGroupA2GSystem( PlayerUnit, PlayerGroup, PlayerName, A2GSystem )
|
||||
BASE:E( {self, PlayerUnit:GetName(), A2GSystem} )
|
||||
self.A2GSystem = A2GSystem
|
||||
MESSAGE:New( string.format("Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
MESSAGE:New( string.format( "Settings: A2G format set to %s for player %s.", A2GSystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
@@ -421,42 +617,40 @@ do -- SETTINGS
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuGroupA2ASystem( PlayerUnit, PlayerGroup, PlayerName, A2ASystem )
|
||||
self.A2ASystem = A2ASystem
|
||||
MESSAGE:New( string.format("Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
MESSAGE:New( string.format( "Settings: A2A format set to %s for player %s.", A2ASystem, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuGroupLL_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
|
||||
function SETTINGS:MenuGroupLL_DDM_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, LL_Accuracy )
|
||||
self.LL_Accuracy = LL_Accuracy
|
||||
MESSAGE:New( string.format("Settings: A2G LL format accuracy set to %d for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
MESSAGE:New( string.format( "Settings: A2G LL format accuracy set to %d for player %s.", LL_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuGroupLL_DMSSystem( PlayerUnit, PlayerGroup, PlayerName, LL_DMS )
|
||||
self.LL_DMS = LL_DMS
|
||||
MESSAGE:New( string.format("Settings: A2G LL format mode set to %s for player %s.", LL_DMS and "DMS" or "HMS", PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuGroupMGRS_AccuracySystem( PlayerUnit, PlayerGroup, PlayerName, MGRS_Accuracy )
|
||||
self.MGRS_Accuracy = MGRS_Accuracy
|
||||
MESSAGE:New( string.format("Settings: A2G MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
MESSAGE:New( string.format( "Settings: A2G MGRS format accuracy set to %d for player %s.", MGRS_Accuracy, PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuGroupMWSystem( PlayerUnit, PlayerGroup, PlayerName, MW )
|
||||
self.Metrics = MW
|
||||
MESSAGE:New( string.format("Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
self.Metric = MW
|
||||
MESSAGE:New( string.format( "Settings: Measurement format set to %s for player %s.", MW and "Metric" or "Imperial", PlayerName ), 5 ):ToGroup( PlayerGroup )
|
||||
self:RemovePlayerMenu(PlayerUnit)
|
||||
self:SetPlayerMenu(PlayerUnit)
|
||||
end
|
||||
|
||||
--- @param #SETTINGS self
|
||||
function SETTINGS:MenuGroupMessageTimingsSystem( PlayerUnit, PlayerGroup, PlayerName, MessageType, MessageTime )
|
||||
self:SetMessageTime( MessageType, MessageTime )
|
||||
MESSAGE:New( string.format( "Settings: Default message time set for %s to %d.", MessageType, MessageTime ), 5 ):ToGroup( PlayerGroup )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Spawn dynamically new GROUPs in your missions.
|
||||
--- **Core** -- SPAWN class dynamically spawns new groups of units in your missions.
|
||||
--
|
||||
-- 
|
||||
--
|
||||
@@ -55,8 +55,12 @@
|
||||
|
||||
--- # SPAWN class, extends @{Base#BASE}
|
||||
--
|
||||
-- -- 
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- The SPAWN class allows to spawn dynamically new groups.
|
||||
-- Each SPAWN object needs to be have a related **template group** setup in the Mission Editor (ME),
|
||||
-- Each SPAWN object needs to be have related **template groups** setup in the Mission Editor (ME),
|
||||
-- which is a normal group with the **Late Activation** flag set.
|
||||
-- This template group will never be activated in your mission.
|
||||
-- SPAWN uses that **template group** to reference to all the characteristics
|
||||
@@ -200,6 +204,7 @@
|
||||
-- * @{#SPAWN.SpawnFromStatic}(): Spawn a new group from a structure, taking the position of a @{Static}.
|
||||
-- * @{#SPAWN.SpawnFromUnit}(): Spawn a new group taking the position of a @{Unit}.
|
||||
-- * @{#SPAWN.SpawnInZone}(): Spawn a new group in a @{Zone}.
|
||||
-- * @{#SPAWN.SpawnAtAirbase}(): Spawn a new group at an @{Airbase}, which can be an airdrome, ship or helipad.
|
||||
--
|
||||
-- Note that @{#SPAWN.Spawn} and @{#SPAWN.ReSpawn} return a @{GROUP#GROUP.New} object, that contains a reference to the DCSGroup object.
|
||||
-- You can use the @{GROUP} object to do further actions with the DCSGroup.
|
||||
@@ -270,8 +275,12 @@ SPAWN = {
|
||||
-- @extends Wrapper.Group#GROUP.Takeoff
|
||||
|
||||
--- @field #SPAWN.Takeoff Takeoff
|
||||
SPAWN.Takeoff = GROUP.Takeoff
|
||||
|
||||
SPAWN.Takeoff = {
|
||||
Air = 1,
|
||||
Runway = 2,
|
||||
Hot = 3,
|
||||
Cold = 4,
|
||||
}
|
||||
|
||||
--- @type SPAWN.SpawnZoneTable
|
||||
-- @list <Core.Zone#ZONE_BASE> SpawnZone
|
||||
@@ -289,7 +298,7 @@ function SPAWN:New( SpawnTemplatePrefix )
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #SPAWN
|
||||
self:F( { SpawnTemplatePrefix } )
|
||||
|
||||
local TemplateGroup = Group.getByName( SpawnTemplatePrefix )
|
||||
local TemplateGroup = GROUP:FindByName( SpawnTemplatePrefix )
|
||||
if TemplateGroup then
|
||||
self.SpawnTemplatePrefix = SpawnTemplatePrefix
|
||||
self.SpawnIndex = 0
|
||||
@@ -333,7 +342,7 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix )
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
self:F( { SpawnTemplatePrefix, SpawnAliasPrefix } )
|
||||
|
||||
local TemplateGroup = Group.getByName( SpawnTemplatePrefix )
|
||||
local TemplateGroup = GROUP:FindByName( SpawnTemplatePrefix )
|
||||
if TemplateGroup then
|
||||
self.SpawnTemplatePrefix = SpawnTemplatePrefix
|
||||
self.SpawnAliasPrefix = SpawnAliasPrefix
|
||||
@@ -520,6 +529,73 @@ function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Randomize templates to be used as the unit representatives for the Spawned group, defined using a SET_GROUP object.
|
||||
-- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor,
|
||||
-- but they will all follow the same Template route and have the same prefix name.
|
||||
-- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group.
|
||||
-- @param #SPAWN self
|
||||
-- @param Core.Set#SET_GROUP SpawnTemplateSet A SET_GROUP object set, that contains the groups that are possible unit representatives of the group to be spawned.
|
||||
-- @return #SPAWN
|
||||
-- @usage
|
||||
-- -- NATO Tank Platoons invading Gori.
|
||||
--
|
||||
-- -- Choose between different 'US Tank Platoon Template' configurations to be spawned for the
|
||||
-- -- 'US Tank Platoon Left', 'US Tank Platoon Middle' and 'US Tank Platoon Right' SPAWN objects.
|
||||
--
|
||||
-- -- Each new SPAWN will randomize the route, with a defined time interval of 200 seconds with 40% time variation (randomization) and
|
||||
-- -- with a limit set of maximum 12 Units alive simulteneously and 150 Groups to be spawned during the whole mission.
|
||||
--
|
||||
-- Spawn_US_PlatoonSet = SET_GROUP:New():FilterPrefixes( "US Tank Platoon Templates" ):FilterOnce()
|
||||
--
|
||||
-- --- Now use the Spawn_US_PlatoonSet to define the templates using InitRandomizeTemplateSet.
|
||||
-- Spawn_US_Platoon_Left = SPAWN:New( 'US Tank Platoon Left' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
|
||||
-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
|
||||
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplateSet( Spawn_US_PlatoonSet ):InitRandomizeRoute( 3, 3, 2000 )
|
||||
function SPAWN:InitRandomizeTemplateSet( SpawnTemplateSet ) -- R2.3
|
||||
self:F( { self.SpawnTemplatePrefix } )
|
||||
|
||||
self.SpawnTemplatePrefixTable = SpawnTemplateSet:GetSetNames()
|
||||
self.SpawnRandomizeTemplate = true
|
||||
|
||||
for SpawnGroupID = 1, self.SpawnMaxGroups do
|
||||
self:_RandomizeTemplate( SpawnGroupID )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Randomize templates to be used as the unit representatives for the Spawned group, defined by specifying the prefix names.
|
||||
-- This method becomes useful when you need to spawn groups with random templates of groups defined within the mission editor,
|
||||
-- but they will all follow the same Template route and have the same prefix name.
|
||||
-- In other words, this method randomizes between a defined set of groups the template to be used for each new spawn of a group.
|
||||
-- @param #SPAWN self
|
||||
-- @param #string SpawnTemplatePrefixes A string or a list of string that contains the prefixes of the groups that are possible unit representatives of the group to be spawned.
|
||||
-- @return #SPAWN
|
||||
-- @usage
|
||||
-- -- NATO Tank Platoons invading Gori.
|
||||
--
|
||||
-- -- Choose between different 'US Tank Platoon Templates' configurations to be spawned for the
|
||||
-- -- 'US Tank Platoon Left', 'US Tank Platoon Middle' and 'US Tank Platoon Right' SPAWN objects.
|
||||
--
|
||||
-- -- Each new SPAWN will randomize the route, with a defined time interval of 200 seconds with 40% time variation (randomization) and
|
||||
-- -- with a limit set of maximum 12 Units alive simulteneously and 150 Groups to be spawned during the whole mission.
|
||||
--
|
||||
-- Spawn_US_Platoon_Left = SPAWN:New( 'US Tank Platoon Left' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
|
||||
-- Spawn_US_Platoon_Middle = SPAWN:New( 'US Tank Platoon Middle' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
|
||||
-- Spawn_US_Platoon_Right = SPAWN:New( 'US Tank Platoon Right' ):InitLimit( 12, 150 ):Schedule( 200, 0.4 ):InitRandomizeTemplatePrefixes( "US Tank Platoon Templates" ):InitRandomizeRoute( 3, 3, 2000 )
|
||||
function SPAWN:InitRandomizeTemplatePrefixes( SpawnTemplatePrefixes ) --R2.3
|
||||
self:F( { self.SpawnTemplatePrefix } )
|
||||
|
||||
local SpawnTemplateSet = SET_GROUP:New():FilterPrefixes( SpawnTemplatePrefixes ):FilterOnce()
|
||||
|
||||
self:InitRandomizeTemplateSet( SpawnTemplateSet )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- When spawning a new group, make the grouping of the units according the InitGrouping setting.
|
||||
-- @param #SPAWN self
|
||||
-- @param #number Grouping Indicates the maximum amount of units in the group.
|
||||
@@ -982,19 +1058,53 @@ function SPAWN:OnSpawnGroup( SpawnCallBackFunction, ... )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Will spawn a group at an airbase.
|
||||
--- Will spawn a group at an @{Airbase}.
|
||||
-- This method is mostly advisable to be used if you want to simulate spawning units at an airbase.
|
||||
-- Note that each point in the route assigned to the spawning group is reset to the point of the spawn.
|
||||
-- You can use the returned group to further define the route to be followed.
|
||||
--
|
||||
-- The @{Airbase#AIRBASE} object must refer to a valid airbase known in the sim.
|
||||
-- You can use the following enumerations to search for the pre-defined airbases on the current known maps of DCS:
|
||||
--
|
||||
-- * @{Airbase#AIRBASE.Caucasus}: The airbases on the Caucasus map.
|
||||
-- * @{Airbase#AIRBASE.Nevada}: The airbases on the Nevada (NTTR) map.
|
||||
-- * @{Airbase#AIRBASE.Normandy}: The airbases on the Normandy map.
|
||||
--
|
||||
-- Use the method @{Airbase#AIRBASE.FindByName}() to retrieve the airbase object.
|
||||
-- The known AIRBASE objects are automatically imported at mission start by MOOSE.
|
||||
-- Therefore, there isn't any New() constructor defined for AIRBASE objects.
|
||||
--
|
||||
-- Ships and Farps are added within the mission, and are therefore not known.
|
||||
-- For these AIRBASE objects, there isn't an @{Airbase#AIRBASE} enumeration defined.
|
||||
-- You need to provide the **exact name** of the airbase as the parameter to the @{Airbase#AIRBASE.FindByName}() method!
|
||||
--
|
||||
-- @param #SPAWN self
|
||||
-- @param Wrapper.Airbase#AIRBASE Airbase The @{Airbase} where to spawn the group.
|
||||
-- @param Wrapper.Airbase#AIRBASE SpawnAirbase The @{Airbase} where to spawn the group.
|
||||
-- @param #SPAWN.Takeoff Takeoff (optional) The location and takeoff method. Default is Hot.
|
||||
-- @param #number TakeoffAltitude (optional) The altitude above the ground.
|
||||
-- @return Wrapper.Group#GROUP that was spawned.
|
||||
-- @return #nil Nothing was spawned.
|
||||
function SPAWN:SpawnAtAirbase( Airbase, Takeoff ) -- R2.2
|
||||
self:F( { self.SpawnTemplatePrefix, Airbase } )
|
||||
-- @usage
|
||||
-- Spawn_Plane = SPAWN:New( "Plane" )
|
||||
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Cold )
|
||||
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Hot )
|
||||
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( AIRBASE.Caucasus.Krymsk ), SPAWN.Takeoff.Runway )
|
||||
--
|
||||
-- Spawn_Plane:SpawnAtAirbase( AIRBASE:FindByName( "Carrier" ), SPAWN.Takeoff.Cold )
|
||||
--
|
||||
-- Spawn_Heli = SPAWN:New( "Heli")
|
||||
--
|
||||
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Cold" ), SPAWN.Takeoff.Cold )
|
||||
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Hot" ), SPAWN.Takeoff.Hot )
|
||||
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Runway" ), SPAWN.Takeoff.Runway )
|
||||
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "FARP Air" ), SPAWN.Takeoff.Air )
|
||||
--
|
||||
-- Spawn_Heli:SpawnAtAirbase( AIRBASE:FindByName( "Carrier" ), SPAWN.Takeoff.Cold )
|
||||
--
|
||||
function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude ) -- R2.2
|
||||
self:E( { self.SpawnTemplatePrefix, SpawnAirbase, Takeoff, TakeoffAltitude } )
|
||||
|
||||
local PointVec3 = Airbase:GetPointVec3()
|
||||
local PointVec3 = SpawnAirbase:GetPointVec3()
|
||||
self:T2(PointVec3)
|
||||
|
||||
Takeoff = Takeoff or SPAWN.Takeoff.Hot
|
||||
@@ -1005,34 +1115,87 @@ function SPAWN:SpawnAtAirbase( Airbase, Takeoff ) -- R2.2
|
||||
|
||||
if SpawnTemplate then
|
||||
|
||||
self:T( { "Current point of ", self.SpawnTemplatePrefix, Airbase } )
|
||||
self:T( { "Current point of ", self.SpawnTemplatePrefix, SpawnAirbase } )
|
||||
|
||||
local SpawnPoint = SpawnTemplate.route.points[1]
|
||||
|
||||
-- These are only for ships.
|
||||
SpawnPoint.linkUnit = nil
|
||||
SpawnPoint.helipadId = nil
|
||||
SpawnPoint.airdromeId = nil
|
||||
|
||||
local AirbaseID = SpawnAirbase:GetID()
|
||||
local AirbaseCategory = SpawnAirbase:GetDesc().category
|
||||
self:F( { AirbaseCategory = AirbaseCategory } )
|
||||
|
||||
if AirbaseCategory == Airbase.Category.SHIP then
|
||||
SpawnPoint.linkUnit = AirbaseID
|
||||
SpawnPoint.helipadId = AirbaseID
|
||||
elseif AirbaseCategory == Airbase.Category.HELIPAD then
|
||||
SpawnPoint.linkUnit = AirbaseID
|
||||
SpawnPoint.helipadId = AirbaseID
|
||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
||||
SpawnPoint.airdromeId = AirbaseID
|
||||
end
|
||||
|
||||
SpawnPoint.alt = 0
|
||||
|
||||
SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
|
||||
SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
|
||||
|
||||
|
||||
-- Translate the position of the Group Template to the Vec3.
|
||||
for UnitID = 1, #SpawnTemplate.units do
|
||||
self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
|
||||
-- These cause a lot of confusion.
|
||||
local UnitTemplate = SpawnTemplate.units[UnitID]
|
||||
|
||||
UnitTemplate.parking = nil
|
||||
UnitTemplate.parking_id = nil
|
||||
UnitTemplate.alt = 0
|
||||
|
||||
local SX = UnitTemplate.x
|
||||
local SY = UnitTemplate.y
|
||||
local BX = SpawnTemplate.route.points[1].x
|
||||
local BY = SpawnTemplate.route.points[1].y
|
||||
local BX = SpawnPoint.x
|
||||
local BY = SpawnPoint.y
|
||||
local TX = PointVec3.x + ( SX - BX )
|
||||
local TY = PointVec3.z + ( SY - BY )
|
||||
SpawnTemplate.units[UnitID].x = TX
|
||||
SpawnTemplate.units[UnitID].y = TY
|
||||
SpawnTemplate.units[UnitID].alt = PointVec3.y
|
||||
self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
|
||||
UnitTemplate.x = TX
|
||||
UnitTemplate.y = TY
|
||||
|
||||
if Takeoff == GROUP.Takeoff.Air then
|
||||
UnitTemplate.alt = PointVec3.y + ( TakeoffAltitude or 200 )
|
||||
--else
|
||||
-- UnitTemplate.alt = PointVec3.y + 10
|
||||
end
|
||||
self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y )
|
||||
end
|
||||
|
||||
SpawnTemplate.route.points[1].x = PointVec3.x
|
||||
SpawnTemplate.route.points[1].y = PointVec3.z
|
||||
SpawnTemplate.route.points[1].alt = Airbase.y
|
||||
SpawnTemplate.route.points[1].type = GROUPTEMPLATE.Takeoff[Takeoff]
|
||||
SpawnTemplate.route.points[1].airdromeId = Airbase:GetID()
|
||||
SpawnPoint.x = PointVec3.x
|
||||
SpawnPoint.y = PointVec3.z
|
||||
|
||||
if Takeoff == GROUP.Takeoff.Air then
|
||||
SpawnPoint.alt = PointVec3.y + ( TakeoffAltitude or 200 )
|
||||
--else
|
||||
-- SpawnPoint.alt = PointVec3.y + 10
|
||||
end
|
||||
|
||||
SpawnTemplate.x = PointVec3.x
|
||||
SpawnTemplate.y = PointVec3.z
|
||||
|
||||
return self:SpawnWithIndex( self.SpawnIndex )
|
||||
|
||||
local GroupSpawned = self:SpawnWithIndex( self.SpawnIndex )
|
||||
|
||||
-- When spawned in the air, we need to generate a Takeoff Event
|
||||
|
||||
if Takeoff == GROUP.Takeoff.Air then
|
||||
for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do
|
||||
SCHEDULER:New( nil, BASE.CreateEventTakeoff, { timer.getTime(), UnitSpawned:GetDCSObject() } , 1 )
|
||||
end
|
||||
end
|
||||
|
||||
return GroupSpawned
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1068,6 +1231,8 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
||||
if SpawnTemplate then
|
||||
|
||||
self:T( { "Current point of ", self.SpawnTemplatePrefix, Vec3 } )
|
||||
|
||||
local TemplateHeight = SpawnTemplate.route.points[1].alt
|
||||
|
||||
-- Translate the position of the Group Template to the Vec3.
|
||||
for UnitID = 1, #SpawnTemplate.units do
|
||||
@@ -1081,16 +1246,20 @@ function SPAWN:SpawnFromVec3( Vec3, SpawnIndex )
|
||||
local TY = Vec3.z + ( SY - BY )
|
||||
SpawnTemplate.units[UnitID].x = TX
|
||||
SpawnTemplate.units[UnitID].y = TY
|
||||
SpawnTemplate.units[UnitID].alt = Vec3.y
|
||||
if SpawnTemplate.CategoryID ~= Group.Category.SHIP then
|
||||
SpawnTemplate.units[UnitID].alt = Vec3.y or TemplateHeight
|
||||
end
|
||||
self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y )
|
||||
end
|
||||
|
||||
SpawnTemplate.route.points[1].x = Vec3.x
|
||||
SpawnTemplate.route.points[1].y = Vec3.z
|
||||
SpawnTemplate.route.points[1].alt = Vec3.y
|
||||
|
||||
if SpawnTemplate.CategoryID ~= Group.Category.SHIP then
|
||||
SpawnTemplate.route.points[1].alt = Vec3.y or TemplateHeight
|
||||
end
|
||||
SpawnTemplate.x = Vec3.x
|
||||
SpawnTemplate.y = Vec3.z
|
||||
SpawnTemplate.alt = Vec3.y or TemplateHeight
|
||||
|
||||
return self:SpawnWithIndex( self.SpawnIndex )
|
||||
end
|
||||
@@ -1105,14 +1274,31 @@ end
|
||||
-- You can use the returned group to further define the route to be followed.
|
||||
-- @param #SPAWN self
|
||||
-- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 coordinates where to spawn the group.
|
||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||
-- @return Wrapper.Group#GROUP that was spawned.
|
||||
-- @return #nil Nothing was spawned.
|
||||
function SPAWN:SpawnFromVec2( Vec2, SpawnIndex )
|
||||
self:F( { self.SpawnTemplatePrefix, Vec2, SpawnIndex } )
|
||||
-- @usage
|
||||
--
|
||||
-- local SpawnVec2 = ZONE:New( ZoneName ):GetVec2()
|
||||
--
|
||||
-- -- Spawn at the zone center position at the height specified in the ME of the group template!
|
||||
-- SpawnAirplanes:SpawnFromVec2( SpawnVec2 )
|
||||
--
|
||||
-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters.
|
||||
-- SpawnAirplanes:SpawnFromVec2( SpawnVec2, 2000, 4000 )
|
||||
--
|
||||
function SPAWN:SpawnFromVec2( Vec2, MinHeight, MaxHeight, SpawnIndex )
|
||||
self:F( { self.SpawnTemplatePrefix, self.SpawnIndex, Vec2, MinHeight, MaxHeight, SpawnIndex } )
|
||||
|
||||
local PointVec2 = POINT_VEC2:NewFromVec2( Vec2 )
|
||||
return self:SpawnFromVec3( PointVec2:GetVec3(), SpawnIndex )
|
||||
local Height = nil
|
||||
|
||||
if MinHeight and MaxHeight then
|
||||
Height = math.random( MinHeight, MaxHeight)
|
||||
end
|
||||
|
||||
return self:SpawnFromVec3( { x = Vec2.x, y = Height, z = Vec2.y }, SpawnIndex ) -- y can be nil. In this case, spawn on the ground for vehicles, and in the template altitude for air.
|
||||
end
|
||||
|
||||
|
||||
@@ -1121,14 +1307,26 @@ end
|
||||
-- You can use the returned group to further define the route to be followed.
|
||||
-- @param #SPAWN self
|
||||
-- @param Wrapper.Unit#UNIT HostUnit The air or ground unit dropping or unloading the group.
|
||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||
-- @return Wrapper.Group#GROUP that was spawned.
|
||||
-- @return #nil Nothing was spawned.
|
||||
function SPAWN:SpawnFromUnit( HostUnit, SpawnIndex )
|
||||
self:F( { self.SpawnTemplatePrefix, HostUnit, SpawnIndex } )
|
||||
-- @usage
|
||||
--
|
||||
-- local SpawnStatic = STATIC:FindByName( StaticName )
|
||||
--
|
||||
-- -- Spawn from the static position at the height specified in the ME of the group template!
|
||||
-- SpawnAirplanes:SpawnFromUnit( SpawnStatic )
|
||||
--
|
||||
-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters.
|
||||
-- SpawnAirplanes:SpawnFromUnit( SpawnStatic, 2000, 4000 )
|
||||
--
|
||||
function SPAWN:SpawnFromUnit( HostUnit, MinHeight, MaxHeight, SpawnIndex )
|
||||
self:F( { self.SpawnTemplatePrefix, HostUnit, MinHeight, MaxHeight, SpawnIndex } )
|
||||
|
||||
if HostUnit and HostUnit:IsAlive() ~= nil then -- and HostUnit:getUnit(1):inAir() == false then
|
||||
return self:SpawnFromVec3( HostUnit:GetVec3(), SpawnIndex )
|
||||
return self:SpawnFromVec2( HostUnit:GetVec2(), MinHeight, MaxHeight, SpawnIndex )
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -1138,14 +1336,26 @@ end
|
||||
-- You can use the returned group to further define the route to be followed.
|
||||
-- @param #SPAWN self
|
||||
-- @param Wrapper.Static#STATIC HostStatic The static dropping or unloading the group.
|
||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||
-- @return Wrapper.Group#GROUP that was spawned.
|
||||
-- @return #nil Nothing was spawned.
|
||||
function SPAWN:SpawnFromStatic( HostStatic, SpawnIndex )
|
||||
self:F( { self.SpawnTemplatePrefix, HostStatic, SpawnIndex } )
|
||||
-- @usage
|
||||
--
|
||||
-- local SpawnStatic = STATIC:FindByName( StaticName )
|
||||
--
|
||||
-- -- Spawn from the static position at the height specified in the ME of the group template!
|
||||
-- SpawnAirplanes:SpawnFromStatic( SpawnStatic )
|
||||
--
|
||||
-- -- Spawn from the static position at the height randomized between 2000 and 4000 meters.
|
||||
-- SpawnAirplanes:SpawnFromStatic( SpawnStatic, 2000, 4000 )
|
||||
--
|
||||
function SPAWN:SpawnFromStatic( HostStatic, MinHeight, MaxHeight, SpawnIndex )
|
||||
self:F( { self.SpawnTemplatePrefix, HostStatic, MinHeight, MaxHeight, SpawnIndex } )
|
||||
|
||||
if HostStatic and HostStatic:IsAlive() then
|
||||
return self:SpawnFromVec3( HostStatic:GetVec3(), SpawnIndex )
|
||||
return self:SpawnFromVec2( HostStatic:GetVec2(), MinHeight, MaxHeight, SpawnIndex )
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -1158,17 +1368,38 @@ end
|
||||
-- @param #SPAWN self
|
||||
-- @param Core.Zone#ZONE Zone The zone where the group is to be spawned.
|
||||
-- @param #boolean RandomizeGroup (optional) Randomization of the @{Group} position in the zone.
|
||||
-- @param #number MinHeight (optional) The minimum height to spawn an airborne group into the zone.
|
||||
-- @param #number MaxHeight (optional) The maximum height to spawn an airborne group into the zone.
|
||||
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
|
||||
-- @return Wrapper.Group#GROUP that was spawned.
|
||||
-- @return #nil when nothing was spawned.
|
||||
function SPAWN:SpawnInZone( Zone, RandomizeGroup, SpawnIndex )
|
||||
self:F( { self.SpawnTemplatePrefix, Zone, RandomizeGroup, SpawnIndex } )
|
||||
-- @usage
|
||||
--
|
||||
-- local SpawnZone = ZONE:New( ZoneName )
|
||||
--
|
||||
-- -- Spawn at the zone center position at the height specified in the ME of the group template!
|
||||
-- SpawnAirplanes:SpawnInZone( SpawnZone )
|
||||
--
|
||||
-- -- Spawn in the zone at a random position at the height specified in the Me of the group template.
|
||||
-- SpawnAirplanes:SpawnInZone( SpawnZone, true )
|
||||
--
|
||||
-- -- Spawn in the zone at a random position at the height randomized between 2000 and 4000 meters.
|
||||
-- SpawnAirplanes:SpawnInZone( SpawnZone, true, 2000, 4000 )
|
||||
--
|
||||
-- -- Spawn at the zone center position at the height randomized between 2000 and 4000 meters.
|
||||
-- SpawnAirplanes:SpawnInZone( SpawnZone, false, 2000, 4000 )
|
||||
--
|
||||
-- -- Spawn at the zone center position at the height randomized between 2000 and 4000 meters.
|
||||
-- SpawnAirplanes:SpawnInZone( SpawnZone, nil, 2000, 4000 )
|
||||
--
|
||||
function SPAWN:SpawnInZone( Zone, RandomizeGroup, MinHeight, MaxHeight, SpawnIndex )
|
||||
self:F( { self.SpawnTemplatePrefix, Zone, RandomizeGroup, MinHeight, MaxHeight, SpawnIndex } )
|
||||
|
||||
if Zone then
|
||||
if RandomizeGroup then
|
||||
return self:SpawnFromVec2( Zone:GetRandomVec2(), SpawnIndex )
|
||||
return self:SpawnFromVec2( Zone:GetRandomVec2(), MinHeight, MaxHeight, SpawnIndex )
|
||||
else
|
||||
return self:SpawnFromVec2( Zone:GetVec2(), SpawnIndex )
|
||||
return self:SpawnFromVec2( Zone:GetVec2(), MinHeight, MaxHeight, SpawnIndex )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -116,6 +116,33 @@ function SPAWNSTATIC:NewFromType( SpawnTypeName, SpawnShapeName, SpawnCategory,
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates a new @{Static} at the original position.
|
||||
-- @param #SPAWNSTATIC self
|
||||
-- @param #number Heading The heading of the static, which is a number in degrees from 0 to 360.
|
||||
-- @param #string (optional) The name of the new static.
|
||||
-- @return #SPAWNSTATIC
|
||||
function SPAWNSTATIC:Spawn( Heading, NewName ) --R2.3
|
||||
self:F( { Heading, NewName } )
|
||||
|
||||
local CountryName = _DATABASE.COUNTRY_NAME[self.CountryID]
|
||||
|
||||
local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix )
|
||||
|
||||
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
|
||||
StaticTemplate.heading = ( Heading / 180 ) * math.pi
|
||||
|
||||
StaticTemplate.CountryID = nil
|
||||
StaticTemplate.CoalitionID = nil
|
||||
StaticTemplate.CategoryID = nil
|
||||
|
||||
local Static = coalition.addStaticObject( self.CountryID, StaticTemplate )
|
||||
|
||||
self.SpawnIndex = self.SpawnIndex + 1
|
||||
|
||||
return Static
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Creates a new @{Static} from a POINT_VEC2.
|
||||
-- @param #SPAWNSTATIC self
|
||||
@@ -130,8 +157,13 @@ function SPAWNSTATIC:SpawnFromPointVec2( PointVec2, Heading, NewName ) --R2.1
|
||||
|
||||
local StaticTemplate = _DATABASE:GetStaticUnitTemplate( self.SpawnTemplatePrefix )
|
||||
|
||||
StaticTemplate.x = PointVec2:GetLat()
|
||||
StaticTemplate.y = PointVec2:GetLon()
|
||||
StaticTemplate.x = PointVec2.x
|
||||
StaticTemplate.y = PointVec2.z
|
||||
|
||||
StaticTemplate.units = nil
|
||||
StaticTemplate.route = nil
|
||||
StaticTemplate.groupId = nil
|
||||
|
||||
|
||||
StaticTemplate.name = NewName or string.format("%s#%05d", self.SpawnTemplatePrefix, self.SpawnIndex )
|
||||
StaticTemplate.heading = ( Heading / 180 ) * math.pi
|
||||
|
||||
@@ -222,7 +222,7 @@ do
|
||||
|
||||
self:HandleEvent( EVENTS.Dead )
|
||||
|
||||
self:__Lasing( -0.2 )
|
||||
self:__Lasing( -1 )
|
||||
end
|
||||
|
||||
--- @param #SPOT self
|
||||
|
||||
95
Moose Development/Moose/Core/UserFlag.lua
Normal file
95
Moose Development/Moose/Core/UserFlag.lua
Normal file
@@ -0,0 +1,95 @@
|
||||
--- **Core (WIP)** -- Manage user flags.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- Management of DCS User Flags.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module UserFlag
|
||||
|
||||
do -- UserFlag
|
||||
|
||||
--- @type USERFLAG
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
--- # USERFLAG class, extends @{Base#BASE}
|
||||
--
|
||||
-- Management of DCS User Flags.
|
||||
--
|
||||
-- ## 1. USERFLAG constructor
|
||||
--
|
||||
-- * @{#USERFLAG.New}(): Creates a new USERFLAG object.
|
||||
--
|
||||
-- @field #USERFLAG
|
||||
USERFLAG = {
|
||||
ClassName = "USERFLAG",
|
||||
}
|
||||
|
||||
--- USERFLAG Constructor.
|
||||
-- @param #USERFLAG self
|
||||
-- @param #string UserFlagName The name of the userflag, which is a free text string.
|
||||
-- @return #USERFLAG
|
||||
function USERFLAG:New( UserFlagName ) --R2.3
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #USERFLAG
|
||||
|
||||
self.UserFlagName = UserFlagName
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set the userflag to a given Number.
|
||||
-- @param #USERFLAG self
|
||||
-- @param #number Number The number value to be checked if it is the same as the userflag.
|
||||
-- @return #USERFLAG The userflag instance.
|
||||
-- @usage
|
||||
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
|
||||
-- BlueVictory:Set( 100 ) -- Set the UserFlag VictoryBlue to 100.
|
||||
--
|
||||
function USERFLAG:Set( Number ) --R2.3
|
||||
|
||||
self:F( { Number = Number } )
|
||||
|
||||
trigger.action.setUserFlag( self.UserFlagName, Number )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Get the userflag Number.
|
||||
-- @param #USERFLAG self
|
||||
-- @return #number Number The number value to be checked if it is the same as the userflag.
|
||||
-- @usage
|
||||
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
|
||||
-- local BlueVictoryValue = BlueVictory:Get() -- Get the UserFlag VictoryBlue value.
|
||||
--
|
||||
function USERFLAG:Get( Number ) --R2.3
|
||||
|
||||
return trigger.misc.getUserFlag( self.UserFlagName )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Check if the userflag has a value of Number.
|
||||
-- @param #USERFLAG self
|
||||
-- @param #number Number The number value to be checked if it is the same as the userflag.
|
||||
-- @return #boolean true if the Number is the value of the userflag.
|
||||
-- @usage
|
||||
-- local BlueVictory = USERFLAG:New( "VictoryBlue" )
|
||||
-- if BlueVictory:Is( 1 ) then
|
||||
-- return "Blue has won"
|
||||
-- end
|
||||
function USERFLAG:Is( Number ) --R2.3
|
||||
|
||||
return trigger.misc.getUserFlag( self.UserFlagName ) == Number
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
129
Moose Development/Moose/Core/UserSound.lua
Normal file
129
Moose Development/Moose/Core/UserSound.lua
Normal file
@@ -0,0 +1,129 @@
|
||||
--- **Core (WIP)** -- Manage user sound.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- Management of DCS User Sound.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module UserSound
|
||||
|
||||
do -- UserSound
|
||||
|
||||
--- @type USERSOUND
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
--- # USERSOUND class, extends @{Base#BASE}
|
||||
--
|
||||
-- Management of DCS User Sound.
|
||||
--
|
||||
-- ## 1. USERSOUND constructor
|
||||
--
|
||||
-- * @{#USERSOUND.New}(): Creates a new USERSOUND object.
|
||||
--
|
||||
-- @field #USERSOUND
|
||||
USERSOUND = {
|
||||
ClassName = "USERSOUND",
|
||||
}
|
||||
|
||||
--- USERSOUND Constructor.
|
||||
-- @param #USERSOUND self
|
||||
-- @param #string UserSoundFileName The filename of the usersound.
|
||||
-- @return #USERSOUND
|
||||
function USERSOUND:New( UserSoundFileName ) --R2.3
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #USERSOUND
|
||||
|
||||
self.UserSoundFileName = UserSoundFileName
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set usersound filename.
|
||||
-- @param #USERSOUND self
|
||||
-- @param #string UserSoundFileName The filename of the usersound.
|
||||
-- @return #USERSOUND The usersound instance.
|
||||
-- @usage
|
||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||
-- BlueVictory:SetFileName( "BlueVictoryLoud.ogg" ) -- Set the BlueVictory to change the file name to play a louder sound.
|
||||
--
|
||||
function USERSOUND:SetFileName( UserSoundFileName ) --R2.3
|
||||
|
||||
self.UserSoundFileName = UserSoundFileName
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Play the usersound to all players.
|
||||
-- @param #USERSOUND self
|
||||
-- @return #USERSOUND The usersound instance.
|
||||
-- @usage
|
||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||
-- BlueVictory:ToAll() -- Play the sound that Blue has won.
|
||||
--
|
||||
function USERSOUND:ToAll() --R2.3
|
||||
|
||||
trigger.action.outSound( self.UserSoundFileName )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Play the usersound to the given coalition.
|
||||
-- @param #USERSOUND self
|
||||
-- @param Dcs.DCScoalition#coalition Coalition The coalition to play the usersound to.
|
||||
-- @return #USERSOUND The usersound instance.
|
||||
-- @usage
|
||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||
-- BlueVictory:ToCoalition( coalition.side.BLUE ) -- Play the sound that Blue has won to the blue coalition.
|
||||
--
|
||||
function USERSOUND:ToCoalition( Coalition ) --R2.3
|
||||
|
||||
trigger.action.outSoundForCoalition(Coalition, self.UserSoundFileName )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Play the usersound to the given country.
|
||||
-- @param #USERSOUND self
|
||||
-- @param Dcs.DCScountry#country Country The country to play the usersound to.
|
||||
-- @return #USERSOUND The usersound instance.
|
||||
-- @usage
|
||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||
-- BlueVictory:ToCountry( country.id.USA ) -- Play the sound that Blue has won to the USA country.
|
||||
--
|
||||
function USERSOUND:ToCountry( Country ) --R2.3
|
||||
|
||||
trigger.action.outSoundForCountry( Country, self.UserSoundFileName )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Play the usersound to the given @{Group}.
|
||||
-- @param #USERSOUND self
|
||||
-- @param Wrapper.Group#GROUP Group The @{Group} to play the usersound to.
|
||||
-- @return #USERSOUND The usersound instance.
|
||||
-- @usage
|
||||
-- local BlueVictory = USERSOUND:New( "BlueVictory.ogg" )
|
||||
-- local PlayerGroup = GROUP:FindByName( "PlayerGroup" ) -- Search for the active group named "PlayerGroup", that contains a human player.
|
||||
-- BlueVictory:ToGroup( PlayerGroup ) -- Play the sound that Blue has won to the player group.
|
||||
--
|
||||
function USERSOUND:ToGroup( Group ) --R2.3
|
||||
|
||||
trigger.action.outSoundForGroup( Group:GetID(), self.UserSoundFileName )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
184
Moose Development/Moose/Core/Velocity.lua
Normal file
184
Moose Development/Moose/Core/Velocity.lua
Normal file
@@ -0,0 +1,184 @@
|
||||
--- **Core** -- VELOCITY models a speed, which can be expressed in various formats according the Settings.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module Velocity
|
||||
|
||||
do -- Velocity
|
||||
|
||||
--- @type VELOCITY
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
--- # VELOCITY class, extends @{Base#BASE}
|
||||
--
|
||||
-- VELOCITY models a speed, which can be expressed in various formats according the Settings.
|
||||
--
|
||||
-- ## 1. VELOCITY constructor
|
||||
--
|
||||
-- * @{#VELOCITY.New}(): Creates a new VELOCITY object.
|
||||
--
|
||||
-- @field #VELOCITY
|
||||
VELOCITY = {
|
||||
ClassName = "VELOCITY",
|
||||
}
|
||||
|
||||
--- VELOCITY Constructor.
|
||||
-- @param #VELOCITY self
|
||||
-- @param #number VelocityMps The velocity in meters per second.
|
||||
-- @return #VELOCITY
|
||||
function VELOCITY:New( VelocityMps )
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #VELOCITY
|
||||
self:F( {} )
|
||||
self.Velocity = VelocityMps
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the velocity in Mps (meters per second).
|
||||
-- @param #VELOCITY self
|
||||
-- @param #number VelocityMps The velocity in meters per second.
|
||||
-- @return #VELOCITY
|
||||
function VELOCITY:Set( VelocityMps )
|
||||
self.Velocity = VelocityMps
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the velocity in Mps (meters per second).
|
||||
-- @param #VELOCITY self
|
||||
-- @return #number The velocity in meters per second.
|
||||
function VELOCITY:Get()
|
||||
return self.Velocity
|
||||
end
|
||||
|
||||
--- Set the velocity in Kmph (kilometers per hour).
|
||||
-- @param #VELOCITY self
|
||||
-- @param #number VelocityKmph The velocity in kilometers per hour.
|
||||
-- @return #VELOCITY
|
||||
function VELOCITY:SetKmph( VelocityKmph )
|
||||
self.Velocity = UTILS.KmphToMps( VelocityKmph )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the velocity in Kmph (kilometers per hour).
|
||||
-- @param #VELOCITY self
|
||||
-- @return #number The velocity in kilometers per hour.
|
||||
function VELOCITY:GetKmph()
|
||||
|
||||
return UTILS.MpsToKmph( self.Velocity )
|
||||
end
|
||||
|
||||
--- Set the velocity in Miph (miles per hour).
|
||||
-- @param #VELOCITY self
|
||||
-- @param #number VelocityMiph The velocity in miles per hour.
|
||||
-- @return #VELOCITY
|
||||
function VELOCITY:SetMiph( VelocityMiph )
|
||||
self.Velocity = UTILS.MiphToMps( VelocityMiph )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the velocity in Miph (miles per hour).
|
||||
-- @param #VELOCITY self
|
||||
-- @return #number The velocity in miles per hour.
|
||||
function VELOCITY:GetMiph()
|
||||
return UTILS.MpsToMiph( self.Velocity )
|
||||
end
|
||||
|
||||
|
||||
--- Get the velocity in text, according the player @{Settings}.
|
||||
-- @param #VELOCITY self
|
||||
-- @param Core.Settings#SETTINGS Settings
|
||||
-- @return #string The velocity in text.
|
||||
function VELOCITY:GetText( Settings )
|
||||
local Settings = Settings or _SETTINGS
|
||||
if self.Velocity ~= 0 then
|
||||
if Settings:IsMetric() then
|
||||
return string.format( "%d km/h", UTILS.MpsToKmph( self.Velocity ) )
|
||||
else
|
||||
return string.format( "%d mi/h", UTILS.MpsToMiph( self.Velocity ) )
|
||||
end
|
||||
else
|
||||
return "stationary"
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the velocity in text, according the player or default @{Settings}.
|
||||
-- @param #VELOCITY self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
-- @param Core.Settings#SETTINGS Settings
|
||||
-- @return #string The velocity in text according the player or default @{Settings}
|
||||
function VELOCITY:ToString( VelocityGroup, Settings ) -- R2.3
|
||||
self:F( { Group = VelocityGroup and VelocityGroup:GetName() } )
|
||||
local Settings = Settings or ( VelocityGroup and _DATABASE:GetPlayerSettings( VelocityGroup:GetPlayerName() ) ) or _SETTINGS
|
||||
return self:GetText( Settings )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do -- VELOCITY_POSITIONABLE
|
||||
|
||||
--- @type VELOCITY_POSITIONABLE
|
||||
-- @extends Core.Base#BASE
|
||||
|
||||
|
||||
--- # VELOCITY_POSITIONABLE class, extends @{Base#BASE}
|
||||
--
|
||||
-- VELOCITY_POSITIONABLE monitors the speed of an @{Positionable} in the simulation, which can be expressed in various formats according the Settings.
|
||||
--
|
||||
-- ## 1. VELOCITY_POSITIONABLE constructor
|
||||
--
|
||||
-- * @{#VELOCITY_POSITIONABLE.New}(): Creates a new VELOCITY_POSITIONABLE object.
|
||||
--
|
||||
-- @field #VELOCITY_POSITIONABLE
|
||||
VELOCITY_POSITIONABLE = {
|
||||
ClassName = "VELOCITY_POSITIONABLE",
|
||||
}
|
||||
|
||||
--- VELOCITY_POSITIONABLE Constructor.
|
||||
-- @param #VELOCITY_POSITIONABLE self
|
||||
-- @param Wrapper.Positionable#POSITIONABLE Positionable The Positionable to monitor the speed.
|
||||
-- @return #VELOCITY_POSITIONABLE
|
||||
function VELOCITY_POSITIONABLE:New( Positionable )
|
||||
local self = BASE:Inherit( self, VELOCITY:New() ) -- #VELOCITY_POSITIONABLE
|
||||
self:F( {} )
|
||||
self.Positionable = Positionable
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the velocity in Mps (meters per second).
|
||||
-- @param #VELOCITY_POSITIONABLE self
|
||||
-- @return #number The velocity in meters per second.
|
||||
function VELOCITY_POSITIONABLE:Get()
|
||||
return self.Positionable:GetVelocityMPS() or 0
|
||||
end
|
||||
|
||||
--- Get the velocity in Kmph (kilometers per hour).
|
||||
-- @param #VELOCITY_POSITIONABLE self
|
||||
-- @return #number The velocity in kilometers per hour.
|
||||
function VELOCITY_POSITIONABLE:GetKmph()
|
||||
|
||||
return UTILS.MpsToKmph( self.Positionable:GetVelocityMPS() or 0)
|
||||
end
|
||||
|
||||
--- Get the velocity in Miph (miles per hour).
|
||||
-- @param #VELOCITY_POSITIONABLE self
|
||||
-- @return #number The velocity in miles per hour.
|
||||
function VELOCITY_POSITIONABLE:GetMiph()
|
||||
return UTILS.MpsToMiph( self.Positionable:GetVelocityMPS() or 0 )
|
||||
end
|
||||
|
||||
--- Get the velocity in text, according the player or default @{Settings}.
|
||||
-- @param #VELOCITY_POSITIONABLE self
|
||||
-- @return #string The velocity in text according the player or default @{Settings}
|
||||
function VELOCITY_POSITIONABLE:ToString() -- R2.3
|
||||
self:F( { Group = self.Positionable and self.Positionable:GetName() } )
|
||||
local Settings = Settings or ( self.Positionable and _DATABASE:GetPlayerSettings( self.Positionable:GetPlayerName() ) ) or _SETTINGS
|
||||
self.Velocity = self.Positionable:GetVelocityMPS()
|
||||
return self:GetText( Settings )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -50,6 +50,8 @@
|
||||
-- ## Each zone has a name:
|
||||
--
|
||||
-- * @{#ZONE_BASE.GetName}(): Returns the name of the zone.
|
||||
-- * @{#ZONE_BASE.SetName}(): Sets the name of the zone.
|
||||
--
|
||||
--
|
||||
-- ## Each zone implements two polymorphic functions defined in @{Zone#ZONE_BASE}:
|
||||
--
|
||||
@@ -121,6 +123,17 @@ function ZONE_BASE:GetName()
|
||||
return self.ZoneName
|
||||
end
|
||||
|
||||
|
||||
--- Sets the name of the zone.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
-- @return #ZONE_BASE
|
||||
function ZONE_BASE:SetName( ZoneName )
|
||||
self:F2()
|
||||
|
||||
self.ZoneName = ZoneName
|
||||
end
|
||||
|
||||
--- Returns if a Vec2 is within the zone.
|
||||
-- @param #ZONE_BASE self
|
||||
-- @param Dcs.DCSTypes#Vec2 Vec2 The Vec2 to test.
|
||||
@@ -445,12 +458,17 @@ end
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The smoke color.
|
||||
-- @param #number Points (optional) The amount of points in the circle.
|
||||
-- @param #number AddHeight (optional) The height to be added for the smoke.
|
||||
-- @param #number AddOffSet (optional) The angle to be added for the smoking start position.
|
||||
-- @return #ZONE_RADIUS self
|
||||
function ZONE_RADIUS:SmokeZone( SmokeColor, Points )
|
||||
function ZONE_RADIUS:SmokeZone( SmokeColor, Points, AddHeight, AngleOffset )
|
||||
self:F2( SmokeColor )
|
||||
|
||||
local Point = {}
|
||||
local Vec2 = self:GetVec2()
|
||||
|
||||
AddHeight = AddHeight or 0
|
||||
AngleOffset = AngleOffset or 0
|
||||
|
||||
Points = Points and Points or 360
|
||||
|
||||
@@ -458,10 +476,10 @@ function ZONE_RADIUS:SmokeZone( SmokeColor, Points )
|
||||
local RadialBase = math.pi*2
|
||||
|
||||
for Angle = 0, 360, 360 / Points do
|
||||
local Radial = Angle * RadialBase / 360
|
||||
local Radial = ( Angle + AngleOffset ) * RadialBase / 360
|
||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||
POINT_VEC2:New( Point.x, Point.y ):Smoke( SmokeColor )
|
||||
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Smoke( SmokeColor )
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -473,13 +491,16 @@ end
|
||||
-- @param Utilities.Utils#FLARECOLOR FlareColor The flare color.
|
||||
-- @param #number Points (optional) The amount of points in the circle.
|
||||
-- @param Dcs.DCSTypes#Azimuth Azimuth (optional) Azimuth The azimuth of the flare.
|
||||
-- @param #number AddHeight (optional) The height to be added for the smoke.
|
||||
-- @return #ZONE_RADIUS self
|
||||
function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth )
|
||||
function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth, AddHeight )
|
||||
self:F2( { FlareColor, Azimuth } )
|
||||
|
||||
local Point = {}
|
||||
local Vec2 = self:GetVec2()
|
||||
|
||||
AddHeight = AddHeight or 0
|
||||
|
||||
Points = Points and Points or 360
|
||||
|
||||
local Angle
|
||||
@@ -489,7 +510,7 @@ function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth )
|
||||
local Radial = Angle * RadialBase / 360
|
||||
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
|
||||
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
|
||||
POINT_VEC2:New( Point.x, Point.y ):Flare( FlareColor, Azimuth )
|
||||
POINT_VEC2:New( Point.x, Point.y, AddHeight ):Flare( FlareColor, Azimuth )
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -562,6 +583,189 @@ function ZONE_RADIUS:GetVec3( Height )
|
||||
end
|
||||
|
||||
|
||||
--- Scan the zone
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param ObjectCategories
|
||||
-- @param Coalition
|
||||
function ZONE_RADIUS:Scan( ObjectCategories )
|
||||
|
||||
self.ScanData = {}
|
||||
self.ScanData.Coalitions = {}
|
||||
self.ScanData.Scenery = {}
|
||||
|
||||
local ZoneCoord = self:GetCoordinate()
|
||||
local ZoneRadius = self:GetRadius()
|
||||
|
||||
self:E({ZoneCoord = ZoneCoord, ZoneRadius = ZoneRadius, ZoneCoordLL = ZoneCoord:ToStringLLDMS()})
|
||||
|
||||
local SphereSearch = {
|
||||
id = world.VolumeType.SPHERE,
|
||||
params = {
|
||||
point = ZoneCoord:GetVec3(),
|
||||
radius = ZoneRadius,
|
||||
}
|
||||
}
|
||||
|
||||
local function EvaluateZone( ZoneObject )
|
||||
if ZoneObject:isExist() then
|
||||
local ObjectCategory = ZoneObject:getCategory()
|
||||
if ( ObjectCategory == Object.Category.UNIT and ZoneObject:isActive() ) or
|
||||
ObjectCategory == Object.Category.STATIC then
|
||||
local CoalitionDCSUnit = ZoneObject:getCoalition()
|
||||
self.ScanData.Coalitions[CoalitionDCSUnit] = true
|
||||
self:E( { Name = ZoneObject:getName(), Coalition = CoalitionDCSUnit } )
|
||||
end
|
||||
if ObjectCategory == Object.Category.SCENERY then
|
||||
local SceneryType = ZoneObject:getTypeName()
|
||||
local SceneryName = ZoneObject:getName()
|
||||
self.ScanData.Scenery[SceneryType] = self.ScanData.Scenery[SceneryType] or {}
|
||||
self.ScanData.Scenery[SceneryType][SceneryName] = SCENERY:Register( SceneryName, ZoneObject )
|
||||
self:E( { SCENERY = self.ScanData.Scenery[SceneryType][SceneryName] } )
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
world.searchObjects( ObjectCategories, SphereSearch, EvaluateZone )
|
||||
|
||||
end
|
||||
|
||||
|
||||
function ZONE_RADIUS:CountScannedCoalitions()
|
||||
|
||||
local Count = 0
|
||||
|
||||
for CoalitionID, Coalition in pairs( self.ScanData.Coalitions ) do
|
||||
Count = Count + 1
|
||||
end
|
||||
return Count
|
||||
end
|
||||
|
||||
|
||||
--- Get Coalitions of the units in the Zone, or Check if there are units of the given Coalition in the Zone.
|
||||
-- Returns nil if there are none ot two Coalitions in the zone!
|
||||
-- Returns one Coalition if there are only Units of one Coalition in the Zone.
|
||||
-- Returns the Coalition for the given Coalition if there are units of the Coalition in the Zone
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @return #table
|
||||
function ZONE_RADIUS:GetScannedCoalition( Coalition )
|
||||
|
||||
if Coalition then
|
||||
return self.ScanData.Coalitions[Coalition]
|
||||
else
|
||||
local Count = 0
|
||||
local ReturnCoalition = nil
|
||||
|
||||
for CoalitionID, Coalition in pairs( self.ScanData.Coalitions ) do
|
||||
Count = Count + 1
|
||||
ReturnCoalition = CoalitionID
|
||||
end
|
||||
|
||||
if Count ~= 1 then
|
||||
ReturnCoalition = nil
|
||||
end
|
||||
|
||||
return ReturnCoalition
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ZONE_RADIUS:GetScannedSceneryType( SceneryType )
|
||||
return self.ScanData.Scenery[SceneryType]
|
||||
end
|
||||
|
||||
|
||||
function ZONE_RADIUS:GetScannedScenery()
|
||||
return self.ScanData.Scenery
|
||||
end
|
||||
|
||||
|
||||
--- Is All in Zone of Coalition?
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param Coalition
|
||||
-- @return #boolean
|
||||
function ZONE_RADIUS:IsAllInZoneOfCoalition( Coalition )
|
||||
|
||||
return self:CountScannedCoalitions() == 1 and self:GetScannedCoalition( Coalition ) == true
|
||||
end
|
||||
|
||||
|
||||
--- Is All in Zone of Other Coalition?
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param Coalition
|
||||
-- @return #boolean
|
||||
function ZONE_RADIUS:IsAllInZoneOfOtherCoalition( Coalition )
|
||||
|
||||
self:E( { Coalitions = self.Coalitions, Count = self:CountScannedCoalitions() } )
|
||||
return self:CountScannedCoalitions() == 1 and self:GetScannedCoalition( Coalition ) == nil
|
||||
end
|
||||
|
||||
|
||||
--- Is Some in Zone of Coalition?
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param Coalition
|
||||
-- @return #boolean
|
||||
function ZONE_RADIUS:IsSomeInZoneOfCoalition( Coalition )
|
||||
|
||||
return self:CountScannedCoalitions() > 1 and self:GetScannedCoalition( Coalition ) == true
|
||||
end
|
||||
|
||||
|
||||
--- Is None in Zone of Coalition?
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param Coalition
|
||||
-- @return #boolean
|
||||
function ZONE_RADIUS:IsNoneInZoneOfCoalition( Coalition )
|
||||
|
||||
return self:GetScannedCoalition( Coalition ) == nil
|
||||
end
|
||||
|
||||
|
||||
--- Is None in Zone?
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @return #boolean
|
||||
function ZONE_RADIUS:IsNoneInZone()
|
||||
|
||||
return self:CountScannedCoalitions() == 0
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Searches the zone
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param ObjectCategories A list of categories, which are members of Object.Category
|
||||
-- @param EvaluateFunction
|
||||
function ZONE_RADIUS:SearchZone( EvaluateFunction, ObjectCategories )
|
||||
|
||||
local SearchZoneResult = true
|
||||
|
||||
local ZoneCoord = self:GetCoordinate()
|
||||
local ZoneRadius = self:GetRadius()
|
||||
|
||||
self:E({ZoneCoord = ZoneCoord, ZoneRadius = ZoneRadius, ZoneCoordLL = ZoneCoord:ToStringLLDMS()})
|
||||
|
||||
local SphereSearch = {
|
||||
id = world.VolumeType.SPHERE,
|
||||
params = {
|
||||
point = ZoneCoord:GetVec3(),
|
||||
radius = ZoneRadius / 2,
|
||||
}
|
||||
}
|
||||
|
||||
local function EvaluateZone( ZoneDCSUnit )
|
||||
|
||||
env.info( ZoneDCSUnit:getName() )
|
||||
|
||||
local ZoneUnit = UNIT:Find( ZoneDCSUnit )
|
||||
|
||||
return EvaluateFunction( ZoneUnit )
|
||||
end
|
||||
|
||||
world.searchObjects( Object.Category.UNIT, SphereSearch, EvaluateZone )
|
||||
|
||||
end
|
||||
|
||||
--- Returns if a location is within the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param Dcs.DCSTypes#Vec2 Vec2 The location to test.
|
||||
@@ -645,6 +849,22 @@ function ZONE_RADIUS:GetRandomPointVec3( inner, outer )
|
||||
end
|
||||
|
||||
|
||||
--- Returns a @{Point#COORDINATE} object reflecting a random 3D location within the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||
-- @return Core.Point#COORDINATE
|
||||
function ZONE_RADIUS:GetRandomCoordinate( inner, outer )
|
||||
self:F( self.ZoneName, inner, outer )
|
||||
|
||||
local Coordinate = COORDINATE:NewFromVec2( self:GetRandomVec2() )
|
||||
|
||||
self:T3( { Coordinate = Coordinate } )
|
||||
|
||||
return Coordinate
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @type ZONE
|
||||
-- @extends #ZONE_RADIUS
|
||||
@@ -834,6 +1054,20 @@ function ZONE_GROUP:GetRandomVec2()
|
||||
return Point
|
||||
end
|
||||
|
||||
--- Returns a @{Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
||||
-- @param #ZONE_GROUP self
|
||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||
-- @return Core.Point#POINT_VEC2 The @{Point#POINT_VEC2} object reflecting the random 3D location within the zone.
|
||||
function ZONE_GROUP:GetRandomPointVec2( inner, outer )
|
||||
self:F( self.ZoneName, inner, outer )
|
||||
|
||||
local PointVec2 = POINT_VEC2:NewFromVec2( self:GetRandomVec2() )
|
||||
|
||||
self:T3( { PointVec2 } )
|
||||
|
||||
return PointVec2
|
||||
end
|
||||
|
||||
|
||||
--- @type ZONE_POLYGON_BASE
|
||||
@@ -1077,6 +1311,20 @@ function ZONE_POLYGON_BASE:GetRandomPointVec3()
|
||||
end
|
||||
|
||||
|
||||
--- Return a @{Point#COORDINATE} object representing a random 3D point at landheight within the zone.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @return Core.Point#COORDINATE
|
||||
function ZONE_POLYGON_BASE:GetRandomCoordinate()
|
||||
self:F2()
|
||||
|
||||
local Coordinate = COORDINATE:NewFromVec2( self:GetRandomVec2() )
|
||||
|
||||
self:T2( Coordinate )
|
||||
|
||||
return Coordinate
|
||||
end
|
||||
|
||||
|
||||
--- Get the bounding square the zone.
|
||||
-- @param #ZONE_POLYGON_BASE self
|
||||
-- @return #ZONE_POLYGON_BASE.BoundingSquare The bounding square.
|
||||
@@ -1114,7 +1362,7 @@ ZONE_POLYGON = {
|
||||
ClassName="ZONE_POLYGON",
|
||||
}
|
||||
|
||||
--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the name of the @{Group#GROUP} defined within the Mission Editor.
|
||||
--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the @{Group#GROUP} defined within the Mission Editor.
|
||||
-- The @{Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON.
|
||||
-- @param #ZONE_POLYGON self
|
||||
-- @param #string ZoneName Name of the zone.
|
||||
@@ -1130,3 +1378,22 @@ function ZONE_POLYGON:New( ZoneName, ZoneGroup )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Constructor to create a ZONE_POLYGON instance, taking the zone name and the **name** of the @{Group#GROUP} defined within the Mission Editor.
|
||||
-- The @{Group#GROUP} waypoints define the polygon corners. The first and the last point are automatically connected by ZONE_POLYGON.
|
||||
-- @param #ZONE_POLYGON self
|
||||
-- @param #string ZoneName Name of the zone.
|
||||
-- @param #string GroupName The group name of the GROUP defining the waypoints within the Mission Editor to define the polygon shape.
|
||||
-- @return #ZONE_POLYGON self
|
||||
function ZONE_POLYGON:NewFromGroupName( ZoneName, GroupName )
|
||||
|
||||
local ZoneGroup = GROUP:FindByName( GroupName )
|
||||
|
||||
local GroupPoints = ZoneGroup:GetTaskRoute()
|
||||
|
||||
local self = BASE:Inherit( self, ZONE_POLYGON_BASE:New( ZoneName, GroupPoints ) )
|
||||
self:F( { ZoneName, ZoneGroup, self._.Polygon } )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
2311
Moose Development/Moose/Functional/ATC_Ground.lua
Normal file
2311
Moose Development/Moose/Functional/ATC_Ground.lua
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,136 +1,234 @@
|
||||
--- **Functional** -- The CLEANUP class keeps an area clean of crashing or colliding airplanes. It also prevents airplanes from firing within this area.
|
||||
--- **Functional** -- The CLEANUP_AIRBASE class keeps an area clean of crashing or colliding airplanes. It also prevents airplanes from firing within this area.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
-- ### Contributions:
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module CleanUp
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--- The CLEANUP class.
|
||||
-- @type CLEANUP
|
||||
--- @type CLEANUP_AIRBASE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-)
|
||||
-- @field #map<#string,Wrapper.Airbase#AIRBASE> Airbases Map of Airbases.
|
||||
-- @extends Core.Base#BASE
|
||||
CLEANUP = {
|
||||
ClassName = "CLEANUP",
|
||||
ZoneNames = {},
|
||||
TimeInterval = 300,
|
||||
|
||||
--- @type CLEANUP_AIRBASE
|
||||
-- @extends #CLEANUP_AIRBASE.__
|
||||
|
||||
--- # CLEANUP_AIRBASE, extends @{Base#BASE}
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- The CLEANUP_AIRBASE class keeps airbases clean, and tries to guarantee continuous airbase operations, even under combat.
|
||||
-- Specific airbases need to be provided that need to be guarded. Each airbase registered, will be guarded within a zone of 8 km around the airbase.
|
||||
-- Any unit that fires a missile, or shoots within the zone of an airbase, will be monitored by CLEANUP_AIRBASE.
|
||||
-- Within the 8km zone, units cannot fire any missile, which prevents the airbase runway to receive missile or bomb hits.
|
||||
-- Any airborne or ground unit that is on the runway below 30 meters (default value) will be automatically removed if it is damaged.
|
||||
--
|
||||
-- This is not a full 100% secure implementation. It is still possible that CLEANUP_AIRBASE cannot prevent (in-time) to keep the airbase clean.
|
||||
-- The following situations may happen that will still stop the runway of an airbase:
|
||||
--
|
||||
-- * A damaged unit is not removed on time when above the runway, and crashes on the runway.
|
||||
-- * A bomb or missile is still able to dropped on the runway.
|
||||
-- * Units collide on the airbase, and could not be removed on time.
|
||||
--
|
||||
-- When a unit is within the airbase zone and needs to be monitored,
|
||||
-- its status will be checked every 0.25 seconds! This is required to ensure that the airbase is kept clean.
|
||||
-- But as a result, there is more CPU overload.
|
||||
--
|
||||
-- So as an advise, I suggest you use the CLEANUP_AIRBASE class with care:
|
||||
--
|
||||
-- * Only monitor airbases that really need to be monitored!
|
||||
-- * Try not to monitor airbases that are likely to be invaded by enemy troops.
|
||||
-- For these airbases, there is little use to keep them clean, as they will be invaded anyway...
|
||||
--
|
||||
-- By following the above guidelines, you can add airbase cleanup with acceptable CPU overhead.
|
||||
--
|
||||
-- ## 1. CLEANUP_AIRBASE Constructor
|
||||
--
|
||||
-- Creates the main object which is preventing the airbase to get polluted with debris on the runway, which halts the airbase.
|
||||
--
|
||||
-- -- Clean these Zones.
|
||||
-- CleanUpAirports = CLEANUP_AIRBASE:New( { AIRBASE.Caucasus.Tbilisi, AIRBASE.Caucasus.Kutaisi )
|
||||
--
|
||||
-- -- or
|
||||
-- CleanUpTbilisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Tbilisi )
|
||||
-- CleanUpKutaisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Kutaisi )
|
||||
--
|
||||
-- ## 2. Add or Remove airbases
|
||||
--
|
||||
-- The method @{#CLEANUP_AIRBASE.AddAirbase}() to add an airbase to the cleanup validation process.
|
||||
-- The method @{#CLEANUP_AIRBASE.RemoveAirbase}() removes an airbase from the cleanup validation process.
|
||||
--
|
||||
-- ## 3. Clean missiles and bombs within the airbase zone.
|
||||
--
|
||||
-- When missiles or bombs hit the runway, the airbase operations stop.
|
||||
-- Use the method @{#CLEANUP_AIRBASE.SetCleanMissiles}() to control the cleaning of missiles, which will prevent airbases to stop.
|
||||
-- Note that this method will not allow anymore airbases to be attacked, so there is a trade-off here to do.
|
||||
--
|
||||
-- @field #CLEANUP_AIRBASE
|
||||
CLEANUP_AIRBASE = {
|
||||
ClassName = "CLEANUP_AIRBASE",
|
||||
TimeInterval = 0.2,
|
||||
CleanUpList = {},
|
||||
}
|
||||
|
||||
-- @field #CLEANUP_AIRBASE.__
|
||||
CLEANUP_AIRBASE.__ = {}
|
||||
|
||||
--- @field #CLEANUP_AIRBASE.__.Airbases
|
||||
CLEANUP_AIRBASE.__.Airbases = {}
|
||||
|
||||
--- Creates the main object which is handling the cleaning of the debris within the given Zone Names.
|
||||
-- @param #CLEANUP self
|
||||
-- @param #table ZoneNames Is a table of zone names where the debris should be cleaned. Also a single string can be passed with one zone name.
|
||||
-- @param #number TimeInterval The interval in seconds when the clean activity takes place. The default is 300 seconds, thus every 5 minutes.
|
||||
-- @return #CLEANUP
|
||||
-- @param #CLEANUP_AIRBASE self
|
||||
-- @param #list<#string> AirbaseNames Is a table of airbase names where the debris should be cleaned. Also a single string can be passed with one airbase name.
|
||||
-- @return #CLEANUP_AIRBASE
|
||||
-- @usage
|
||||
-- -- Clean these Zones.
|
||||
-- CleanUpAirports = CLEANUP:New( { 'CLEAN Tbilisi', 'CLEAN Kutaisi' }, 150 )
|
||||
-- CleanUpAirports = CLEANUP_AIRBASE:New( { AIRBASE.Caucasus.Tbilisi, AIRBASE.Caucasus.Kutaisi )
|
||||
-- or
|
||||
-- CleanUpTbilisi = CLEANUP:New( 'CLEAN Tbilisi', 150 )
|
||||
-- CleanUpKutaisi = CLEANUP:New( 'CLEAN Kutaisi', 600 )
|
||||
function CLEANUP:New( ZoneNames, TimeInterval )
|
||||
-- CleanUpTbilisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Tbilisi )
|
||||
-- CleanUpKutaisi = CLEANUP_AIRBASE:New( AIRBASE.Caucasus.Kutaisi )
|
||||
function CLEANUP_AIRBASE:New( AirbaseNames )
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #CLEANUP
|
||||
self:F( { ZoneNames, TimeInterval } )
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #CLEANUP_AIRBASE
|
||||
self:F( { AirbaseNames } )
|
||||
|
||||
if type( ZoneNames ) == 'table' then
|
||||
self.ZoneNames = ZoneNames
|
||||
if type( AirbaseNames ) == 'table' then
|
||||
for AirbaseID, AirbaseName in pairs( AirbaseNames ) do
|
||||
self:AddAirbase( AirbaseName )
|
||||
end
|
||||
else
|
||||
self.ZoneNames = { ZoneNames }
|
||||
end
|
||||
if TimeInterval then
|
||||
self.TimeInterval = TimeInterval
|
||||
local AirbaseName = AirbaseNames
|
||||
self:AddAirbase( AirbaseName )
|
||||
end
|
||||
|
||||
self:HandleEvent( EVENTS.Birth )
|
||||
self:HandleEvent( EVENTS.Birth, self.__.OnEventBirth )
|
||||
|
||||
self.CleanUpScheduler = SCHEDULER:New( self, self._CleanUpScheduler, {}, 1, TimeInterval )
|
||||
self.__.CleanUpScheduler = SCHEDULER:New( self, self.__.CleanUpSchedule, {}, 1, self.TimeInterval )
|
||||
|
||||
self:HandleEvent( EVENTS.EngineShutdown , self.__.EventAddForCleanUp )
|
||||
self:HandleEvent( EVENTS.EngineStartup, self.__.EventAddForCleanUp )
|
||||
self:HandleEvent( EVENTS.Hit, self.__.EventAddForCleanUp )
|
||||
self:HandleEvent( EVENTS.PilotDead, self.__.OnEventCrash )
|
||||
self:HandleEvent( EVENTS.Dead, self.__.OnEventCrash )
|
||||
self:HandleEvent( EVENTS.Crash, self.__.OnEventCrash )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Destroys a group from the simulator, but checks first if it is still existing!
|
||||
-- @param #CLEANUP self
|
||||
-- @param Dcs.DCSWrapper.Group#Group GroupObject The object to be destroyed.
|
||||
-- @param #string CleanUpGroupName The groupname...
|
||||
function CLEANUP:_DestroyGroup( GroupObject, CleanUpGroupName )
|
||||
self:F( { GroupObject, CleanUpGroupName } )
|
||||
|
||||
if GroupObject then -- and GroupObject:isExist() then
|
||||
trigger.action.deactivateGroup(GroupObject)
|
||||
self:T( { "GroupObject Destroyed", GroupObject } )
|
||||
end
|
||||
--- Adds an airbase to the airbase validation list.
|
||||
-- @param #CLEANUP_AIRBASE self
|
||||
-- @param #string AirbaseName
|
||||
-- @return #CLEANUP_AIRBASE
|
||||
function CLEANUP_AIRBASE:AddAirbase( AirbaseName )
|
||||
self.__.Airbases[AirbaseName] = AIRBASE:FindByName( AirbaseName )
|
||||
self:F({"Airbase:", AirbaseName, self.__.Airbases[AirbaseName]:GetDesc()})
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Destroys a @{DCSWrapper.Unit#Unit} from the simulator, but checks first if it is still existing!
|
||||
-- @param #CLEANUP self
|
||||
-- @param Dcs.DCSWrapper.Unit#Unit CleanUpUnit The object to be destroyed.
|
||||
-- @param #string CleanUpUnitName The Unit name ...
|
||||
function CLEANUP:_DestroyUnit( CleanUpUnit, CleanUpUnitName )
|
||||
self:F( { CleanUpUnit, CleanUpUnitName } )
|
||||
--- Removes an airbase from the airbase validation list.
|
||||
-- @param #CLEANUP_AIRBASE self
|
||||
-- @param #string AirbaseName
|
||||
-- @return #CLEANUP_AIRBASE
|
||||
function CLEANUP_AIRBASE:RemoveAirbase( AirbaseName )
|
||||
self.__.Airbases[AirbaseName] = nil
|
||||
return self
|
||||
end
|
||||
|
||||
--- Enables or disables the cleaning of missiles within the airbase zones.
|
||||
-- Airbase operations stop when a missile or bomb is dropped at a runway.
|
||||
-- Note that when this method is used, the airbase operations won't stop if
|
||||
-- the missile or bomb was cleaned within the airbase zone, which is 8km from the center of the airbase.
|
||||
-- However, there is a trade-off to make. Attacks on airbases won't be possible anymore if this method is used.
|
||||
-- Note, one can also use the method @{#CLEANUP_AIRBASE.RemoveAirbase}() to remove the airbase from the control process as a whole,
|
||||
-- when an enemy unit is near. That is also an option...
|
||||
-- @param #CLEANUP_AIRBASE self
|
||||
-- @param #string CleanMissiles (Default=true) If true, missiles fired are immediately destroyed. If false missiles are not controlled.
|
||||
-- @return #CLEANUP_AIRBASE
|
||||
function CLEANUP_AIRBASE:SetCleanMissiles( CleanMissiles )
|
||||
|
||||
if CleanMissiles then
|
||||
self:HandleEvent( EVENTS.Shot, self.__.OnEventShot )
|
||||
else
|
||||
self:UnHandleEvent( EVENTS.Shot )
|
||||
end
|
||||
end
|
||||
|
||||
function CLEANUP_AIRBASE.__:IsInAirbase( Vec2 )
|
||||
|
||||
local InAirbase = false
|
||||
for AirbaseName, Airbase in pairs( self.__.Airbases ) do
|
||||
local Airbase = Airbase -- Wrapper.Airbase#AIRBASE
|
||||
if Airbase:GetZone():IsVec2InZone( Vec2 ) then
|
||||
InAirbase = true
|
||||
break;
|
||||
end
|
||||
end
|
||||
|
||||
return InAirbase
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Destroys a @{Unit} from the simulator, but checks first if it is still existing!
|
||||
-- @param #CLEANUP_AIRBASE self
|
||||
-- @param Wrapper.Unit#UNIT CleanUpUnit The object to be destroyed.
|
||||
function CLEANUP_AIRBASE.__:DestroyUnit( CleanUpUnit )
|
||||
self:F( { CleanUpUnit } )
|
||||
|
||||
if CleanUpUnit then
|
||||
local CleanUpGroup = Unit.getGroup(CleanUpUnit)
|
||||
local CleanUpUnitName = CleanUpUnit:GetName()
|
||||
local CleanUpGroup = CleanUpUnit:GetGroup()
|
||||
-- TODO Client bug in 1.5.3
|
||||
if CleanUpGroup and CleanUpGroup:isExist() then
|
||||
local CleanUpGroupUnits = CleanUpGroup:getUnits()
|
||||
if CleanUpGroup:IsAlive() then
|
||||
local CleanUpGroupUnits = CleanUpGroup:GetUnits()
|
||||
if #CleanUpGroupUnits == 1 then
|
||||
local CleanUpGroupName = CleanUpGroup:getName()
|
||||
--self:CreateEventCrash( timer.getTime(), CleanUpUnit )
|
||||
CleanUpGroup:destroy()
|
||||
self:T( { "Destroyed Group:", CleanUpGroupName } )
|
||||
local CleanUpGroupName = CleanUpGroup:GetName()
|
||||
CleanUpGroup:Destroy()
|
||||
else
|
||||
CleanUpUnit:destroy()
|
||||
self:T( { "Destroyed Unit:", CleanUpUnitName } )
|
||||
CleanUpUnit:Destroy()
|
||||
end
|
||||
self.CleanUpList[CleanUpUnitName] = nil -- Cleaning from the list
|
||||
CleanUpUnit = nil
|
||||
self.CleanUpList[CleanUpUnitName] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO check Dcs.DCSTypes#Weapon
|
||||
--- Destroys a missile from the simulator, but checks first if it is still existing!
|
||||
-- @param #CLEANUP self
|
||||
-- @param Dcs.DCSTypes#Weapon MissileObject
|
||||
function CLEANUP:_DestroyMissile( MissileObject )
|
||||
self:F( { MissileObject } )
|
||||
|
||||
|
||||
--- Destroys a missile from the simulator, but checks first if it is still existing!
|
||||
-- @param #CLEANUP_AIRBASE self
|
||||
-- @param Dcs.DCSTypes#Weapon MissileObject
|
||||
function CLEANUP_AIRBASE.__:DestroyMissile( MissileObject )
|
||||
self:F( { MissileObject } )
|
||||
|
||||
if MissileObject and MissileObject:isExist() then
|
||||
MissileObject:destroy()
|
||||
self:T( "MissileObject Destroyed")
|
||||
end
|
||||
end
|
||||
|
||||
--- @param #CLEANUP self
|
||||
--- @param #CLEANUP_AIRBASE self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function CLEANUP:_OnEventBirth( EventData )
|
||||
function CLEANUP_AIRBASE.__:OnEventBirth( EventData )
|
||||
self:F( { EventData } )
|
||||
|
||||
self.CleanUpList[EventData.IniDCSUnitName] = {}
|
||||
self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnit = EventData.IniDCSUnit
|
||||
self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroup = EventData.IniDCSGroup
|
||||
self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnit = EventData.IniUnit
|
||||
self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroup = EventData.IniGroup
|
||||
self.CleanUpList[EventData.IniDCSUnitName].CleanUpGroupName = EventData.IniDCSGroupName
|
||||
self.CleanUpList[EventData.IniDCSUnitName].CleanUpUnitName = EventData.IniDCSUnitName
|
||||
|
||||
EventData.IniUnit:HandleEvent( EVENTS.EngineShutdown , self._EventAddForCleanUp )
|
||||
EventData.IniUnit:HandleEvent( EVENTS.EngineStartup, self._EventAddForCleanUp )
|
||||
EventData.IniUnit:HandleEvent( EVENTS.Hit, self._EventAddForCleanUp )
|
||||
EventData.IniUnit:HandleEvent( EVENTS.PilotDead, self._EventCrash )
|
||||
EventData.IniUnit:HandleEvent( EVENTS.Dead, self._EventCrash )
|
||||
EventData.IniUnit:HandleEvent( EVENTS.Crash, self._EventCrash )
|
||||
EventData.IniUnit:HandleEvent( EVENTS.Shot, self._EventShot )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Detects if a crash event occurs.
|
||||
-- Crashed units go into a CleanUpList for removal.
|
||||
-- @param #CLEANUP self
|
||||
-- @param Dcs.DCSTypes#Event event
|
||||
function CLEANUP:_EventCrash( Event )
|
||||
-- @param #CLEANUP_AIRBASE self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
function CLEANUP_AIRBASE.__:OnEventCrash( Event )
|
||||
self:F( { Event } )
|
||||
|
||||
--TODO: This stuff is not working due to a DCS bug. Burning units cannot be destroyed.
|
||||
@@ -141,171 +239,164 @@ function CLEANUP:_EventCrash( Event )
|
||||
-- self:T("after deactivateGroup")
|
||||
-- event.initiator:destroy()
|
||||
|
||||
self.CleanUpList[Event.IniDCSUnitName] = {}
|
||||
self.CleanUpList[Event.IniDCSUnitName].CleanUpUnit = Event.IniDCSUnit
|
||||
self.CleanUpList[Event.IniDCSUnitName].CleanUpGroup = Event.IniDCSGroup
|
||||
self.CleanUpList[Event.IniDCSUnitName].CleanUpGroupName = Event.IniDCSGroupName
|
||||
self.CleanUpList[Event.IniDCSUnitName].CleanUpUnitName = Event.IniDCSUnitName
|
||||
if Event.IniDCSUnitName and Event.IniCategory == Object.Category.UNIT then
|
||||
self.CleanUpList[Event.IniDCSUnitName] = {}
|
||||
self.CleanUpList[Event.IniDCSUnitName].CleanUpUnit = Event.IniUnit
|
||||
self.CleanUpList[Event.IniDCSUnitName].CleanUpGroup = Event.IniGroup
|
||||
self.CleanUpList[Event.IniDCSUnitName].CleanUpGroupName = Event.IniDCSGroupName
|
||||
self.CleanUpList[Event.IniDCSUnitName].CleanUpUnitName = Event.IniDCSUnitName
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Detects if a unit shoots a missile.
|
||||
-- If this occurs within one of the zones, then the weapon used must be destroyed.
|
||||
-- @param #CLEANUP self
|
||||
-- @param Dcs.DCSTypes#Event event
|
||||
function CLEANUP:_EventShot( Event )
|
||||
-- If this occurs within one of the airbases, then the weapon used must be destroyed.
|
||||
-- @param #CLEANUP_AIRBASE self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
function CLEANUP_AIRBASE.__:OnEventShot( Event )
|
||||
self:F( { Event } )
|
||||
|
||||
-- Test if the missile was fired within one of the CLEANUP.ZoneNames.
|
||||
local CurrentLandingZoneID = 0
|
||||
CurrentLandingZoneID = routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames )
|
||||
if ( CurrentLandingZoneID ) then
|
||||
-- Okay, the missile was fired within the CLEANUP.ZoneNames, destroy the fired weapon.
|
||||
--_SEADmissile:destroy()
|
||||
SCHEDULER:New( self, CLEANUP._DestroyMissile, { Event.Weapon }, 0.1 )
|
||||
-- Test if the missile was fired within one of the CLEANUP_AIRBASE.AirbaseNames.
|
||||
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
|
||||
-- Okay, the missile was fired within the CLEANUP_AIRBASE.AirbaseNames, destroy the fired weapon.
|
||||
self:DestroyMissile( Event.Weapon )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Detects if the Unit has an S_EVENT_HIT within the given ZoneNames. If this is the case, destroy the unit.
|
||||
-- @param #CLEANUP self
|
||||
-- @param Dcs.DCSTypes#Event event
|
||||
function CLEANUP:_EventHitCleanUp( Event )
|
||||
--- Detects if the Unit has an S_EVENT_HIT within the given AirbaseNames. If this is the case, destroy the unit.
|
||||
-- @param #CLEANUP_AIRBASE self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
function CLEANUP_AIRBASE.__:OnEventHit( Event )
|
||||
self:F( { Event } )
|
||||
|
||||
if Event.IniDCSUnit then
|
||||
if routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) ~= nil then
|
||||
self:T( { "Life: ", Event.IniDCSUnitName, ' = ', Event.IniDCSUnit:getLife(), "/", Event.IniDCSUnit:getLife0() } )
|
||||
if Event.IniDCSUnit:getLife() < Event.IniDCSUnit:getLife0() then
|
||||
if Event.IniUnit then
|
||||
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
|
||||
self:T( { "Life: ", Event.IniDCSUnitName, ' = ', Event.IniUnit:GetLife(), "/", Event.IniUnit:GetLife0() } )
|
||||
if Event.IniUnit:GetLife() < Event.IniUnit:GetLife0() then
|
||||
self:T( "CleanUp: Destroy: " .. Event.IniDCSUnitName )
|
||||
SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.IniDCSUnit }, 0.1 )
|
||||
CLEANUP_AIRBASE.__:DestroyUnit( Event.IniUnit )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Event.TgtDCSUnit then
|
||||
if routines.IsUnitInZones( Event.TgtDCSUnit, self.ZoneNames ) ~= nil then
|
||||
self:T( { "Life: ", Event.TgtDCSUnitName, ' = ', Event.TgtDCSUnit:getLife(), "/", Event.TgtDCSUnit:getLife0() } )
|
||||
if Event.TgtDCSUnit:getLife() < Event.TgtDCSUnit:getLife0() then
|
||||
if Event.TgtUnit then
|
||||
if self:IsInAirbase( Event.TgtUnit:GetVec2() ) then
|
||||
self:T( { "Life: ", Event.TgtDCSUnitName, ' = ', Event.TgtUnit:GetLife(), "/", Event.TgtUnit:GetLife0() } )
|
||||
if Event.TgtUnit:GetLife() < Event.TgtUnit:GetLife0() then
|
||||
self:T( "CleanUp: Destroy: " .. Event.TgtDCSUnitName )
|
||||
SCHEDULER:New( self, CLEANUP._DestroyUnit, { Event.TgtDCSUnit }, 0.1 )
|
||||
CLEANUP_AIRBASE.__:DestroyUnit( Event.TgtUnit )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Add the @{DCSWrapper.Unit#Unit} to the CleanUpList for CleanUp.
|
||||
function CLEANUP:_AddForCleanUp( CleanUpUnit, CleanUpUnitName )
|
||||
-- @param #CLEANUP_AIRBASE self
|
||||
-- @param Wrapper.Unit#UNIT CleanUpUnit
|
||||
-- @oaram #string CleanUpUnitName
|
||||
function CLEANUP_AIRBASE.__:AddForCleanUp( CleanUpUnit, CleanUpUnitName )
|
||||
self:F( { CleanUpUnit, CleanUpUnitName } )
|
||||
|
||||
self.CleanUpList[CleanUpUnitName] = {}
|
||||
self.CleanUpList[CleanUpUnitName].CleanUpUnit = CleanUpUnit
|
||||
self.CleanUpList[CleanUpUnitName].CleanUpUnitName = CleanUpUnitName
|
||||
self.CleanUpList[CleanUpUnitName].CleanUpGroup = Unit.getGroup(CleanUpUnit)
|
||||
self.CleanUpList[CleanUpUnitName].CleanUpGroupName = Unit.getGroup(CleanUpUnit):getName()
|
||||
|
||||
local CleanUpGroup = CleanUpUnit:GetGroup()
|
||||
|
||||
self.CleanUpList[CleanUpUnitName].CleanUpGroup = CleanUpGroup
|
||||
self.CleanUpList[CleanUpUnitName].CleanUpGroupName = CleanUpGroup:GetName()
|
||||
self.CleanUpList[CleanUpUnitName].CleanUpTime = timer.getTime()
|
||||
self.CleanUpList[CleanUpUnitName].CleanUpMoved = false
|
||||
|
||||
self:T( { "CleanUp: Add to CleanUpList: ", Unit.getGroup(CleanUpUnit):getName(), CleanUpUnitName } )
|
||||
self:T( { "CleanUp: Add to CleanUpList: ", CleanUpGroup:GetName(), CleanUpUnitName } )
|
||||
|
||||
end
|
||||
|
||||
--- Detects if the Unit has an S_EVENT_ENGINE_SHUTDOWN or an S_EVENT_HIT within the given ZoneNames. If this is the case, add the Group to the CLEANUP List.
|
||||
-- @param #CLEANUP self
|
||||
-- @param Dcs.DCSTypes#Event event
|
||||
function CLEANUP:_EventAddForCleanUp( Event )
|
||||
--- Detects if the Unit has an S_EVENT_ENGINE_SHUTDOWN or an S_EVENT_HIT within the given AirbaseNames. If this is the case, add the Group to the CLEANUP_AIRBASE List.
|
||||
-- @param #CLEANUP_AIRBASE.__ self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
function CLEANUP_AIRBASE.__:EventAddForCleanUp( Event )
|
||||
|
||||
if Event.IniDCSUnit then
|
||||
self:F({Event})
|
||||
|
||||
|
||||
if Event.IniDCSUnit and Event.IniCategory == Object.Category.UNIT then
|
||||
if self.CleanUpList[Event.IniDCSUnitName] == nil then
|
||||
if routines.IsUnitInZones( Event.IniDCSUnit, self.ZoneNames ) ~= nil then
|
||||
self:_AddForCleanUp( Event.IniDCSUnit, Event.IniDCSUnitName )
|
||||
if self:IsInAirbase( Event.IniUnit:GetVec2() ) then
|
||||
self:AddForCleanUp( Event.IniUnit, Event.IniDCSUnitName )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Event.TgtDCSUnit then
|
||||
if Event.TgtDCSUnit and Event.TgtCategory == Object.Category.UNIT then
|
||||
if self.CleanUpList[Event.TgtDCSUnitName] == nil then
|
||||
if routines.IsUnitInZones( Event.TgtDCSUnit, self.ZoneNames ) ~= nil then
|
||||
self:_AddForCleanUp( Event.TgtDCSUnit, Event.TgtDCSUnitName )
|
||||
if self:IsInAirbase( Event.TgtUnit:GetVec2() ) then
|
||||
self:AddForCleanUp( Event.TgtUnit, Event.TgtDCSUnitName )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local CleanUpSurfaceTypeText = {
|
||||
"LAND",
|
||||
"SHALLOW_WATER",
|
||||
"WATER",
|
||||
"ROAD",
|
||||
"RUNWAY"
|
||||
}
|
||||
|
||||
--- At the defined time interval, CleanUp the Groups within the CleanUpList.
|
||||
-- @param #CLEANUP self
|
||||
function CLEANUP:_CleanUpScheduler()
|
||||
self:F( { "CleanUp Scheduler" } )
|
||||
-- @param #CLEANUP_AIRBASE self
|
||||
function CLEANUP_AIRBASE.__:CleanUpSchedule()
|
||||
|
||||
local CleanUpCount = 0
|
||||
for CleanUpUnitName, UnitData in pairs( self.CleanUpList ) do
|
||||
for CleanUpUnitName, CleanUpListData in pairs( self.CleanUpList ) do
|
||||
CleanUpCount = CleanUpCount + 1
|
||||
|
||||
self:T( { CleanUpUnitName, UnitData } )
|
||||
local CleanUpUnit = Unit.getByName(UnitData.CleanUpUnitName)
|
||||
local CleanUpGroupName = UnitData.CleanUpGroupName
|
||||
local CleanUpUnitName = UnitData.CleanUpUnitName
|
||||
if CleanUpUnit then
|
||||
self:T( { "CleanUp Scheduler", "Checking:", CleanUpUnitName } )
|
||||
local CleanUpUnit = CleanUpListData.CleanUpUnit -- Wrapper.Unit#UNIT
|
||||
local CleanUpGroupName = CleanUpListData.CleanUpGroupName
|
||||
|
||||
if CleanUpUnit:IsAlive() ~= nil then
|
||||
|
||||
if _DATABASE:GetStatusGroup( CleanUpGroupName ) ~= "ReSpawn" then
|
||||
local CleanUpUnitVec3 = CleanUpUnit:getPoint()
|
||||
--self:T( CleanUpUnitVec3 )
|
||||
local CleanUpUnitVec2 = {}
|
||||
CleanUpUnitVec2.x = CleanUpUnitVec3.x
|
||||
CleanUpUnitVec2.y = CleanUpUnitVec3.z
|
||||
--self:T( CleanUpUnitVec2 )
|
||||
local CleanUpSurfaceType = land.getSurfaceType(CleanUpUnitVec2)
|
||||
--self:T( CleanUpSurfaceType )
|
||||
|
||||
if CleanUpUnit and CleanUpUnit:getLife() <= CleanUpUnit:getLife0() * 0.95 then
|
||||
if CleanUpSurfaceType == land.SurfaceType.RUNWAY then
|
||||
if CleanUpUnit:inAir() then
|
||||
local CleanUpLandHeight = land.getHeight(CleanUpUnitVec2)
|
||||
local CleanUpUnitHeight = CleanUpUnitVec3.y - CleanUpLandHeight
|
||||
self:T( { "CleanUp Scheduler", "Height = " .. CleanUpUnitHeight } )
|
||||
if CleanUpUnitHeight < 30 then
|
||||
|
||||
local CleanUpCoordinate = CleanUpUnit:GetCoordinate()
|
||||
|
||||
self:T( { "CleanUp Scheduler", CleanUpUnitName } )
|
||||
if CleanUpUnit:GetLife() <= CleanUpUnit:GetLife0() * 0.95 then
|
||||
if CleanUpUnit:IsAboveRunway() then
|
||||
if CleanUpUnit:InAir() then
|
||||
|
||||
local CleanUpLandHeight = CleanUpCoordinate:GetLandHeight()
|
||||
local CleanUpUnitHeight = CleanUpCoordinate.y - CleanUpLandHeight
|
||||
|
||||
if CleanUpUnitHeight < 100 then
|
||||
self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because below safe height and damaged." } )
|
||||
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
|
||||
self:DestroyUnit( CleanUpUnit )
|
||||
end
|
||||
else
|
||||
self:T( { "CleanUp Scheduler", "Destroy " .. CleanUpUnitName .. " because on runway and damaged." } )
|
||||
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
|
||||
self:DestroyUnit( CleanUpUnit )
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Clean Units which are waiting for a very long time in the CleanUpZone.
|
||||
if CleanUpUnit then
|
||||
local CleanUpUnitVelocity = CleanUpUnit:getVelocity()
|
||||
local CleanUpUnitVelocityTotal = math.abs(CleanUpUnitVelocity.x) + math.abs(CleanUpUnitVelocity.y) + math.abs(CleanUpUnitVelocity.z)
|
||||
if CleanUpUnitVelocityTotal < 1 then
|
||||
if UnitData.CleanUpMoved then
|
||||
if UnitData.CleanUpTime + 180 <= timer.getTime() then
|
||||
local CleanUpUnitVelocity = CleanUpUnit:GetVelocityKMH()
|
||||
if CleanUpUnitVelocity < 1 then
|
||||
if CleanUpListData.CleanUpMoved then
|
||||
if CleanUpListData.CleanUpTime + 180 <= timer.getTime() then
|
||||
self:T( { "CleanUp Scheduler", "Destroy due to not moving anymore " .. CleanUpUnitName } )
|
||||
self:_DestroyUnit(CleanUpUnit, CleanUpUnitName)
|
||||
self:DestroyUnit( CleanUpUnit )
|
||||
end
|
||||
end
|
||||
else
|
||||
UnitData.CleanUpTime = timer.getTime()
|
||||
UnitData.CleanUpMoved = true
|
||||
CleanUpListData.CleanUpTime = timer.getTime()
|
||||
CleanUpListData.CleanUpMoved = true
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
-- Do nothing ...
|
||||
self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE
|
||||
self.CleanUpList[CleanUpUnitName] = nil
|
||||
end
|
||||
else
|
||||
self:T( "CleanUp: Group " .. CleanUpUnitName .. " cannot be found in DCS RTE, removing ..." )
|
||||
self.CleanUpList[CleanUpUnitName] = nil -- Not anymore in the DCSRTE
|
||||
self.CleanUpList[CleanUpUnitName] = nil
|
||||
end
|
||||
end
|
||||
self:T(CleanUpCount)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- **Functional** -- Management of target **Designation**.
|
||||
--- **Functional** -- Management of target **Designation**. Lase, smoke and illuminate targets.
|
||||
--
|
||||
-- --
|
||||
--
|
||||
@@ -70,10 +70,14 @@ do -- DESIGNATE
|
||||
-- The RecceSet is continuously detecting for potential Targets, executing its task as part of the DetectionObject.
|
||||
-- Once Targets have been detected, the DesignateObject will trigger the **Detect Event**.
|
||||
--
|
||||
-- In order to prevent an overflow in the DesignateObject of detected targets, there is a maximum
|
||||
-- amount of DetectionItems that can be put in **scope** of the DesignateObject.
|
||||
-- We call this the **MaximumDesignations** term.
|
||||
--
|
||||
-- As part of the Detect Event, the DetectionItems list is used by the DesignateObject to provide the Players with:
|
||||
--
|
||||
-- * The RecceGroups are reporting to each AttackGroup, sending **Messages** containing the Threat Level and the TargetSet composition.
|
||||
-- * **Menu options** are created and updated for each AttackGroup, containing the Threat Level and the TargetSet composition.
|
||||
-- * **Menu options** are created and updated for each AttackGroup, containing the Detection ID and the Coordinates.
|
||||
--
|
||||
-- A Player can then select an action from the Designate Menu.
|
||||
--
|
||||
@@ -109,7 +113,7 @@ do -- DESIGNATE
|
||||
--
|
||||
-- ### 2.1 DESIGNATE States
|
||||
--
|
||||
-- * **Designating** ( Group ): The process is not started yet.
|
||||
-- * **Designating** ( Group ): The designation process.
|
||||
--
|
||||
-- ### 2.2 DESIGNATE Events
|
||||
--
|
||||
@@ -119,9 +123,17 @@ do -- DESIGNATE
|
||||
-- * **@{#DESIGNATE.Smoke}**: Smoke the targets with the specified Index.
|
||||
-- * **@{#DESIGNATE.Status}**: Report designation status.
|
||||
--
|
||||
-- ## 3. Laser codes
|
||||
-- ## 3. Maximum Designations
|
||||
--
|
||||
-- ### 3.1 Set possible laser codes
|
||||
-- In order to prevent an overflow of designations due to many Detected Targets, there is a
|
||||
-- Maximum Designations scope that is set in the DesignationObject.
|
||||
--
|
||||
-- The method @{#DESIGNATE.SetMaximumDesignations}() will put a limit on the amount of designations put in scope of the DesignationObject.
|
||||
-- Using the menu system, the player can "forget" a designation, so that gradually a new designation can be put in scope when detected.
|
||||
--
|
||||
-- ## 4. Laser codes
|
||||
--
|
||||
-- ### 4.1. Set possible laser codes
|
||||
--
|
||||
-- An array of laser codes can be provided, that will be used by the DESIGNATE when lasing.
|
||||
-- The laser code is communicated by the Recce when it is lasing a larget.
|
||||
@@ -139,11 +151,20 @@ do -- DESIGNATE
|
||||
--
|
||||
-- The above sets a collection of possible laser codes that can be assigned. **Note the { } notation!**
|
||||
--
|
||||
-- ### 3.2 Auto generate laser codes
|
||||
-- ### 4.2. Auto generate laser codes
|
||||
--
|
||||
-- Use the method @{#DESIGNATE.GenerateLaserCodes}() to generate all possible laser codes. Logic implemented and advised by Ciribob!
|
||||
--
|
||||
-- ## 4. Autolase to automatically lase detected targets.
|
||||
-- ### 4.3. Add specific lase codes to the lase menu
|
||||
--
|
||||
-- Certain plane types can only drop laser guided ordonnance when targets are lased with specific laser codes.
|
||||
-- The SU-25T needs targets to be lased using laser code 1113.
|
||||
-- The A-10A needs targets to be lased using laser code 1680.
|
||||
--
|
||||
-- The method @{#DESIGNATE.AddMenuLaserCode}() to allow a player to lase a target using a specific laser code.
|
||||
-- Remove such a lase menu option using @{#DESIGNATE.RemoveMenuLaserCode}().
|
||||
--
|
||||
-- ## 5. Autolase to automatically lase detected targets.
|
||||
--
|
||||
-- DetectionItems can be auto lased once detected by Recces. As such, there is almost no action required from the Players using the Designate Menu.
|
||||
-- The **auto lase** function can be activated through the Designation Menu.
|
||||
@@ -154,7 +175,7 @@ do -- DESIGNATE
|
||||
--
|
||||
-- Activate the auto lasing.
|
||||
--
|
||||
-- ## 5. Target prioritization on threat level
|
||||
-- ## 6. Target prioritization on threat level
|
||||
--
|
||||
-- Targets can be detected of different types in one DetectionItem. Depending on the type of the Target, a different threat level applies in an Air to Ground combat context.
|
||||
-- SAMs are of a higher threat than normal tanks. So, if the Target type was recognized, the Recces will select those targets that form the biggest threat first,
|
||||
@@ -167,7 +188,12 @@ do -- DESIGNATE
|
||||
--
|
||||
-- The example will activate the threat level prioritization for this the Designate object. Threats will be marked based on the threat level of the Target.
|
||||
--
|
||||
-- ## 6. Status Report
|
||||
-- ## 6. Designate Menu Location for a Mission
|
||||
--
|
||||
-- You can make DESIGNATE work for a @{Mission#MISSION} object. In this way, the designate menu will not appear in the root of the radio menu, but in the menu of the Mission.
|
||||
-- Use the method @{#DESIGNATE.SetMission}() to set the @{Mission} object for the designate function.
|
||||
--
|
||||
-- ## 7. Status Report
|
||||
--
|
||||
-- A status report is available that displays the current Targets detected, grouped per DetectionItem, and a list of which Targets are currently being marked.
|
||||
--
|
||||
@@ -182,7 +208,6 @@ do -- DESIGNATE
|
||||
-- The example will activate the flashing of the status menu for this Designate object.
|
||||
--
|
||||
-- @field #DESIGNATE
|
||||
--
|
||||
DESIGNATE = {
|
||||
ClassName = "DESIGNATE",
|
||||
}
|
||||
@@ -192,8 +217,9 @@ do -- DESIGNATE
|
||||
-- @param Tasking.CommandCenter#COMMANDCENTER CC
|
||||
-- @param Functional.Detection#DETECTION_BASE Detection
|
||||
-- @param Core.Set#SET_GROUP AttackSet The Attack collection of GROUP objects to designate and report for.
|
||||
-- @param Tasking.Mission#MISSION Mission (Optional) The Mission where the menu needs to be attached.
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:New( CC, Detection, AttackSet )
|
||||
function DESIGNATE:New( CC, Detection, AttackSet, Mission )
|
||||
|
||||
local self = BASE:Inherit( self, FSM:New() ) -- #DESIGNATE
|
||||
self:F( { Detection } )
|
||||
@@ -360,22 +386,33 @@ do -- DESIGNATE
|
||||
self.RecceSet = Detection:GetDetectionSetGroup()
|
||||
self.Recces = {}
|
||||
self.Designating = {}
|
||||
self:SetDesignateName()
|
||||
|
||||
self.LaseDuration = 60
|
||||
|
||||
self:SetFlashStatusMenu( false )
|
||||
self:SetDesignateMenu()
|
||||
self:SetMission( Mission )
|
||||
|
||||
self:SetLaserCodes( 1688 ) -- set self.LaserCodes
|
||||
self:SetAutoLase( false ) -- set self.Autolase
|
||||
self:SetLaserCodes( { 1688, 1130, 4785, 6547, 1465, 4578 } ) -- set self.LaserCodes
|
||||
self:SetAutoLase( false, false ) -- set self.Autolase and don't send message.
|
||||
|
||||
self:SetThreatLevelPrioritization( false ) -- self.ThreatLevelPrioritization, default is threat level priorization off
|
||||
self:SetMaximumDesignations( 5 ) -- Sets the maximum designations. The default is 5 designations.
|
||||
self:SetMaximumDistanceDesignations( 12000 ) -- Sets the maximum distance on which designations can be accepted. The default is 8000 meters.
|
||||
self:SetMaximumMarkings( 2 ) -- Per target group, a maximum of 2 markings will be made by default.
|
||||
|
||||
self:SetDesignateMenu()
|
||||
|
||||
self.LaserCodesUsed = {}
|
||||
|
||||
|
||||
self.MenuLaserCodes = {} -- This map contains the laser codes that will be shown in the designate menu to lase with specific laser codes.
|
||||
|
||||
self.Detection:__Start( 2 )
|
||||
|
||||
self:__Detect( -15 )
|
||||
|
||||
self.MarkScheduler = SCHEDULER:New( self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -399,6 +436,56 @@ do -- DESIGNATE
|
||||
end
|
||||
|
||||
|
||||
--- Set the maximum amount of designations.
|
||||
-- @param #DESIGNATE self
|
||||
-- @param #number MaximumDesignations
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:SetMaximumDesignations( MaximumDesignations )
|
||||
self.MaximumDesignations = MaximumDesignations
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set the maximum ground designation distance.
|
||||
-- @param #DESIGNATE self
|
||||
-- @param #number MaximumDistanceGroundDesignation Maximum ground designation distance in meters.
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:SetMaximumDistanceGroundDesignation( MaximumDistanceGroundDesignation )
|
||||
self.MaximumDistanceGroundDesignation = MaximumDistanceGroundDesignation
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set the maximum air designation distance.
|
||||
-- @param #DESIGNATE self
|
||||
-- @param #number MaximumDistanceAirDesignation Maximum air designation distance in meters.
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:SetMaximumDistanceAirDesignation( MaximumDistanceAirDesignation )
|
||||
self.MaximumDistanceAirDesignation = MaximumDistanceAirDesignation
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set the overall maximum distance when designations can be accepted.
|
||||
-- @param #DESIGNATE self
|
||||
-- @param #number MaximumDistanceDesignations Maximum distance in meters to accept designations.
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:SetMaximumDistanceDesignations( MaximumDistanceDesignations )
|
||||
self.MaximumDistanceDesignations = MaximumDistanceDesignations
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set the maximum amount of markings FACs will do, per designated target group.
|
||||
-- @param #DESIGNATE self
|
||||
-- @param #number MaximumMarkings Maximum markings FACs will do, per designated target group.
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:SetMaximumMarkings( MaximumMarkings )
|
||||
self.MaximumMarkings = MaximumMarkings
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set an array of possible laser codes.
|
||||
-- Each new lase will select a code from this table.
|
||||
-- @param #DESIGNATE self
|
||||
@@ -407,13 +494,64 @@ do -- DESIGNATE
|
||||
function DESIGNATE:SetLaserCodes( LaserCodes ) --R2.1
|
||||
|
||||
self.LaserCodes = ( type( LaserCodes ) == "table" ) and LaserCodes or { LaserCodes }
|
||||
self:E(self.LaserCodes)
|
||||
self:E( { LaserCodes = self.LaserCodes } )
|
||||
|
||||
self.LaserCodesUsed = {}
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Add a specific lase code to the designate lase menu to lase targets with a specific laser code.
|
||||
-- The MenuText will appear in the lase menu.
|
||||
-- @param #DESIGNATE self
|
||||
-- @param #number LaserCode The specific laser code to be added to the lase menu.
|
||||
-- @param #string MenuText The text to be shown to the player. If you specify a %d in the MenuText, the %d will be replaced with the LaserCode specified.
|
||||
-- @return #DESIGNATE
|
||||
-- @usage
|
||||
-- RecceDesignation:AddMenuLaserCode( 1113, "Lase with %d for Su-25T" )
|
||||
-- RecceDesignation:AddMenuLaserCode( 1680, "Lase with %d for A-10A" )
|
||||
--
|
||||
function DESIGNATE:AddMenuLaserCode( LaserCode, MenuText )
|
||||
|
||||
self.MenuLaserCodes[LaserCode] = MenuText
|
||||
self:SetDesignateMenu()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Removes a specific lase code from the designate lase menu.
|
||||
-- @param #DESIGNATE self
|
||||
-- @param #number LaserCode The specific laser code that was set to be added to the lase menu.
|
||||
-- @return #DESIGNATE
|
||||
-- @usage
|
||||
-- RecceDesignation:RemoveMenuLaserCode( 1113 )
|
||||
--
|
||||
function DESIGNATE:RemoveMenuLaserCode( LaserCode )
|
||||
|
||||
self.MenuLaserCodes[LaserCode] = nil
|
||||
self:SetDesignateMenu()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Set the name of the designation. The name will appear in the menu.
|
||||
-- This method can be used to control different designations for different plane types.
|
||||
-- @param #DESIGNATE self
|
||||
-- @param #string DesignateName
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:SetDesignateName( DesignateName )
|
||||
|
||||
self.DesignateName = "Designation" .. ( DesignateName and ( " for " .. DesignateName ) or "" )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Generate an array of possible laser codes.
|
||||
-- Each new lase will select a code from this table.
|
||||
-- The entered value can range from 1111 - 1788,
|
||||
@@ -470,21 +608,22 @@ do -- DESIGNATE
|
||||
--- Set auto lase.
|
||||
-- Auto lase will start lasing targets immediately when these are in range.
|
||||
-- @param #DESIGNATE self
|
||||
-- @param #boolean AutoLase
|
||||
-- @param #boolean AutoLase (optional) true sets autolase on, false off. Default is off.
|
||||
-- @param #boolean Message (optional) true is send message, false or nil won't send a message. Default is no message sent.
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:SetAutoLase( AutoLase ) --R2.1
|
||||
function DESIGNATE:SetAutoLase( AutoLase, Message )
|
||||
|
||||
self.AutoLase = AutoLase
|
||||
self.AutoLase = AutoLase or false
|
||||
|
||||
local AutoLaseOnOff = ( AutoLase == true ) and "On" or "Off"
|
||||
|
||||
local CC = self.CC:GetPositionable()
|
||||
|
||||
if CC then
|
||||
CC:MessageToSetGroup( "Auto Lase " .. AutoLaseOnOff .. ".", 15, self.AttackSet )
|
||||
if Message then
|
||||
local AutoLaseOnOff = ( self.AutoLase == true ) and "On" or "Off"
|
||||
local CC = self.CC:GetPositionable()
|
||||
if CC then
|
||||
CC:MessageToSetGroup( self.DesignateName .. ": Auto Lase " .. AutoLaseOnOff .. ".", 15, self.AttackSet )
|
||||
end
|
||||
end
|
||||
|
||||
self:ActivateAutoLase()
|
||||
self:CoordinateLase()
|
||||
self:SetDesignateMenu()
|
||||
|
||||
return self
|
||||
@@ -501,6 +640,17 @@ do -- DESIGNATE
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set the MISSION object for which designate will function.
|
||||
-- When a MISSION object is assigned, the menu for the designation will be located at the Mission Menu.
|
||||
-- @param #DESIGNATE self
|
||||
-- @param Tasking.Mission#MISSION Mission The MISSION object.
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:SetMission( Mission ) --R2.2
|
||||
|
||||
self.Mission = Mission
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
@@ -508,15 +658,96 @@ do -- DESIGNATE
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:onafterDetect()
|
||||
|
||||
self:__Detect( -60 )
|
||||
self:__Detect( -math.random( 60 ) )
|
||||
|
||||
self:ActivateAutoLase()
|
||||
self:DesignationScope()
|
||||
self:CoordinateLase()
|
||||
self:SendStatus()
|
||||
self:SetDesignateMenu()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Adapt the designation scope according the detected items.
|
||||
-- @param #DESIGNATE self
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:DesignationScope()
|
||||
|
||||
local DetectedItems = self.Detection:GetDetectedItems()
|
||||
|
||||
local DetectedItemCount = 0
|
||||
|
||||
for DesignateIndex, Designating in pairs( self.Designating ) do
|
||||
local DetectedItem = DetectedItems[DesignateIndex]
|
||||
if DetectedItem then
|
||||
-- Check LOS...
|
||||
local IsDetected = self.Detection:IsDetectedItemDetected( DetectedItem )
|
||||
self:F({IsDetected = IsDetected, DetectedItem })
|
||||
if IsDetected == false then
|
||||
self:F("Removing")
|
||||
-- This Detection is obsolete, remove from the designate scope
|
||||
self.Designating[DesignateIndex] = nil
|
||||
self.AttackSet:ForEachGroup(
|
||||
function( AttackGroup )
|
||||
local DetectionText = self.Detection:DetectedItemReportSummary( DesignateIndex, AttackGroup ):Text( ", " )
|
||||
self.CC:GetPositionable():MessageToGroup( "Targets out of LOS\n" .. DetectionText, 10, AttackGroup, self.DesignateName )
|
||||
end
|
||||
)
|
||||
else
|
||||
DetectedItemCount = DetectedItemCount + 1
|
||||
end
|
||||
else
|
||||
-- This Detection is obsolete, remove from the designate scope
|
||||
self.Designating[DesignateIndex] = nil
|
||||
end
|
||||
end
|
||||
|
||||
if DetectedItemCount < 5 then
|
||||
for DesignateIndex, DetectedItem in pairs( DetectedItems ) do
|
||||
local IsDetected = self.Detection:IsDetectedItemDetected( DetectedItem )
|
||||
if IsDetected == true then
|
||||
self:F( { DistanceRecce = DetectedItem.DistanceRecce } )
|
||||
if DetectedItem.DistanceRecce <= self.MaximumDistanceDesignations then
|
||||
if self.Designating[DesignateIndex] == nil then
|
||||
-- ok, we added one item to the designate scope.
|
||||
self.AttackSet:ForEachGroup(
|
||||
function( AttackGroup )
|
||||
local DetectionText = self.Detection:DetectedItemReportSummary( DesignateIndex, AttackGroup ):Text( ", " )
|
||||
self.CC:GetPositionable():MessageToGroup( "Targets detected at \n" .. DetectionText, 10, AttackGroup, self.DesignateName )
|
||||
end
|
||||
)
|
||||
self.Designating[DesignateIndex] = ""
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Coordinates the Auto Lase.
|
||||
-- @param #DESIGNATE self
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:CoordinateLase()
|
||||
|
||||
local DetectedItems = self.Detection:GetDetectedItems()
|
||||
|
||||
for DesignateIndex, Designating in pairs( self.Designating ) do
|
||||
local DetectedItem = DetectedItems[DesignateIndex]
|
||||
if DetectedItem then
|
||||
if self.AutoLase then
|
||||
self:LaseOn( DesignateIndex, self.LaseDuration )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Sends the status to the Attack Groups.
|
||||
-- @param #DESIGNATE self
|
||||
-- @param Wrapper.Group#GROUP AttackGroup
|
||||
@@ -533,20 +764,23 @@ do -- DESIGNATE
|
||||
|
||||
if self.FlashStatusMenu[AttackGroup] or ( MenuAttackGroup and ( AttackGroup:GetName() == MenuAttackGroup:GetName() ) ) then
|
||||
|
||||
local DetectedReport = REPORT:New( "Targets designated:\n" )
|
||||
local DetectedReport = REPORT:New( "Targets ready for Designation:" )
|
||||
local DetectedItems = self.Detection:GetDetectedItems()
|
||||
|
||||
for Index, DetectedItemData in pairs( DetectedItems ) do
|
||||
|
||||
local Report = self.Detection:DetectedItemReportSummary( Index, AttackGroup )
|
||||
DetectedReport:Add(" - " .. Report)
|
||||
for DesignateIndex, Designating in pairs( self.Designating ) do
|
||||
local DetectedItem = DetectedItems[DesignateIndex]
|
||||
if DetectedItem then
|
||||
local Report = self.Detection:DetectedItemReportSummary( DesignateIndex, AttackGroup ):Text( ", " )
|
||||
DetectedReport:Add( string.rep( "-", 140 ) )
|
||||
DetectedReport:Add( " - " .. Report )
|
||||
end
|
||||
end
|
||||
|
||||
local CC = self.CC:GetPositionable()
|
||||
|
||||
CC:MessageToGroup( DetectedReport:Text( "\n" ), Duration, AttackGroup )
|
||||
CC:MessageToGroup( DetectedReport:Text( "\n" ), Duration, AttackGroup, self.DesignateName )
|
||||
|
||||
local DesignationReport = REPORT:New( "Targets marked:\n" )
|
||||
local DesignationReport = REPORT:New( "Marking Targets:\n" )
|
||||
|
||||
self.RecceSet:ForEachGroup(
|
||||
function( RecceGroup )
|
||||
@@ -560,34 +794,7 @@ do -- DESIGNATE
|
||||
end
|
||||
)
|
||||
|
||||
CC:MessageToGroup( DesignationReport:Text(), Duration, AttackGroup )
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Coordinates the Auto Lase.
|
||||
-- @param #DESIGNATE self
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:ActivateAutoLase()
|
||||
|
||||
self.AttackSet:Flush()
|
||||
|
||||
self.AttackSet:ForEachGroup(
|
||||
|
||||
--- @param Wrapper.Group#GROUP GroupReport
|
||||
function( AttackGroup )
|
||||
|
||||
local DetectedItems = self.Detection:GetDetectedItems()
|
||||
|
||||
for Index, DetectedItemData in pairs( DetectedItems ) do
|
||||
if self.AutoLase then
|
||||
if not self.Designating[Index] then
|
||||
self:LaseOn( Index, self.LaseDuration )
|
||||
end
|
||||
end
|
||||
CC:MessageToGroup( DesignationReport:Text(), Duration, AttackGroup, self.DesignateName )
|
||||
end
|
||||
end
|
||||
)
|
||||
@@ -606,66 +813,79 @@ do -- DESIGNATE
|
||||
|
||||
--- @param Wrapper.Group#GROUP GroupReport
|
||||
function( AttackGroup )
|
||||
local DesignateMenu = AttackGroup:GetState( AttackGroup, "DesignateMenu" ) -- Core.Menu#MENU_GROUP
|
||||
if DesignateMenu then
|
||||
DesignateMenu:Remove()
|
||||
DesignateMenu = nil
|
||||
self:E("Remove Menu")
|
||||
end
|
||||
DesignateMenu = MENU_GROUP:New( AttackGroup, "Designate" )
|
||||
self:E(DesignateMenu)
|
||||
AttackGroup:SetState( AttackGroup, "DesignateMenu", DesignateMenu )
|
||||
self.MenuDesignate = self.MenuDesignate or {}
|
||||
|
||||
local MissionMenu = nil
|
||||
|
||||
if self.Mission then
|
||||
MissionMenu = self.Mission:GetRootMenu( AttackGroup )
|
||||
end
|
||||
|
||||
local MenuTime = timer.getTime()
|
||||
|
||||
self.MenuDesignate[AttackGroup] = MENU_GROUP:New( AttackGroup, self.DesignateName, MissionMenu ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
local MenuDesignate = self.MenuDesignate[AttackGroup] -- Core.Menu#MENU_GROUP
|
||||
|
||||
-- Set Menu option for auto lase
|
||||
|
||||
if self.AutoLase then
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Auto Lase Off", DesignateMenu, self.MenuAutoLase, self, false )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Auto Lase Off", MenuDesignate, self.MenuAutoLase, self, false ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
else
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Auto Lase On", DesignateMenu, self.MenuAutoLase, self, true )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Auto Lase On", MenuDesignate, self.MenuAutoLase, self, true ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
end
|
||||
|
||||
local StatusMenu = MENU_GROUP:New( AttackGroup, "Status", DesignateMenu )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Report Status 15s", StatusMenu, self.MenuStatus, self, AttackGroup, 15 )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Report Status 30s", StatusMenu, self.MenuStatus, self, AttackGroup, 30 )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Report Status 60s", StatusMenu, self.MenuStatus, self, AttackGroup, 60 )
|
||||
local StatusMenu = MENU_GROUP:New( AttackGroup, "Status", MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Report Status 15s", StatusMenu, self.MenuStatus, self, AttackGroup, 15 ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Report Status 30s", StatusMenu, self.MenuStatus, self, AttackGroup, 30 ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Report Status 60s", StatusMenu, self.MenuStatus, self, AttackGroup, 60 ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
|
||||
if self.FlashStatusMenu[AttackGroup] then
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Flash Status Report Off", StatusMenu, self.MenuFlashStatus, self, AttackGroup, false )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Flash Status Report Off", StatusMenu, self.MenuFlashStatus, self, AttackGroup, false ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
else
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Flash Status Report On", StatusMenu, self.MenuFlashStatus, self, AttackGroup, true )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Flash Status Report On", StatusMenu, self.MenuFlashStatus, self, AttackGroup, true ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
end
|
||||
|
||||
local DetectedItems = self.Detection:GetDetectedItems()
|
||||
|
||||
for Index, DetectedItemData in pairs( DetectedItems ) do
|
||||
for DesignateIndex, Designating in pairs( self.Designating ) do
|
||||
|
||||
local DetectedItem = self.Detection:GetDetectedItem( DesignateIndex )
|
||||
|
||||
if DetectedItem then
|
||||
|
||||
local Report = self.Detection:DetectedItemMenu( Index, AttackGroup )
|
||||
|
||||
if not self.Designating[Index] then
|
||||
local DetectedMenu = MENU_GROUP:New( AttackGroup, Report, DesignateMenu )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Lase target 60 secs", DetectedMenu, self.MenuLaseOn, self, Index, 60 )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Lase target 120 secs", DetectedMenu, self.MenuLaseOn, self, Index, 120 )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke red", DetectedMenu, self.MenuSmoke, self, Index, SMOKECOLOR.Red )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke blue", DetectedMenu, self.MenuSmoke, self, Index, SMOKECOLOR.Blue )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke green", DetectedMenu, self.MenuSmoke, self, Index, SMOKECOLOR.Green )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke white", DetectedMenu, self.MenuSmoke, self, Index, SMOKECOLOR.White )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke orange", DetectedMenu, self.MenuSmoke, self, Index, SMOKECOLOR.Orange )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Illuminate", DetectedMenu, self.MenuIlluminate, self, Index )
|
||||
else
|
||||
if self.Designating[Index] == "Laser" then
|
||||
Report = "Lasing " .. Report
|
||||
elseif self.Designating[Index] == "Smoke" then
|
||||
Report = "Smoking " .. Report
|
||||
elseif self.Designating[Index] == "Illuminate" then
|
||||
Report = "Illuminating " .. Report
|
||||
end
|
||||
local DetectedMenu = MENU_GROUP:New( AttackGroup, Report, DesignateMenu )
|
||||
if self.Designating[Index] == "Laser" then
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Stop lasing", DetectedMenu, self.MenuLaseOff, self, Index )
|
||||
local Coord = self.Detection:GetDetectedItemCoordinate( DesignateIndex )
|
||||
local ID = self.Detection:GetDetectedItemID( DesignateIndex )
|
||||
local MenuText = ID .. ", " .. Coord:ToStringA2G( AttackGroup )
|
||||
|
||||
if Designating == "" then
|
||||
MenuText = "(-) " .. MenuText
|
||||
local DetectedMenu = MENU_GROUP:New( AttackGroup, MenuText, MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Search other target", DetectedMenu, self.MenuForget, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
for LaserCode, MenuText in pairs( self.MenuLaserCodes ) do
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, string.format( MenuText, LaserCode ), DetectedMenu, self.MenuLaseCode, self, DesignateIndex, 60, LaserCode ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
end
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Lase with random laser code(s)", DetectedMenu, self.MenuLaseOn, self, DesignateIndex, 60 ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke red", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Red ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke blue", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Blue ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke green", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Green ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke white", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.White ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Smoke orange", DetectedMenu, self.MenuSmoke, self, DesignateIndex, SMOKECOLOR.Orange ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Illuminate", DetectedMenu, self.MenuIlluminate, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
else
|
||||
if Designating == "Laser" then
|
||||
MenuText = "(L) " .. MenuText
|
||||
elseif Designating == "Smoke" then
|
||||
MenuText = "(S) " .. MenuText
|
||||
elseif Designating == "Illuminate" then
|
||||
MenuText = "(I) " .. MenuText
|
||||
end
|
||||
local DetectedMenu = MENU_GROUP:New( AttackGroup, MenuText, MenuDesignate ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
if Designating == "Laser" then
|
||||
MENU_GROUP_COMMAND:New( AttackGroup, "Stop lasing", DetectedMenu, self.MenuLaseOff, self, DesignateIndex ):SetTime( MenuTime ):SetTag( self.DesignateName )
|
||||
else
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
MenuDesignate:Remove( MenuTime, self.DesignateName )
|
||||
end
|
||||
)
|
||||
|
||||
@@ -692,13 +912,23 @@ do -- DESIGNATE
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #DESIGNATE self
|
||||
function DESIGNATE:MenuForget( Index )
|
||||
|
||||
self:E("Forget")
|
||||
|
||||
self.Designating[Index] = nil
|
||||
self:SetDesignateMenu()
|
||||
end
|
||||
|
||||
---
|
||||
-- @param #DESIGNATE self
|
||||
function DESIGNATE:MenuAutoLase( AutoLase )
|
||||
|
||||
self:E("AutoLase")
|
||||
|
||||
self:SetAutoLase( AutoLase )
|
||||
self:SetAutoLase( AutoLase, true )
|
||||
end
|
||||
|
||||
---
|
||||
@@ -708,7 +938,7 @@ do -- DESIGNATE
|
||||
self:E("Designate through Smoke")
|
||||
|
||||
self.Designating[Index] = "Smoke"
|
||||
self:__Smoke( 1, Index, Color )
|
||||
self:Smoke( Index, Color )
|
||||
end
|
||||
|
||||
---
|
||||
@@ -729,96 +959,204 @@ do -- DESIGNATE
|
||||
self:E("Designate through Lase")
|
||||
|
||||
self:__LaseOn( 1, Index, Duration )
|
||||
self:SetDesignateMenu()
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #DESIGNATE self
|
||||
function DESIGNATE:MenuLaseCode( Index, Duration, LaserCode )
|
||||
|
||||
self:E( "Designate through Lase using " .. LaserCode )
|
||||
|
||||
self:__LaseOn( 1, Index, Duration, LaserCode )
|
||||
self:SetDesignateMenu()
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #DESIGNATE self
|
||||
function DESIGNATE:MenuLaseOff( Index, Duration )
|
||||
|
||||
self:E("Lasing off")
|
||||
|
||||
self.Designating[Index] = nil
|
||||
self.Designating[Index] = ""
|
||||
self:__LaseOff( 1, Index )
|
||||
self:SetDesignateMenu()
|
||||
end
|
||||
|
||||
---
|
||||
-- @param #DESIGNATE self
|
||||
function DESIGNATE:onafterLaseOn( From, Event, To, Index, Duration )
|
||||
function DESIGNATE:onafterLaseOn( From, Event, To, Index, Duration, LaserCode )
|
||||
|
||||
self.Designating[Index] = "Laser"
|
||||
self:Lasing( Index, Duration )
|
||||
self.LaseStart = timer.getTime()
|
||||
self.LaseDuration = Duration
|
||||
self:__Lasing( -1, Index, Duration, LaserCode )
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #DESIGNATE self
|
||||
-- @return #DESIGNATE
|
||||
function DESIGNATE:onafterLasing( From, Event, To, Index, Duration )
|
||||
function DESIGNATE:onafterLasing( From, Event, To, Index, Duration, LaserCodeRequested )
|
||||
|
||||
|
||||
local TargetSetUnit = self.Detection:GetDetectedSet( Index )
|
||||
|
||||
local MarkingCount = 0
|
||||
local MarkedTypes = {}
|
||||
local ReportTypes = REPORT:New()
|
||||
local ReportLaserCodes = REPORT:New()
|
||||
|
||||
TargetSetUnit:Flush()
|
||||
|
||||
--self:F( { Recces = self.Recces } )
|
||||
for TargetUnit, RecceData in pairs( self.Recces ) do
|
||||
local Recce = RecceData -- Wrapper.Unit#UNIT
|
||||
self:F( { TargetUnit = TargetUnit, Recce = Recce:GetName() } )
|
||||
if not Recce:IsLasing() then
|
||||
local LaserCode = Recce:GetLaserCode() --(Not deleted when stopping with lasing).
|
||||
local LaserCode = Recce:GetLaserCode() -- (Not deleted when stopping with lasing).
|
||||
self:F( { ClearingLaserCode = LaserCode } )
|
||||
self.LaserCodesUsed[LaserCode] = nil
|
||||
self.Recces[TargetUnit] = nil
|
||||
end
|
||||
end
|
||||
|
||||
TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0,
|
||||
--- @param Wrapper.Unit#UNIT SmokeUnit
|
||||
function( TargetUnit )
|
||||
self:E("In procedure")
|
||||
if TargetUnit:IsAlive() then
|
||||
local Recce = self.Recces[TargetUnit]
|
||||
if not Recce then
|
||||
for RecceGroupID, RecceGroup in pairs( self.RecceSet:GetSet() ) do
|
||||
for UnitID, UnitData in pairs( RecceGroup:GetUnits() or {} ) do
|
||||
local RecceUnit = UnitData -- Wrapper.Unit#UNIT
|
||||
if RecceUnit:IsLasing() == false then
|
||||
if RecceUnit:IsDetected( TargetUnit ) and RecceUnit:IsLOS( TargetUnit ) then
|
||||
local LaserCodeIndex = math.random( 1, #self.LaserCodes )
|
||||
local LaserCode = self.LaserCodes[LaserCodeIndex]
|
||||
if not self.LaserCodesUsed[LaserCode] then
|
||||
self.LaserCodesUsed[LaserCode] = LaserCodeIndex
|
||||
local Spot = RecceUnit:LaseUnit( TargetUnit, LaserCode, Duration )
|
||||
local AttackSet = self.AttackSet
|
||||
function Spot:OnAfterDestroyed( From, Event, To )
|
||||
self:E( "Destroyed Message" )
|
||||
self.Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() .. " destroyed. " .. TargetSetUnit:Count() .. " targets left.", 5, AttackSet )
|
||||
end
|
||||
self.Recces[TargetUnit] = RecceUnit
|
||||
RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.", 5, self.AttackSet )
|
||||
break
|
||||
end
|
||||
else
|
||||
RecceUnit:MessageToSetGroup( "Can't mark " .. TargetUnit:GetTypeName(), 5, self.AttackSet )
|
||||
end
|
||||
else
|
||||
-- The Recce is lasing, but the Target is not detected or within LOS. So stop lasing and send a report.
|
||||
if not RecceUnit:IsDetected( TargetUnit ) or not RecceUnit:IsLOS( TargetUnit ) then
|
||||
local Recce = self.Recces[TargetUnit] -- Wrapper.Unit#UNIT
|
||||
if Recce then
|
||||
Recce:LaseOff()
|
||||
Recce:MessageToGroup( "Target " .. TargetUnit:GetTypeName() "out of LOS. Cancelling lase!", 5, self.AttackSet )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
Recce:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. Recce.LaserCode .. ".", 5, self.AttackSet )
|
||||
end
|
||||
|
||||
-- If a specific lasercode is requested, we disable one active lase!
|
||||
if LaserCodeRequested then
|
||||
for TargetUnit, RecceData in pairs( self.Recces ) do -- We break after the first has been processed.
|
||||
local Recce = RecceData -- Wrapper.Unit#UNIT
|
||||
self:F( { TargetUnit = TargetUnit, Recce = Recce:GetName() } )
|
||||
if Recce:IsLasing() then
|
||||
-- When a Recce is lasing, we switch the lasing off, and clear the references to the lasing in the DESIGNATE class.
|
||||
Recce:LaseOff() -- Switch off the lasing.
|
||||
local LaserCode = Recce:GetLaserCode() -- (Not deleted when stopping with lasing).
|
||||
self:F( { ClearingLaserCode = LaserCode } )
|
||||
self.LaserCodesUsed[LaserCode] = nil
|
||||
self.Recces[TargetUnit] = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
self:__Lasing( 15, Index, Duration )
|
||||
end
|
||||
|
||||
self:SetDesignateMenu()
|
||||
if self.AutoLase or ( not self.AutoLase and ( self.LaseStart + Duration >= timer.getTime() ) ) then
|
||||
|
||||
TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0,
|
||||
--- @param Wrapper.Unit#UNIT SmokeUnit
|
||||
function( TargetUnit )
|
||||
|
||||
self:F( { TargetUnit = TargetUnit:GetName() } )
|
||||
|
||||
if MarkingCount < self.MaximumMarkings then
|
||||
|
||||
if TargetUnit:IsAlive() then
|
||||
|
||||
local Recce = self.Recces[TargetUnit]
|
||||
|
||||
if not Recce then
|
||||
|
||||
self:E( "Lasing..." )
|
||||
self.RecceSet:Flush()
|
||||
|
||||
for RecceGroupID, RecceGroup in pairs( self.RecceSet:GetSet() ) do
|
||||
for UnitID, UnitData in pairs( RecceGroup:GetUnits() or {} ) do
|
||||
|
||||
local RecceUnit = UnitData -- Wrapper.Unit#UNIT
|
||||
local RecceUnitDesc = RecceUnit:GetDesc()
|
||||
--self:F( { RecceUnit = RecceUnit:GetName(), RecceDescription = RecceUnitDesc } )
|
||||
|
||||
if RecceUnit:IsLasing() == false then
|
||||
--self:F( { IsDetected = RecceUnit:IsDetected( TargetUnit ), IsLOS = RecceUnit:IsLOS( TargetUnit ) } )
|
||||
|
||||
if RecceUnit:IsDetected( TargetUnit ) and RecceUnit:IsLOS( TargetUnit ) then
|
||||
|
||||
local LaserCodeIndex = math.random( 1, #self.LaserCodes )
|
||||
local LaserCode = self.LaserCodes[LaserCodeIndex]
|
||||
--self:F( { LaserCode = LaserCode, LaserCodeUsed = self.LaserCodesUsed[LaserCode] } )
|
||||
|
||||
if LaserCodeRequested and LaserCodeRequested ~= LaserCode then
|
||||
LaserCode = LaserCodeRequested
|
||||
LaserCodeRequested = nil
|
||||
end
|
||||
|
||||
if not self.LaserCodesUsed[LaserCode] then
|
||||
|
||||
self.LaserCodesUsed[LaserCode] = LaserCodeIndex
|
||||
local Spot = RecceUnit:LaseUnit( TargetUnit, LaserCode, Duration )
|
||||
local AttackSet = self.AttackSet
|
||||
|
||||
function Spot:OnAfterDestroyed( From, Event, To )
|
||||
self:E( "Destroyed Message" )
|
||||
self.Recce:ToSetGroup( "Target " .. TargetUnit:GetTypeName() .. " destroyed. " .. TargetSetUnit:Count() .. " targets left.", 5, AttackSet, self.DesignateName )
|
||||
end
|
||||
|
||||
self.Recces[TargetUnit] = RecceUnit
|
||||
RecceUnit:MessageToSetGroup( "Marking " .. TargetUnit:GetTypeName() .. " with laser " .. RecceUnit:GetSpot().LaserCode .. " for " .. Duration .. "s.", 5, self.AttackSet, self.DesignateName )
|
||||
-- OK. We have assigned for the Recce a TargetUnit. We can exit the function.
|
||||
MarkingCount = MarkingCount + 1
|
||||
local TargetUnitType = TargetUnit:GetTypeName()
|
||||
if not MarkedTypes[TargetUnitType] then
|
||||
MarkedTypes[TargetUnitType] = true
|
||||
ReportTypes:Add(TargetUnitType)
|
||||
end
|
||||
ReportLaserCodes:Add(RecceUnit.LaserCode)
|
||||
return
|
||||
end
|
||||
else
|
||||
--RecceUnit:MessageToSetGroup( "Can't mark " .. TargetUnit:GetTypeName(), 5, self.AttackSet )
|
||||
end
|
||||
else
|
||||
-- The Recce is lasing, but the Target is not detected or within LOS. So stop lasing and send a report.
|
||||
|
||||
if not RecceUnit:IsDetected( TargetUnit ) or not RecceUnit:IsLOS( TargetUnit ) then
|
||||
|
||||
local Recce = self.Recces[TargetUnit] -- Wrapper.Unit#UNIT
|
||||
|
||||
if Recce then
|
||||
Recce:LaseOff()
|
||||
Recce:MessageToSetGroup( "Target " .. TargetUnit:GetTypeName() "out of LOS. Cancelling lase!", 5, self.AttackSet, self.DesignateName )
|
||||
end
|
||||
else
|
||||
MarkingCount = MarkingCount + 1
|
||||
local TargetUnitType = TargetUnit:GetTypeName()
|
||||
if not MarkedTypes[TargetUnitType] then
|
||||
MarkedTypes[TargetUnitType] = true
|
||||
ReportTypes:Add(TargetUnitType)
|
||||
end
|
||||
ReportLaserCodes:Add(RecceUnit.LaserCode)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
MarkingCount = MarkingCount + 1
|
||||
local TargetUnitType = TargetUnit:GetTypeName()
|
||||
if not MarkedTypes[TargetUnitType] then
|
||||
MarkedTypes[TargetUnitType] = true
|
||||
ReportTypes:Add(TargetUnitType)
|
||||
end
|
||||
ReportLaserCodes:Add(Recce.LaserCode)
|
||||
--Recce:MessageToSetGroup( self.DesignateName .. ": Marking " .. TargetUnit:GetTypeName() .. " with laser " .. Recce.LaserCode .. ".", 5, self.AttackSet )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
local MarkedTypesText = ReportTypes:Text(', ')
|
||||
local MarkedLaserCodesText = ReportLaserCodes:Text(', ')
|
||||
for MarkedType, MarketCount in pairs( MarkedTypes ) do
|
||||
self.CC:GetPositionable():MessageToSetGroup( "Marking " .. MarkingCount .. " x " .. MarkedTypesText .. " with lasers " .. MarkedLaserCodesText .. ".", 5, self.AttackSet, self.DesignateName )
|
||||
end
|
||||
|
||||
self:__Lasing( -30, Index, Duration, LaserCodeRequested )
|
||||
|
||||
self:SetDesignateMenu()
|
||||
|
||||
else
|
||||
self:__LaseOff( 1 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -830,7 +1168,7 @@ do -- DESIGNATE
|
||||
local CC = self.CC:GetPositionable()
|
||||
|
||||
if CC then
|
||||
CC:MessageToSetGroup( "Stopped lasing.", 5, self.AttackSet )
|
||||
CC:MessageToSetGroup( "Stopped lasing.", 5, self.AttackSet, self.DesignateName )
|
||||
end
|
||||
|
||||
local TargetSetUnit = self.Detection:GetDetectedSet( Index )
|
||||
@@ -839,7 +1177,7 @@ do -- DESIGNATE
|
||||
|
||||
for TargetID, RecceData in pairs( Recces ) do
|
||||
local Recce = RecceData -- Wrapper.Unit#UNIT
|
||||
Recce:MessageToSetGroup( "Stopped lasing " .. Recce:GetSpot().Target:GetTypeName() .. ".", 5, self.AttackSet )
|
||||
Recce:MessageToSetGroup( "Stopped lasing " .. Recce:GetSpot().Target:GetTypeName() .. ".", 5, self.AttackSet, self.DesignateName )
|
||||
Recce:LaseOff()
|
||||
end
|
||||
|
||||
@@ -859,19 +1197,29 @@ do -- DESIGNATE
|
||||
local TargetSetUnit = self.Detection:GetDetectedSet( Index )
|
||||
local TargetSetUnitCount = TargetSetUnit:Count()
|
||||
|
||||
TargetSetUnit:ForEachUnit(
|
||||
local MarkedCount = 0
|
||||
|
||||
TargetSetUnit:ForEachUnitPerThreatLevel( 10, 0,
|
||||
--- @param Wrapper.Unit#UNIT SmokeUnit
|
||||
function( SmokeUnit )
|
||||
self:E("In procedure")
|
||||
if math.random( 1, TargetSetUnitCount ) == math.random( 1, TargetSetUnitCount ) then
|
||||
|
||||
if MarkedCount < self.MaximumMarkings then
|
||||
|
||||
MarkedCount = MarkedCount + 1
|
||||
|
||||
self:E( "Smoking ..." )
|
||||
|
||||
local RecceGroup = self.RecceSet:FindNearestGroupFromPointVec2(SmokeUnit:GetPointVec2())
|
||||
local RecceUnit = RecceGroup:GetUnit( 1 )
|
||||
|
||||
if RecceUnit then
|
||||
RecceUnit:MessageToSetGroup( "Smoking " .. SmokeUnit:GetTypeName() .. ".", 5, self.AttackSet )
|
||||
SCHEDULER:New( self,
|
||||
|
||||
RecceUnit:MessageToSetGroup( "Smoking " .. SmokeUnit:GetTypeName() .. ".", 5, self.AttackSet, self.DesignateName )
|
||||
|
||||
self.MarkScheduler:Schedule( self,
|
||||
function()
|
||||
if SmokeUnit:IsAlive() then
|
||||
SmokeUnit:Smoke( Color, 150 )
|
||||
SmokeUnit:Smoke( Color, 50, 2 )
|
||||
end
|
||||
self:Done( Index )
|
||||
end, {}, math.random( 5, 20 )
|
||||
@@ -896,8 +1244,8 @@ do -- DESIGNATE
|
||||
local RecceGroup = self.RecceSet:FindNearestGroupFromPointVec2(TargetUnit:GetPointVec2())
|
||||
local RecceUnit = RecceGroup:GetUnit( 1 )
|
||||
if RecceUnit then
|
||||
RecceUnit:MessageToSetGroup( "Illuminating " .. TargetUnit:GetTypeName() .. ".", 5, self.AttackSet )
|
||||
SCHEDULER:New( self,
|
||||
RecceUnit:MessageToSetGroup( "Illuminating " .. TargetUnit:GetTypeName() .. ".", 5, self.AttackSet, self.DesignateName )
|
||||
self.MarkScheduler:Schedule( self,
|
||||
function()
|
||||
if TargetUnit:IsAlive() then
|
||||
TargetUnit:GetPointVec3():AddY(300):IlluminationBomb()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -875,7 +875,7 @@ function ESCORT:_AttackTarget( DetectedItemID )
|
||||
end, Tasks
|
||||
)
|
||||
|
||||
Tasks[#Tasks+1] = EscortGroup:TaskFunction( 1, 2, "_Resume", { "''" } )
|
||||
Tasks[#Tasks+1] = EscortGroup:TaskFunction( "_Resume", { "''" } )
|
||||
|
||||
EscortGroup:SetTask(
|
||||
EscortGroup:TaskCombo(
|
||||
@@ -1161,19 +1161,23 @@ function ESCORT:_ReportTargetsScheduler()
|
||||
for ClientEscortGroupName, EscortGroupData in pairs( self.EscortClient._EscortGroups ) do
|
||||
|
||||
local ClientEscortTargets = EscortGroupData.Detection
|
||||
--local EscortUnit = EscortGroupData:GetUnit( 1 )
|
||||
|
||||
for DetectedItemID, DetectedItem in ipairs( DetectedItems ) do
|
||||
for DetectedItemID, DetectedItem in pairs( DetectedItems ) do
|
||||
self:E( { DetectedItemID, DetectedItem } )
|
||||
-- Remove the sub menus of the Attack menu of the Escort for the EscortGroup.
|
||||
|
||||
local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItemID, EscortGroupData )
|
||||
local DetectedItemReportSummary = self.Detection:DetectedItemReportSummary( DetectedItemID, EscortGroupData.EscortGroup, _DATABASE:GetPlayerSettings( self.EscortClient:GetPlayerName() ) )
|
||||
|
||||
if ClientEscortGroupName == EscortGroupName then
|
||||
|
||||
DetectedMsgs[#DetectedMsgs+1] = DetectedItemReportSummary
|
||||
local DetectedMsg = DetectedItemReportSummary:Text("\n")
|
||||
DetectedMsgs[#DetectedMsgs+1] = DetectedMsg
|
||||
|
||||
self:T( DetectedMsg )
|
||||
|
||||
MENU_CLIENT_COMMAND:New( self.EscortClient,
|
||||
DetectedItemReportSummary,
|
||||
DetectedMsg,
|
||||
self.EscortMenuAttackNearbyTargets,
|
||||
ESCORT._AttackTarget,
|
||||
self,
|
||||
@@ -1182,10 +1186,12 @@ function ESCORT:_ReportTargetsScheduler()
|
||||
else
|
||||
if self.EscortMenuTargetAssistance then
|
||||
|
||||
self:T( DetectedItemReportSummary )
|
||||
local DetectedMsg = DetectedItemReportSummary:Text("\n")
|
||||
self:T( DetectedMsg )
|
||||
|
||||
local MenuTargetAssistance = MENU_CLIENT:New( self.EscortClient, EscortGroupData.EscortName, self.EscortMenuTargetAssistance )
|
||||
MENU_CLIENT_COMMAND:New( self.EscortClient,
|
||||
DetectedItemReportSummary,
|
||||
DetectedMsg,
|
||||
MenuTargetAssistance,
|
||||
ESCORT._AssistTarget,
|
||||
self,
|
||||
@@ -1201,7 +1207,7 @@ function ESCORT:_ReportTargetsScheduler()
|
||||
end
|
||||
self:E( DetectedMsgs )
|
||||
if DetectedTargets then
|
||||
self.EscortGroup:MessageToClient( "Detected targets:\n" .. table.concat( DetectedMsgs, "\n" ), 20, self.EscortClient )
|
||||
self.EscortGroup:MessageToClient( "Reporting detected targets:\n" .. table.concat( DetectedMsgs, "\n" ), 20, self.EscortClient )
|
||||
else
|
||||
self.EscortGroup:MessageToClient( "No targets detected.", 10, self.EscortClient )
|
||||
end
|
||||
|
||||
@@ -442,7 +442,7 @@ function MISSILETRAINER._MenuMessages( MenuParameters )
|
||||
|
||||
if MenuParameters.Distance ~= nil then
|
||||
self.Distance = MenuParameters.Distance
|
||||
MESSAGE:New( "Hit detection distance set to " .. self.Distance * 1000 .. " meters", 15, "Menu" ):ToAll()
|
||||
MESSAGE:New( "Hit detection distance set to " .. ( self.Distance * 1000 ) .. " meters", 15, "Menu" ):ToAll()
|
||||
end
|
||||
|
||||
end
|
||||
@@ -570,72 +570,76 @@ function MISSILETRAINER:_TrackMissiles()
|
||||
for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do
|
||||
|
||||
local Client = ClientData.Client
|
||||
self:T2( { Client:GetName() } )
|
||||
|
||||
if Client and Client:IsAlive() then
|
||||
|
||||
for MissileDataID, MissileData in pairs( ClientData.MissileData ) do
|
||||
self:T3( MissileDataID )
|
||||
|
||||
local TrainerSourceUnit = MissileData.TrainerSourceUnit
|
||||
local TrainerWeapon = MissileData.TrainerWeapon
|
||||
local TrainerTargetUnit = MissileData.TrainerTargetUnit
|
||||
local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName
|
||||
local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched
|
||||
for MissileDataID, MissileData in pairs( ClientData.MissileData ) do
|
||||
self:T3( MissileDataID )
|
||||
|
||||
if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then
|
||||
local PositionMissile = TrainerWeapon:getPosition().p
|
||||
local TargetVec3 = Client:GetVec3()
|
||||
|
||||
local Distance = ( ( PositionMissile.x - TargetVec3.x )^2 +
|
||||
( PositionMissile.y - TargetVec3.y )^2 +
|
||||
( PositionMissile.z - TargetVec3.z )^2
|
||||
) ^ 0.5 / 1000
|
||||
|
||||
if Distance <= self.Distance then
|
||||
-- Hit alert
|
||||
TrainerWeapon:destroy()
|
||||
if self.MessagesOnOff == true and self.AlertsHitsOnOff == true then
|
||||
|
||||
self:T( "killed" )
|
||||
|
||||
local Message = MESSAGE:New(
|
||||
string.format( "%s launched by %s killed %s",
|
||||
TrainerWeapon:getTypeName(),
|
||||
TrainerSourceUnit:GetTypeName(),
|
||||
TrainerTargetUnit:GetPlayerName()
|
||||
), 15, "Hit Alert" )
|
||||
|
||||
if self.AlertsToAll == true then
|
||||
Message:ToAll()
|
||||
else
|
||||
Message:ToClient( Client )
|
||||
local TrainerSourceUnit = MissileData.TrainerSourceUnit
|
||||
local TrainerWeapon = MissileData.TrainerWeapon
|
||||
local TrainerTargetUnit = MissileData.TrainerTargetUnit
|
||||
local TrainerWeaponTypeName = MissileData.TrainerWeaponTypeName
|
||||
local TrainerWeaponLaunched = MissileData.TrainerWeaponLaunched
|
||||
|
||||
if Client and Client:IsAlive() and TrainerSourceUnit and TrainerSourceUnit:IsAlive() and TrainerWeapon and TrainerWeapon:isExist() and TrainerTargetUnit and TrainerTargetUnit:IsAlive() then
|
||||
local PositionMissile = TrainerWeapon:getPosition().p
|
||||
local TargetVec3 = Client:GetVec3()
|
||||
|
||||
local Distance = ( ( PositionMissile.x - TargetVec3.x )^2 +
|
||||
( PositionMissile.y - TargetVec3.y )^2 +
|
||||
( PositionMissile.z - TargetVec3.z )^2
|
||||
) ^ 0.5 / 1000
|
||||
|
||||
if Distance <= self.Distance then
|
||||
-- Hit alert
|
||||
TrainerWeapon:destroy()
|
||||
if self.MessagesOnOff == true and self.AlertsHitsOnOff == true then
|
||||
|
||||
self:T( "killed" )
|
||||
|
||||
local Message = MESSAGE:New(
|
||||
string.format( "%s launched by %s killed %s",
|
||||
TrainerWeapon:getTypeName(),
|
||||
TrainerSourceUnit:GetTypeName(),
|
||||
TrainerTargetUnit:GetPlayerName()
|
||||
), 15, "Hit Alert" )
|
||||
|
||||
if self.AlertsToAll == true then
|
||||
Message:ToAll()
|
||||
else
|
||||
Message:ToClient( Client )
|
||||
end
|
||||
|
||||
MissileData = nil
|
||||
table.remove( ClientData.MissileData, MissileDataID )
|
||||
self:T(ClientData.MissileData)
|
||||
end
|
||||
end
|
||||
else
|
||||
if not ( TrainerWeapon and TrainerWeapon:isExist() ) then
|
||||
if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then
|
||||
-- Weapon does not exist anymore. Delete from Table
|
||||
local Message = MESSAGE:New(
|
||||
string.format( "%s launched by %s self destructed!",
|
||||
TrainerWeaponTypeName,
|
||||
TrainerSourceUnit:GetTypeName()
|
||||
), 5, "Tracking" )
|
||||
|
||||
if self.AlertsToAll == true then
|
||||
Message:ToAll()
|
||||
else
|
||||
Message:ToClient( Client )
|
||||
end
|
||||
end
|
||||
|
||||
MissileData = nil
|
||||
table.remove( ClientData.MissileData, MissileDataID )
|
||||
self:T(ClientData.MissileData)
|
||||
self:T( ClientData.MissileData )
|
||||
end
|
||||
end
|
||||
else
|
||||
if not ( TrainerWeapon and TrainerWeapon:isExist() ) then
|
||||
if self.MessagesOnOff == true and self.AlertsLaunchesOnOff == true then
|
||||
-- Weapon does not exist anymore. Delete from Table
|
||||
local Message = MESSAGE:New(
|
||||
string.format( "%s launched by %s self destructed!",
|
||||
TrainerWeaponTypeName,
|
||||
TrainerSourceUnit:GetTypeName()
|
||||
), 5, "Tracking" )
|
||||
|
||||
if self.AlertsToAll == true then
|
||||
Message:ToAll()
|
||||
else
|
||||
Message:ToClient( Client )
|
||||
end
|
||||
end
|
||||
MissileData = nil
|
||||
table.remove( ClientData.MissileData, MissileDataID )
|
||||
self:T( ClientData.MissileData )
|
||||
end
|
||||
end
|
||||
else
|
||||
self.TrackingMissiles[ClientDataID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -651,7 +655,7 @@ function MISSILETRAINER:_TrackMissiles()
|
||||
for ClientDataID, ClientData in pairs( self.TrackingMissiles ) do
|
||||
|
||||
local Client = ClientData.Client
|
||||
self:T2( { Client:GetName() } )
|
||||
--self:T2( { Client:GetName() } )
|
||||
|
||||
|
||||
ClientData.MessageToClient = ""
|
||||
@@ -661,7 +665,7 @@ function MISSILETRAINER:_TrackMissiles()
|
||||
for TrackingDataID, TrackingData in pairs( self.TrackingMissiles ) do
|
||||
|
||||
for MissileDataID, MissileData in pairs( TrackingData.MissileData ) do
|
||||
self:T3( MissileDataID )
|
||||
--self:T3( MissileDataID )
|
||||
|
||||
local TrainerSourceUnit = MissileData.TrainerSourceUnit
|
||||
local TrainerWeapon = MissileData.TrainerWeapon
|
||||
|
||||
305
Moose Development/Moose/Functional/Protect.lua
Normal file
305
Moose Development/Moose/Functional/Protect.lua
Normal file
@@ -0,0 +1,305 @@
|
||||
--- **Functional** -- The PROTECT class handles the protection of objects, which can be zones, units, scenery.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
-- ### Contributions: **MillerTime**
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module Protect
|
||||
|
||||
--- @type PROTECT.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-)
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
--- @type PROTECT
|
||||
-- @extends #PROTECT.__
|
||||
|
||||
--- # PROTECT, extends @{Base#BASE}
|
||||
--
|
||||
-- @field #PROTECT
|
||||
PROTECT = {
|
||||
ClassName = "PROTECT",
|
||||
}
|
||||
|
||||
--- Get the ProtectZone
|
||||
-- @param #PROTECT self
|
||||
-- @return Core.Zone#ZONE_BASE
|
||||
function PROTECT:GetProtectZone()
|
||||
return self.ProtectZone
|
||||
end
|
||||
|
||||
|
||||
--- Get the name of the ProtectZone
|
||||
-- @param #PROTECT self
|
||||
-- @return #string
|
||||
function PROTECT:GetProtectZoneName()
|
||||
return self.ProtectZone:GetName()
|
||||
end
|
||||
|
||||
|
||||
--- Set the owning coalition of the zone.
|
||||
-- @param #PROTECT self
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition
|
||||
function PROTECT:SetCoalition( Coalition )
|
||||
self.Coalition = Coalition
|
||||
end
|
||||
|
||||
|
||||
--- Get the owning coalition of the zone.
|
||||
-- @param #PROTECT self
|
||||
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
||||
function PROTECT:GetCoalition()
|
||||
return self.Coalition
|
||||
end
|
||||
|
||||
|
||||
--- Get the owning coalition name of the zone.
|
||||
-- @param #PROTECT self
|
||||
-- @return #string Coalition name.
|
||||
function PROTECT:GetCoalitionName()
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
return "Blue"
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.RED then
|
||||
return "Red"
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.NEUTRAL then
|
||||
return "Neutral"
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
|
||||
function PROTECT:IsGuarded()
|
||||
|
||||
local IsGuarded = self.ProtectZone:IsAllInZoneOfCoalition( self.Coalition )
|
||||
self:E( { IsGuarded = IsGuarded } )
|
||||
return IsGuarded
|
||||
end
|
||||
|
||||
function PROTECT:IsCaptured()
|
||||
|
||||
local IsCaptured = self.ProtectZone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
self:E( { IsCaptured = IsCaptured } )
|
||||
return IsCaptured
|
||||
end
|
||||
|
||||
|
||||
function PROTECT:IsAttacked()
|
||||
|
||||
local IsAttacked = self.ProtectZone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
self:E( { IsAttacked = IsAttacked } )
|
||||
return IsAttacked
|
||||
end
|
||||
|
||||
|
||||
function PROTECT:IsEmpty()
|
||||
|
||||
local IsEmpty = self.ProtectZone:IsNoneInZone()
|
||||
self:E( { IsEmpty = IsEmpty } )
|
||||
return IsEmpty
|
||||
end
|
||||
|
||||
|
||||
--- Check if the units are still alive.
|
||||
-- @param #PROTECT self
|
||||
function PROTECT:AreProtectUnitsAlive()
|
||||
|
||||
local IsAlive = false
|
||||
|
||||
local UnitSet = self.ProtectUnitSet
|
||||
UnitSet:Flush()
|
||||
local UnitList = UnitSet:GetSet()
|
||||
|
||||
for UnitID, ProtectUnit in pairs( UnitList ) do
|
||||
local IsUnitAlive = ProtectUnit:IsAlive()
|
||||
if IsUnitAlive == true then
|
||||
IsAlive = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return IsAlive
|
||||
end
|
||||
|
||||
--- Check if the statics are still alive.
|
||||
-- @param #PROTECT self
|
||||
function PROTECT:AreProtectStaticsAlive()
|
||||
|
||||
local IsAlive = false
|
||||
|
||||
local StaticSet = self.ProtectStaticSet
|
||||
StaticSet:Flush()
|
||||
local StaticList = StaticSet:GetSet()
|
||||
|
||||
for UnitID, ProtectStatic in pairs( StaticList ) do
|
||||
local IsStaticAlive = ProtectStatic:IsAlive()
|
||||
if IsStaticAlive == true then
|
||||
IsAlive = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return IsAlive
|
||||
end
|
||||
|
||||
|
||||
--- Check if there is a capture unit in the zone.
|
||||
-- @param #PROTECT self
|
||||
function PROTECT:IsCaptureUnitInZone()
|
||||
|
||||
local CaptureUnitSet = self.CaptureUnitSet
|
||||
CaptureUnitSet:Flush()
|
||||
|
||||
local IsInZone = self.CaptureUnitSet:IsPartiallyInZone( self.ProtectZone )
|
||||
|
||||
self:E({IsInZone = IsInZone})
|
||||
|
||||
return IsInZone
|
||||
end
|
||||
|
||||
--- Smoke.
|
||||
-- @param #PROTECT self
|
||||
-- @param #SMOKECOLOR.Color SmokeColor
|
||||
function PROTECT:Smoke( SmokeColor )
|
||||
|
||||
self.SmokeColor = SmokeColor
|
||||
end
|
||||
|
||||
|
||||
--- Flare.
|
||||
-- @param #PROTECT self
|
||||
-- @param #SMOKECOLOR.Color FlareColor
|
||||
function PROTECT:Flare( FlareColor )
|
||||
self.ProtectZone:FlareZone( FlareColor, math.random( 1, 360 ) )
|
||||
end
|
||||
|
||||
|
||||
--- Mark.
|
||||
-- @param #PROTECT self
|
||||
function PROTECT:Mark()
|
||||
|
||||
local Coord = self.ProtectZone:GetCoordinate()
|
||||
local ZoneName = self:GetProtectZoneName()
|
||||
local State = self:GetState()
|
||||
|
||||
if self.MarkRed and self.MarkBlue then
|
||||
self:E( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } )
|
||||
Coord:RemoveMark( self.MarkRed )
|
||||
Coord:RemoveMark( self.MarkBlue )
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
self.MarkRed = Coord:MarkToCoalitionRed( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
else
|
||||
self.MarkRed = Coord:MarkToCoalitionRed( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Bound.
|
||||
-- @param #PROTECT self
|
||||
function PROTECT:onafterStart()
|
||||
|
||||
self:ScheduleRepeat( 5, 15, 0.1, nil, self.StatusCoalition, self )
|
||||
self:ScheduleRepeat( 5, 15, 0.1, nil, self.StatusZone, self )
|
||||
self:ScheduleRepeat( 10, 15, 0, nil, self.StatusSmoke, self )
|
||||
end
|
||||
|
||||
--- Bound.
|
||||
-- @param #PROTECT self
|
||||
function PROTECT:onenterGuarded()
|
||||
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
--elf.ProtectZone:BoundZone( 12, country.id.USA )
|
||||
else
|
||||
--self.ProtectZone:BoundZone( 12, country.id.RUSSIA )
|
||||
end
|
||||
|
||||
self:Mark()
|
||||
|
||||
end
|
||||
|
||||
function PROTECT:onenterCaptured()
|
||||
|
||||
local NewCoalition = self.ProtectZone:GetCoalition()
|
||||
self:E( { NewCoalition = NewCoalition } )
|
||||
self:SetCoalition( NewCoalition )
|
||||
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
|
||||
function PROTECT:onenterEmpty()
|
||||
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
|
||||
function PROTECT:onenterAttacked()
|
||||
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
|
||||
--- Check status Coalition ownership.
|
||||
-- @param #PROTECT self
|
||||
function PROTECT:StatusCoalition()
|
||||
|
||||
self:E( { State = self:GetState() } )
|
||||
|
||||
self.ProtectZone:Scan()
|
||||
|
||||
if self:IsGuarded() then
|
||||
self:Guard()
|
||||
else
|
||||
if self:IsCaptured() then
|
||||
self:Capture()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Check status Zone.
|
||||
-- @param #PROTECT self
|
||||
function PROTECT:StatusZone()
|
||||
|
||||
self:E( { State = self:GetState() } )
|
||||
|
||||
self.ProtectZone:Scan()
|
||||
|
||||
if self:IsAttacked() then
|
||||
self:Attack()
|
||||
else
|
||||
if self:IsEmpty() then
|
||||
self:Empty()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Check status Smoke.
|
||||
-- @param #PROTECT self
|
||||
function PROTECT:StatusSmoke()
|
||||
|
||||
local CurrentTime = timer.getTime()
|
||||
|
||||
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
|
||||
if self.SmokeColor then
|
||||
self.ProtectZone:GetCoordinate():Smoke( self.SmokeColor )
|
||||
--self.SmokeColor = nil
|
||||
self.SmokeTime = CurrentTime
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
4272
Moose Development/Moose/Functional/RAT.lua
Normal file
4272
Moose Development/Moose/Functional/RAT.lua
Normal file
File diff suppressed because it is too large
Load Diff
@@ -102,7 +102,9 @@
|
||||
-- A mission has goals and achievements. The scoring system provides an API to set additional scores when a goal or achievement event happens.
|
||||
-- Use the method @{#SCORING.AddGoalScore}() to add a score for a Player at any time in your mission.
|
||||
--
|
||||
-- ## 1.5) Configure fratricide level.
|
||||
-- ## 1.5) (Decommissioned) Configure fratricide level.
|
||||
--
|
||||
-- **This functionality is decomissioned until the DCS bug concerning Unit:destroy() not being functional in multi player for player units has been fixed by ED**.
|
||||
--
|
||||
-- When a player commits too much damage to friendlies, his penalty score will reach a certain level.
|
||||
-- Use the method @{#SCORING.SetFratricide}() to define the level when a player gets kicked.
|
||||
@@ -258,7 +260,7 @@ function SCORING:New( GameName )
|
||||
|
||||
-- Configure Messages
|
||||
self:SetMessagesToAll()
|
||||
self:SetMessagesHit( true )
|
||||
self:SetMessagesHit( false )
|
||||
self:SetMessagesDestroy( true )
|
||||
self:SetMessagesScore( true )
|
||||
self:SetMessagesZone( true )
|
||||
@@ -294,7 +296,7 @@ end
|
||||
-- @param #string DisplayMessagePrefix (Default="Scoring: ") The scoring prefix string.
|
||||
-- @return #SCORING
|
||||
function SCORING:SetDisplayMessagePrefix( DisplayMessagePrefix )
|
||||
self.DisplayMessagePrefix = DisplayMessagePrefix or "Scoring: "
|
||||
self.DisplayMessagePrefix = DisplayMessagePrefix or ""
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -608,14 +610,15 @@ function SCORING:_AddPlayerFromUnit( UnitData )
|
||||
if self.Players[PlayerName].UnitCoalition ~= UnitCoalition then
|
||||
self.Players[PlayerName].Penalty = self.Players[PlayerName].Penalty + 50
|
||||
self.Players[PlayerName].PenaltyCoalition = self.Players[PlayerName].PenaltyCoalition + 1
|
||||
MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] ..
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' changed coalition from " .. _SCORINGCoalition[self.Players[PlayerName].UnitCoalition] .. " to " .. _SCORINGCoalition[UnitCoalition] ..
|
||||
"(changed " .. self.Players[PlayerName].PenaltyCoalition .. " times the coalition). 50 Penalty points added.",
|
||||
2
|
||||
MESSAGE.Type.Information
|
||||
):ToAll()
|
||||
self:ScoreCSV( PlayerName, "", "COALITION_PENALTY", 1, -50, self.Players[PlayerName].UnitName, _SCORINGCoalition[self.Players[PlayerName].UnitCoalition], _SCORINGCategory[self.Players[PlayerName].UnitCategory], self.Players[PlayerName].UnitType,
|
||||
UnitName, _SCORINGCoalition[UnitCoalition], _SCORINGCategory[UnitCategory], UnitData:GetTypeName() )
|
||||
end
|
||||
end
|
||||
|
||||
self.Players[PlayerName].UnitName = UnitName
|
||||
self.Players[PlayerName].UnitCoalition = UnitCoalition
|
||||
self.Players[PlayerName].UnitCategory = UnitCategory
|
||||
@@ -624,26 +627,59 @@ function SCORING:_AddPlayerFromUnit( UnitData )
|
||||
self.Players[PlayerName].ThreatLevel = UnitThreatLevel
|
||||
self.Players[PlayerName].ThreatType = UnitThreatType
|
||||
|
||||
-- TODO: DCS bug concerning Units with skill level client don't get destroyed in multi player. This logic is deactivated until this bug gets fixed.
|
||||
--[[
|
||||
if self.Players[PlayerName].Penalty > self.Fratricide * 0.50 then
|
||||
if self.Players[PlayerName].PenaltyWarning < 1 then
|
||||
MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty,
|
||||
30
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "': WARNING! If you continue to commit FRATRICIDE and have a PENALTY score higher than " .. self.Fratricide .. ", you will be COURT MARTIALED and DISMISSED from this mission! \nYour total penalty is: " .. self.Players[PlayerName].Penalty,
|
||||
MESSAGE.Type.Information
|
||||
):ToAll()
|
||||
self.Players[PlayerName].PenaltyWarning = self.Players[PlayerName].PenaltyWarning + 1
|
||||
end
|
||||
end
|
||||
|
||||
if self.Players[PlayerName].Penalty > self.Fratricide then
|
||||
--UnitData:Destroy()
|
||||
MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!",
|
||||
10
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' committed FRATRICIDE, he will be COURT MARTIALED and is DISMISSED from this mission!",
|
||||
MESSAGE.Type.Information
|
||||
):ToAll()
|
||||
UnitData:GetGroup():Destroy()
|
||||
end
|
||||
--]]
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Add a goal score for a player.
|
||||
-- The method takes the Player name for which the Goal score needs to be set.
|
||||
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
|
||||
-- A free text can be given that is shown to the players.
|
||||
-- The Score can be both positive and negative.
|
||||
-- @param #SCORING self
|
||||
-- @param #string PlayerName The name of the Player.
|
||||
-- @param #string GoalTag The string or identifier that is used in the CSV file to identify the goal (sort or group later in Excel).
|
||||
-- @param #string Text A free text that is shown to the players.
|
||||
-- @param #number Score The score can be both positive or negative ( Penalty ).
|
||||
function SCORING:AddGoalScorePlayer( PlayerName, GoalTag, Text, Score )
|
||||
|
||||
self:E( { PlayerName, PlayerName, GoalTag, Text, Score } )
|
||||
|
||||
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
|
||||
if PlayerName then
|
||||
local PlayerData = self.Players[PlayerName]
|
||||
|
||||
PlayerData.Goals[GoalTag] = PlayerData.Goals[GoalTag] or { Score = 0 }
|
||||
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
|
||||
PlayerData.Score = PlayerData.Score + Score
|
||||
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. Text, MESSAGE.Type.Information ):ToAll()
|
||||
|
||||
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, nil )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Add a goal score for a player.
|
||||
-- The method takes the PlayerUnit for which the Goal score needs to be set.
|
||||
-- The GoalTag is a string or identifier that is taken into the CSV file scoring log to identify the goal.
|
||||
@@ -668,7 +704,7 @@ function SCORING:AddGoalScore( PlayerUnit, GoalTag, Text, Score )
|
||||
PlayerData.Goals[GoalTag].Score = PlayerData.Goals[GoalTag].Score + Score
|
||||
PlayerData.Score = PlayerData.Score + Score
|
||||
|
||||
MESSAGE:New( self.DisplayMessagePrefix .. Text, 30 ):ToAll()
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. Text, MESSAGE.Type.Information ):ToAll()
|
||||
|
||||
self:ScoreCSV( PlayerName, "", "GOAL_" .. string.upper( GoalTag ), 1, Score, PlayerUnit:GetName() )
|
||||
end
|
||||
@@ -704,12 +740,45 @@ function SCORING:_AddMissionTaskScore( Mission, PlayerUnit, Text, Score )
|
||||
PlayerData.Score = self.Players[PlayerName].Score + Score
|
||||
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
|
||||
|
||||
MESSAGE:New( self.DisplayMessagePrefix .. MissionName .. " : " .. Text .. " Score: " .. Score, 30 ):ToAll()
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. MissionName .. " : " .. Text .. " Score: " .. Score, MESSAGE.Type.Information ):ToAll()
|
||||
|
||||
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score, PlayerUnit:GetName() )
|
||||
end
|
||||
end
|
||||
|
||||
--- Registers Scores the players completing a Mission Task.
|
||||
-- @param #SCORING self
|
||||
-- @param Tasking.Mission#MISSION Mission
|
||||
-- @param #string PlayerName
|
||||
-- @param #string Text
|
||||
-- @param #number Score
|
||||
function SCORING:_AddMissionGoalScore( Mission, PlayerName, Text, Score )
|
||||
|
||||
local MissionName = Mission:GetName()
|
||||
|
||||
self:E( { Mission:GetName(), PlayerName, Text, Score } )
|
||||
|
||||
-- PlayerName can be nil, if the Unit with the player crashed or due to another reason.
|
||||
if PlayerName then
|
||||
local PlayerData = self.Players[PlayerName]
|
||||
|
||||
if not PlayerData.Mission[MissionName] then
|
||||
PlayerData.Mission[MissionName] = {}
|
||||
PlayerData.Mission[MissionName].ScoreTask = 0
|
||||
PlayerData.Mission[MissionName].ScoreMission = 0
|
||||
end
|
||||
|
||||
self:T( PlayerName )
|
||||
self:T( PlayerData.Mission[MissionName] )
|
||||
|
||||
PlayerData.Score = self.Players[PlayerName].Score + Score
|
||||
PlayerData.Mission[MissionName].ScoreTask = self.Players[PlayerName].Mission[MissionName].ScoreTask + Score
|
||||
|
||||
MESSAGE:NewType( string.format( "%s%s: %s! Player %s receives %d score!", self.DisplayMessagePrefix, MissionName, Text, PlayerName, Score ), MESSAGE.Type.Information ):ToAll()
|
||||
|
||||
self:ScoreCSV( PlayerName, "", "TASK_" .. MissionName:gsub( ' ', '_' ), 1, Score )
|
||||
end
|
||||
end
|
||||
|
||||
--- Registers Mission Scores for possible multiple players that contributed in the Mission.
|
||||
-- @param #SCORING self
|
||||
@@ -732,9 +801,9 @@ function SCORING:_AddMissionScore( Mission, Text, Score )
|
||||
PlayerData.Score = PlayerData.Score + Score
|
||||
PlayerData.Mission[MissionName].ScoreMission = PlayerData.Mission[MissionName].ScoreMission + Score
|
||||
|
||||
MESSAGE:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " ..
|
||||
MESSAGE:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' has " .. Text .. " in Mission '" .. MissionName .. "'. " ..
|
||||
Score .. " mission score!",
|
||||
60 ):ToAll()
|
||||
MESSAGE.Type.Information ):ToAll()
|
||||
|
||||
self:ScoreCSV( PlayerName, "", "MISSION_" .. MissionName:gsub( ' ', '_' ), 1, Score )
|
||||
end
|
||||
@@ -902,19 +971,19 @@ function SCORING:_EventOnHit( Event )
|
||||
|
||||
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " ..
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly player '" .. TargetPlayerName .. "' " ..
|
||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
|
||||
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
2
|
||||
MESSAGE.Type.Update
|
||||
)
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
else
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit a friendly target " ..
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " ..
|
||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
|
||||
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
2
|
||||
MESSAGE.Type.Update
|
||||
)
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
@@ -926,19 +995,19 @@ function SCORING:_EventOnHit( Event )
|
||||
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
|
||||
if TargetPlayerName ~= nil then -- It is a player hitting another player ...
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " ..
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy player '" .. TargetPlayerName .. "' " ..
|
||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
||||
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
2
|
||||
MESSAGE.Type.Update
|
||||
)
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
else
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit an enemy target " ..
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " ..
|
||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
||||
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
2
|
||||
MESSAGE.Type.Update
|
||||
)
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
@@ -947,8 +1016,8 @@ function SCORING:_EventOnHit( Event )
|
||||
end
|
||||
else -- A scenery object was hit.
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit a scenery object.",
|
||||
2
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit scenery object.",
|
||||
MESSAGE.Type.Update
|
||||
)
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
@@ -1008,10 +1077,10 @@ function SCORING:_EventOnHit( Event )
|
||||
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1
|
||||
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit a friendly target " ..
|
||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " ..
|
||||
"Penalty: -" .. PlayerHit.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
2
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
|
||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
||||
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Update
|
||||
)
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
@@ -1021,10 +1090,10 @@ function SCORING:_EventOnHit( Event )
|
||||
PlayerHit.Score = PlayerHit.Score + 1
|
||||
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit an enemy target " ..
|
||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " ..
|
||||
"Score: " .. PlayerHit.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
2
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " ..
|
||||
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
|
||||
"Score: +" .. PlayerHit.Score .. " = " .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Update
|
||||
)
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
@@ -1032,8 +1101,8 @@ function SCORING:_EventOnHit( Event )
|
||||
end
|
||||
else -- A scenery object was hit.
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit a scenery object.",
|
||||
2
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit scenery object.",
|
||||
MESSAGE.Type.Update
|
||||
)
|
||||
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
|
||||
@@ -1131,19 +1200,19 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
||||
|
||||
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " ..
|
||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.PenaltyDestroy .. " times. " ..
|
||||
"Penalty: -" .. TargetDestroy.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
15
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " ..
|
||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Information
|
||||
)
|
||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||
else
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed a friendly target " ..
|
||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.PenaltyDestroy .. " times. " ..
|
||||
"Penalty: -" .. TargetDestroy.Penalty .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
15
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " ..
|
||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Information
|
||||
)
|
||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||
@@ -1165,19 +1234,19 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
||||
TargetDestroy.ScoreDestroy = TargetDestroy.ScoreDestroy + 1
|
||||
if Player.HitPlayers[TargetPlayerName] then -- A player destroyed another player
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " ..
|
||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.ScoreDestroy .. " times. " ..
|
||||
"Score: " .. TargetDestroy.Score .. ". Score Total:" .. Player.Score - Player.Penalty,
|
||||
15
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " ..
|
||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Information
|
||||
)
|
||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||
else
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed an enemy " ..
|
||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. TargetDestroy.ScoreDestroy .. " times. " ..
|
||||
"Score: " .. TargetDestroy.Score .. ". Total:" .. Player.Score - Player.Penalty,
|
||||
15
|
||||
:NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " ..
|
||||
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
|
||||
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
|
||||
MESSAGE.Type.Information
|
||||
)
|
||||
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
|
||||
@@ -1191,9 +1260,9 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
||||
Player.Score = Player.Score + Score
|
||||
TargetDestroy.Score = TargetDestroy.Score + Score
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " ..
|
||||
:NewType( self.DisplayMessagePrefix .. "Special target '" .. TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " .. " destroyed! " ..
|
||||
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! Total: " .. Player.Score - Player.Penalty,
|
||||
15
|
||||
MESSAGE.Type.Information
|
||||
)
|
||||
:ToAllIf( self:IfMessagesScore() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesScore() and self:IfMessagesToCoalition() )
|
||||
@@ -1210,10 +1279,10 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
||||
Player.Score = Player.Score + Score
|
||||
TargetDestroy.Score = TargetDestroy.Score + Score
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
|
||||
:NewType( self.DisplayMessagePrefix .. "Target destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
|
||||
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " ..
|
||||
"Total: " .. Player.Score - Player.Penalty,
|
||||
15 )
|
||||
MESSAGE.Type.Information )
|
||||
:ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
|
||||
self:ScoreCSV( PlayerName, TargetPlayerName, "DESTROY_SCORE", 1, Score, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
|
||||
@@ -1232,10 +1301,10 @@ function SCORING:_EventOnDeadOrCrash( Event )
|
||||
Player.Score = Player.Score + Score
|
||||
TargetDestroy.Score = TargetDestroy.Score + Score
|
||||
MESSAGE
|
||||
:New( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
|
||||
:NewType( self.DisplayMessagePrefix .. "Scenery destroyed in zone '" .. ScoreZone:GetName() .. "'." ..
|
||||
"Player '" .. PlayerName .. "' receives an extra " .. Score .. " points! " ..
|
||||
"Total: " .. Player.Score - Player.Penalty,
|
||||
15
|
||||
MESSAGE.Type.Information
|
||||
)
|
||||
:ToAllIf( self:IfMessagesZone() and self:IfMessagesToAll() )
|
||||
:ToCoalitionIf( InitCoalition, self:IfMessagesZone() and self:IfMessagesToCoalition() )
|
||||
@@ -1522,7 +1591,7 @@ function SCORING:ReportScoreGroupSummary( PlayerGroup )
|
||||
PlayerScore,
|
||||
PlayerPenalty
|
||||
)
|
||||
MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup )
|
||||
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1579,7 +1648,7 @@ function SCORING:ReportScoreGroupDetailed( PlayerGroup )
|
||||
ReportGoals,
|
||||
ReportMissions
|
||||
)
|
||||
MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup )
|
||||
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Detailed ):ToGroup( PlayerGroup )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1628,7 +1697,7 @@ function SCORING:ReportScoreAllSummary( PlayerGroup )
|
||||
PlayerScore,
|
||||
PlayerPenalty
|
||||
)
|
||||
MESSAGE:New( PlayerMessage, 30, "Player '" .. PlayerName .. "'" ):ToGroup( PlayerGroup )
|
||||
MESSAGE:NewType( PlayerMessage, MESSAGE.Type.Overview ):ToGroup( PlayerGroup )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
442
Moose Development/Moose/Functional/ZoneCaptureCoalition.lua
Normal file
442
Moose Development/Moose/Functional/ZoneCaptureCoalition.lua
Normal file
@@ -0,0 +1,442 @@
|
||||
--- **Functional** -- (WIP R2.3) Models the process to capture a Zone for a Coalition, which is guarded by another Coalition.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Contributions: **Millertime**: Concept
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module ZoneCaptureCoalition
|
||||
|
||||
do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
--- @type ZONE_CAPTURE_COALITION
|
||||
-- @extends Functional.ZoneGoalCoalition#ZONE_GOAL_COALITION
|
||||
|
||||
|
||||
--- # ZONE\_CAPTURE\_COALITION class, extends @{ZoneGoalCoalition#ZONE_GOAL_COALITION}
|
||||
--
|
||||
-- Models the process to capture a Zone for a Coalition, which is guarded by another Coalition.
|
||||
--
|
||||
-- ---
|
||||
--
|
||||
-- 
|
||||
--
|
||||
-- ---
|
||||
--
|
||||
-- The Zone is initially **Guarded** by the __owning coalition__, which is the coalition that initially occupies the zone with units of its coalition.
|
||||
-- Once units of an other coalition are entering the Zone, the state will change to **Attacked**. As long as these units remain in the zone, the state keeps set to Attacked.
|
||||
-- When all units are destroyed in the Zone, the state will change to **Empty**, which expresses that the Zone is empty, and can be captured.
|
||||
-- When units of the other coalition are in the Zone, and no other units of the owning coalition is in the Zone, the Zone is captured, and its state will change to **Captured**.
|
||||
--
|
||||
-- Event handlers can be defined by the mission designer to action on the state transitions.
|
||||
--
|
||||
-- ## 1. ZONE\_CAPTURE\_COALITION constructor
|
||||
--
|
||||
-- * @{#ZONE_CAPTURE_COALITION.New}(): Creates a new ZONE\_CAPTURE\_COALITION object.
|
||||
--
|
||||
-- ## 2. ZONE\_CAPTURE\_COALITION is a finite state machine (FSM).
|
||||
--
|
||||
-- ### 2.1 ZONE\_CAPTURE\_COALITION States
|
||||
--
|
||||
-- * **Captured**: The Zone has been captured by an other coalition.
|
||||
-- * **Attacked**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
|
||||
-- * **Guarded**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
|
||||
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
|
||||
--
|
||||
-- ### 2.2 ZONE\_CAPTURE\_COALITION Events
|
||||
--
|
||||
-- * **Capture**: The Zone has been captured by an other coalition.
|
||||
-- * **Attack**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
|
||||
-- * **Guard**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
|
||||
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
|
||||
--
|
||||
-- @field #ZONE_CAPTURE_COALITION
|
||||
ZONE_CAPTURE_COALITION = {
|
||||
ClassName = "ZONE_CAPTURE_COALITION",
|
||||
}
|
||||
|
||||
--- @field #table ZONE_CAPTURE_COALITION.States
|
||||
ZONE_CAPTURE_COALITION.States = {}
|
||||
|
||||
--- ZONE_CAPTURE_COALITION Constructor.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
||||
-- @return #ZONE_CAPTURE_COALITION
|
||||
-- @usage
|
||||
--
|
||||
-- AttackZone = ZONE:New( "AttackZone" )
|
||||
--
|
||||
-- ZoneCaptureCoalition = ZONE_CAPTURE_COALITION:New( AttackZone, coalition.side.RED ) -- Create a new ZONE_CAPTURE_COALITION object of zone AttackZone with ownership RED coalition.
|
||||
-- ZoneCaptureCoalition:__Guard( 1 ) -- Start the Guarding of the AttackZone.
|
||||
--
|
||||
function ZONE_CAPTURE_COALITION:New( Zone, Coalition )
|
||||
|
||||
local self = BASE:Inherit( self, ZONE_GOAL_COALITION:New( Zone, Coalition ) ) -- #ZONE_CAPTURE_COALITION
|
||||
|
||||
self:F( { Zone = Zone, Coalition = Coalition } )
|
||||
|
||||
do
|
||||
|
||||
--- Captured State Handler OnLeave for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveCaptured
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Captured State Handler OnEnter for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterCaptured
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
|
||||
--- Attacked State Handler OnLeave for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveAttacked
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Attacked State Handler OnEnter for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterAttacked
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
end
|
||||
|
||||
do
|
||||
|
||||
--- Guarded State Handler OnLeave for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveGuarded
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Guarded State Handler OnEnter for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterGuarded
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
|
||||
--- Empty State Handler OnLeave for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnLeaveEmpty
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Empty State Handler OnEnter for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnEnterEmpty
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
end
|
||||
|
||||
self:AddTransition( "*", "Guard", "Guarded" )
|
||||
|
||||
--- Guard Handler OnBefore for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeGuard
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Guard Handler OnAfter for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterGuard
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- Guard Trigger for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] Guard
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
|
||||
--- Guard Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] __Guard
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #number Delay
|
||||
|
||||
self:AddTransition( "*", "Empty", "Empty" )
|
||||
|
||||
--- Empty Handler OnBefore for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeEmpty
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Empty Handler OnAfter for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterEmpty
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- Empty Trigger for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] Empty
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
|
||||
--- Empty Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] __Empty
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #number Delay
|
||||
|
||||
|
||||
self:AddTransition( { "Guarded", "Empty" }, "Attack", "Attacked" )
|
||||
|
||||
--- Attack Handler OnBefore for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeAttack
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Attack Handler OnAfter for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterAttack
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- Attack Trigger for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] Attack
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
|
||||
--- Attack Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] __Attack
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #number Delay
|
||||
|
||||
self:AddTransition( { "Guarded", "Attacked", "Empty" }, "Capture", "Captured" )
|
||||
|
||||
--- Capture Handler OnBefore for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnBeforeCapture
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Capture Handler OnAfter for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] OnAfterCapture
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- Capture Trigger for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] Capture
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
|
||||
--- Capture Asynchronous Trigger for ZONE\_CAPTURE\_COALITION
|
||||
-- @function [parent=#ZONE_CAPTURE_COALITION] __Capture
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
-- @param #number Delay
|
||||
|
||||
if not self.ScheduleStatusZone then
|
||||
self.ScheduleStatusZone = self:ScheduleRepeat( 15, 15, 0.1, nil, self.StatusZone, self )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:onenterCaptured()
|
||||
|
||||
self:GetParent( self, ZONE_CAPTURE_COALITION ).onenterCaptured( self )
|
||||
|
||||
self.Goal:Achieved()
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsGuarded()
|
||||
|
||||
local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition )
|
||||
self:E( { IsGuarded = IsGuarded } )
|
||||
return IsGuarded
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsEmpty()
|
||||
|
||||
local IsEmpty = self.Zone:IsNoneInZone()
|
||||
self:E( { IsEmpty = IsEmpty } )
|
||||
return IsEmpty
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsCaptured()
|
||||
|
||||
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
self:E( { IsCaptured = IsCaptured } )
|
||||
return IsCaptured
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsAttacked()
|
||||
|
||||
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
self:E( { IsAttacked = IsAttacked } )
|
||||
return IsAttacked
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Mark.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:Mark()
|
||||
|
||||
local Coord = self.Zone:GetCoordinate()
|
||||
local ZoneName = self:GetZoneName()
|
||||
local State = self:GetState()
|
||||
|
||||
if self.MarkRed and self.MarkBlue then
|
||||
self:E( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } )
|
||||
Coord:RemoveMark( self.MarkRed )
|
||||
Coord:RemoveMark( self.MarkBlue )
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Blue\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Blue\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
else
|
||||
self.MarkRed = Coord:MarkToCoalitionRed( "Coalition: Red\nGuard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Coalition: Red\nCapture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
end
|
||||
end
|
||||
|
||||
--- Bound.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:onenterGuarded()
|
||||
|
||||
--self:GetParent( self ):onenterGuarded()
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
--elf.ProtectZone:BoundZone( 12, country.id.USA )
|
||||
else
|
||||
--self.ProtectZone:BoundZone( 12, country.id.RUSSIA )
|
||||
end
|
||||
|
||||
self:Mark()
|
||||
|
||||
end
|
||||
|
||||
function ZONE_CAPTURE_COALITION:onenterCaptured()
|
||||
|
||||
--self:GetParent( self ):onenterCaptured()
|
||||
|
||||
local NewCoalition = self.Zone:GetScannedCoalition()
|
||||
self:E( { NewCoalition = NewCoalition } )
|
||||
self:SetCoalition( NewCoalition )
|
||||
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:onenterEmpty()
|
||||
|
||||
--self:GetParent( self ):onenterEmpty()
|
||||
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:onenterAttacked()
|
||||
|
||||
--self:GetParent( self ):onenterAttacked()
|
||||
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
|
||||
--- When started, check the Coalition status.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:onafterGuard()
|
||||
|
||||
--self:E({BASE:GetParent( self )})
|
||||
--BASE:GetParent( self ).onafterGuard( self )
|
||||
|
||||
if not self.SmokeScheduler then
|
||||
self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsCaptured()
|
||||
|
||||
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
self:E( { IsCaptured = IsCaptured } )
|
||||
return IsCaptured
|
||||
end
|
||||
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsAttacked()
|
||||
|
||||
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
self:E( { IsAttacked = IsAttacked } )
|
||||
return IsAttacked
|
||||
end
|
||||
|
||||
|
||||
--- Check status Coalition ownership.
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:StatusZone()
|
||||
|
||||
local State = self:GetState()
|
||||
self:E( { State = self:GetState() } )
|
||||
|
||||
self:GetParent( self, ZONE_CAPTURE_COALITION ).StatusZone( self )
|
||||
|
||||
if State ~= "Guarded" and self:IsGuarded() then
|
||||
self:Guard()
|
||||
end
|
||||
|
||||
if State ~= "Empty" and self:IsEmpty() then
|
||||
self:Empty()
|
||||
end
|
||||
|
||||
if State ~= "Attacked" and self:IsAttacked() then
|
||||
self:Attack()
|
||||
end
|
||||
|
||||
if State ~= "Captured" and self:IsCaptured() then
|
||||
self:Capture()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
177
Moose Development/Moose/Functional/ZoneGoal.lua
Normal file
177
Moose Development/Moose/Functional/ZoneGoal.lua
Normal file
@@ -0,0 +1,177 @@
|
||||
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ZONE_GOAL models processes that have a Goal with a defined achievement involving a Zone.
|
||||
-- Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module ZoneGoal
|
||||
|
||||
do -- Zone
|
||||
|
||||
--- @type ZONE_GOAL
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
|
||||
--- # ZONE_GOAL class, extends @{Fsm#FSM}
|
||||
--
|
||||
-- ZONE_GOAL models processes that have a Goal with a defined achievement involving a Zone.
|
||||
-- Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- ## 1. ZONE_GOAL constructor
|
||||
--
|
||||
-- * @{#ZONE_GOAL.New}(): Creates a new ZONE_GOAL object.
|
||||
--
|
||||
-- ## 2. ZONE_GOAL is a finite state machine (FSM).
|
||||
--
|
||||
-- ### 2.1 ZONE_GOAL States
|
||||
--
|
||||
-- * None: Initial State
|
||||
--
|
||||
-- ### 2.2 ZONE_GOAL Events
|
||||
--
|
||||
-- * DestroyedUnit: A @{Unit} is destroyed in the Zone. The event will only get triggered if the method @{#ZONE_GOAL.MonitorDestroyedUnits}() is used.
|
||||
--
|
||||
-- @field #ZONE_GOAL
|
||||
ZONE_GOAL = {
|
||||
ClassName = "ZONE_GOAL",
|
||||
}
|
||||
|
||||
--- ZONE_GOAL Constructor.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param Core.Zone#ZONE_BASE Zone A @{Zone} object with the goal to be achieved.
|
||||
-- @return #ZONE_GOAL
|
||||
function ZONE_GOAL:New( Zone )
|
||||
|
||||
local self = BASE:Inherit( self, FSM:New() ) -- #ZONE_GOAL
|
||||
self:F( { Zone = Zone } )
|
||||
|
||||
self.Zone = Zone -- Core.Zone#ZONE_BASE
|
||||
self.Goal = GOAL:New()
|
||||
|
||||
self.SmokeTime = nil
|
||||
|
||||
self:AddTransition( "*", "DestroyedUnit", "*" )
|
||||
|
||||
--- DestroyedUnit Handler OnAfter for ZONE_GOAL
|
||||
-- @function [parent=#ZONE_GOAL] OnAfterDestroyedUnit
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Unit#UNIT DestroyedUnit The destroyed unit.
|
||||
-- @param #string PlayerName The name of the player.
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get the Zone
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @return Core.Zone#ZONE_BASE
|
||||
function ZONE_GOAL:GetZone()
|
||||
return self.Zone
|
||||
end
|
||||
|
||||
|
||||
--- Get the name of the ProtectZone
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @return #string
|
||||
function ZONE_GOAL:GetZoneName()
|
||||
return self.Zone:GetName()
|
||||
end
|
||||
|
||||
|
||||
--- Smoke the center of theh zone.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param #SMOKECOLOR.Color SmokeColor
|
||||
function ZONE_GOAL:Smoke( SmokeColor )
|
||||
|
||||
self:F( { SmokeColor = SmokeColor} )
|
||||
|
||||
self.SmokeColor = SmokeColor
|
||||
end
|
||||
|
||||
|
||||
--- Flare the center of the zone.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param #SMOKECOLOR.Color FlareColor
|
||||
function ZONE_GOAL:Flare( FlareColor )
|
||||
self.Zone:FlareZone( FlareColor, math.random( 1, 360 ) )
|
||||
end
|
||||
|
||||
|
||||
--- When started, check the Smoke and the Zone status.
|
||||
-- @param #ZONE_GOAL self
|
||||
function ZONE_GOAL:onafterGuard()
|
||||
|
||||
--self:GetParent( self ):onafterStart()
|
||||
|
||||
self:E("Guard")
|
||||
|
||||
--self:ScheduleRepeat( 15, 15, 0.1, nil, self.StatusZone, self )
|
||||
if not self.SmokeScheduler then
|
||||
self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Check status Smoke.
|
||||
-- @param #ZONE_GOAL self
|
||||
function ZONE_GOAL:StatusSmoke()
|
||||
|
||||
self:F({self.SmokeTime, self.SmokeColor})
|
||||
|
||||
local CurrentTime = timer.getTime()
|
||||
|
||||
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
|
||||
if self.SmokeColor then
|
||||
self.Zone:GetCoordinate():Smoke( self.SmokeColor )
|
||||
--self.SmokeColor = nil
|
||||
self.SmokeTime = CurrentTime
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- @param #ZONE_GOAL self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function ZONE_GOAL:__Destroyed( EventData )
|
||||
self:E( { "EventDead", EventData } )
|
||||
|
||||
self:E( { EventData.IniUnit } )
|
||||
|
||||
local Vec3 = EventData.IniDCSUnit:getPosition().p
|
||||
self:E( { Vec3 = Vec3 } )
|
||||
local ZoneGoal = self:GetZone()
|
||||
self:E({ZoneGoal})
|
||||
|
||||
if EventData.IniDCSUnit then
|
||||
if ZoneGoal:IsVec3InZone(Vec3) then
|
||||
local PlayerHits = _DATABASE.HITS[EventData.IniUnitName]
|
||||
if PlayerHits then
|
||||
for PlayerName, PlayerHit in pairs( PlayerHits.Players or {} ) do
|
||||
self.Goal:AddPlayerContribution( PlayerName )
|
||||
self:DestroyedUnit( EventData.IniUnitName, PlayerName )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Activate the event UnitDestroyed to be fired when a unit is destroyed in the zone.
|
||||
-- @param #ZONE_GOAL self
|
||||
function ZONE_GOAL:MonitorDestroyedUnits()
|
||||
|
||||
self:HandleEvent( EVENTS.Dead, self.__Destroyed )
|
||||
self:HandleEvent( EVENTS.Crash, self.__Destroyed )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
452
Moose Development/Moose/Functional/ZoneGoalCargo.lua
Normal file
452
Moose Development/Moose/Functional/ZoneGoalCargo.lua
Normal file
@@ -0,0 +1,452 @@
|
||||
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone and Cargo.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ZONE_GOAL_CARGO models processes that have a Goal with a defined achievement involving a Zone and Cargo.
|
||||
-- Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module ZoneGoalCargo
|
||||
|
||||
do -- ZoneGoal
|
||||
|
||||
--- @type ZONE_GOAL_CARGO
|
||||
-- @extends Functional.ZoneGoal#ZONE_GOAL
|
||||
|
||||
|
||||
--- # ZONE_GOAL_CARGO class, extends @{ZoneGoal#ZONE_GOAL}
|
||||
--
|
||||
-- ZONE_GOAL_CARGO models processes that have a Goal with a defined achievement involving a Zone and Cargo.
|
||||
-- Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- ## 1. ZONE_GOAL_CARGO constructor
|
||||
--
|
||||
-- * @{#ZONE_GOAL_CARGO.New}(): Creates a new ZONE_GOAL_CARGO object.
|
||||
--
|
||||
-- ## 2. ZONE_GOAL_CARGO is a finite state machine (FSM).
|
||||
--
|
||||
-- ### 2.1 ZONE_GOAL_CARGO States
|
||||
--
|
||||
-- * **Deployed**: The Zone has been captured by an other coalition.
|
||||
-- * **Airborne**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
|
||||
-- * **Loaded**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
|
||||
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
|
||||
--
|
||||
-- ### 2.2 ZONE_GOAL_CARGO Events
|
||||
--
|
||||
-- * **Capture**: The Zone has been captured by an other coalition.
|
||||
-- * **Attack**: The Zone is currently intruded by an other coalition. There are units of the owning coalition and an other coalition in the Zone.
|
||||
-- * **Guard**: The Zone is guarded by the owning coalition. There is no other unit of an other coalition in the Zone.
|
||||
-- * **Empty**: The Zone is empty. There is not valid unit in the Zone.
|
||||
--
|
||||
-- ### 2.3 ZONE_GOAL_CARGO State Machine
|
||||
--
|
||||
-- @field #ZONE_GOAL_CARGO
|
||||
ZONE_GOAL_CARGO = {
|
||||
ClassName = "ZONE_GOAL_CARGO",
|
||||
}
|
||||
|
||||
--- @field #table ZONE_GOAL_CARGO.States
|
||||
ZONE_GOAL_CARGO.States = {}
|
||||
|
||||
--- ZONE_GOAL_CARGO Constructor.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
||||
-- @return #ZONE_GOAL_CARGO
|
||||
function ZONE_GOAL_CARGO:New( Zone, Coalition )
|
||||
|
||||
local self = BASE:Inherit( self, ZONE_GOAL:New( Zone ) ) -- #ZONE_GOAL_CARGO
|
||||
self:F( { Zone = Zone, Coalition = Coalition } )
|
||||
|
||||
self:SetCoalition( Coalition )
|
||||
|
||||
do
|
||||
|
||||
--- Captured State Handler OnLeave for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveCaptured
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Captured State Handler OnEnter for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterCaptured
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
|
||||
--- Attacked State Handler OnLeave for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveAttacked
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Attacked State Handler OnEnter for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterAttacked
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
end
|
||||
|
||||
do
|
||||
|
||||
--- Guarded State Handler OnLeave for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveGuarded
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Guarded State Handler OnEnter for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterGuarded
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
|
||||
--- Empty State Handler OnLeave for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnLeaveEmpty
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Empty State Handler OnEnter for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnEnterEmpty
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
end
|
||||
|
||||
self:AddTransition( "*", "Guard", "Guarded" )
|
||||
|
||||
--- Guard Handler OnBefore for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeGuard
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Guard Handler OnAfter for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterGuard
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- Guard Trigger for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] Guard
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
|
||||
--- Guard Asynchronous Trigger for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] __Guard
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #number Delay
|
||||
|
||||
self:AddTransition( "*", "Empty", "Empty" )
|
||||
|
||||
--- Empty Handler OnBefore for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeEmpty
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Empty Handler OnAfter for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterEmpty
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- Empty Trigger for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] Empty
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
|
||||
--- Empty Asynchronous Trigger for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] __Empty
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #number Delay
|
||||
|
||||
|
||||
self:AddTransition( { "Guarded", "Empty" }, "Attack", "Attacked" )
|
||||
|
||||
--- Attack Handler OnBefore for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeAttack
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Attack Handler OnAfter for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterAttack
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- Attack Trigger for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] Attack
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
|
||||
--- Attack Asynchronous Trigger for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] __Attack
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #number Delay
|
||||
|
||||
self:AddTransition( { "Guarded", "Attacked", "Empty" }, "Capture", "Captured" )
|
||||
|
||||
--- Capture Handler OnBefore for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnBeforeCapture
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @return #boolean
|
||||
|
||||
--- Capture Handler OnAfter for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] OnAfterCapture
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- Capture Trigger for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] Capture
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
|
||||
--- Capture Asynchronous Trigger for ZONE_GOAL_CARGO
|
||||
-- @function [parent=#ZONE_GOAL_CARGO] __Capture
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param #number Delay
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition
|
||||
function ZONE_GOAL_CARGO:SetCoalition( Coalition )
|
||||
self.Coalition = Coalition
|
||||
end
|
||||
|
||||
|
||||
--- Get the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
||||
function ZONE_GOAL_CARGO:GetCoalition()
|
||||
return self.Coalition
|
||||
end
|
||||
|
||||
|
||||
--- Get the owning coalition name of the zone.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
-- @return #string Coalition name.
|
||||
function ZONE_GOAL_CARGO:GetCoalitionName()
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
return "Blue"
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.RED then
|
||||
return "Red"
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.NEUTRAL then
|
||||
return "Neutral"
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
|
||||
function ZONE_GOAL_CARGO:IsGuarded()
|
||||
|
||||
local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition )
|
||||
self:E( { IsGuarded = IsGuarded } )
|
||||
return IsGuarded
|
||||
end
|
||||
|
||||
|
||||
function ZONE_GOAL_CARGO:IsEmpty()
|
||||
|
||||
local IsEmpty = self.Zone:IsNoneInZone()
|
||||
self:E( { IsEmpty = IsEmpty } )
|
||||
return IsEmpty
|
||||
end
|
||||
|
||||
|
||||
function ZONE_GOAL_CARGO:IsCaptured()
|
||||
|
||||
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
self:E( { IsCaptured = IsCaptured } )
|
||||
return IsCaptured
|
||||
end
|
||||
|
||||
|
||||
function ZONE_GOAL_CARGO:IsAttacked()
|
||||
|
||||
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
self:E( { IsAttacked = IsAttacked } )
|
||||
return IsAttacked
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Mark.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
function ZONE_GOAL_CARGO:Mark()
|
||||
|
||||
local Coord = self.Zone:GetCoordinate()
|
||||
local ZoneName = self:GetZoneName()
|
||||
local State = self:GetState()
|
||||
|
||||
if self.MarkRed and self.MarkBlue then
|
||||
self:E( { MarkRed = self.MarkRed, MarkBlue = self.MarkBlue } )
|
||||
Coord:RemoveMark( self.MarkRed )
|
||||
Coord:RemoveMark( self.MarkBlue )
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
self.MarkRed = Coord:MarkToCoalitionRed( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
else
|
||||
self.MarkRed = Coord:MarkToCoalitionRed( "Guard Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
self.MarkBlue = Coord:MarkToCoalitionBlue( "Capture Zone: " .. ZoneName .. "\nStatus: " .. State )
|
||||
end
|
||||
end
|
||||
|
||||
--- Bound.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
function ZONE_GOAL_CARGO:onenterGuarded()
|
||||
|
||||
--self:GetParent( self ):onenterGuarded()
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
--elf.ProtectZone:BoundZone( 12, country.id.USA )
|
||||
else
|
||||
--self.ProtectZone:BoundZone( 12, country.id.RUSSIA )
|
||||
end
|
||||
|
||||
self:Mark()
|
||||
|
||||
end
|
||||
|
||||
function ZONE_GOAL_CARGO:onenterCaptured()
|
||||
|
||||
--self:GetParent( self ):onenterCaptured()
|
||||
|
||||
local NewCoalition = self.Zone:GetCoalition()
|
||||
self:E( { NewCoalition = NewCoalition } )
|
||||
self:SetCoalition( NewCoalition )
|
||||
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
|
||||
function ZONE_GOAL_CARGO:onenterEmpty()
|
||||
|
||||
--self:GetParent( self ):onenterEmpty()
|
||||
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
|
||||
function ZONE_GOAL_CARGO:onenterAttacked()
|
||||
|
||||
--self:GetParent( self ):onenterAttacked()
|
||||
|
||||
self:Mark()
|
||||
end
|
||||
|
||||
|
||||
--- When started, check the Coalition status.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
function ZONE_GOAL_CARGO:onafterGuard()
|
||||
|
||||
--self:E({BASE:GetParent( self )})
|
||||
--BASE:GetParent( self ).onafterGuard( self )
|
||||
|
||||
if not self.SmokeScheduler then
|
||||
self.SmokeScheduler = self:ScheduleRepeat( 1, 1, 0.1, nil, self.StatusSmoke, self )
|
||||
end
|
||||
if not self.ScheduleStatusZone then
|
||||
self.ScheduleStatusZone = self:ScheduleRepeat( 15, 15, 0.1, nil, self.StatusZone, self )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ZONE_GOAL_CARGO:IsCaptured()
|
||||
|
||||
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
self:E( { IsCaptured = IsCaptured } )
|
||||
return IsCaptured
|
||||
end
|
||||
|
||||
|
||||
function ZONE_GOAL_CARGO:IsAttacked()
|
||||
|
||||
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
self:E( { IsAttacked = IsAttacked } )
|
||||
return IsAttacked
|
||||
end
|
||||
|
||||
--- Check status Coalition ownership.
|
||||
-- @param #ZONE_GOAL_CARGO self
|
||||
function ZONE_GOAL_CARGO:StatusZone()
|
||||
|
||||
local State = self:GetState()
|
||||
self:E( { State = self:GetState() } )
|
||||
|
||||
self.Zone:Scan()
|
||||
|
||||
if State ~= "Guarded" and self:IsGuarded() then
|
||||
self:Guard()
|
||||
end
|
||||
|
||||
if State ~= "Empty" and self:IsEmpty() then
|
||||
self:Empty()
|
||||
end
|
||||
|
||||
if State ~= "Attacked" and self:IsAttacked() then
|
||||
self:Attack()
|
||||
end
|
||||
|
||||
if State ~= "Captured" and self:IsCaptured() then
|
||||
self:Capture()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
113
Moose Development/Moose/Functional/ZoneGoalCoalition.lua
Normal file
113
Moose Development/Moose/Functional/ZoneGoalCoalition.lua
Normal file
@@ -0,0 +1,113 @@
|
||||
--- **Functional (WIP)** -- Base class that models processes to achieve goals involving a Zone for a Coalition.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition.
|
||||
-- Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module ZoneGoalCoalition
|
||||
|
||||
do -- ZoneGoal
|
||||
|
||||
--- @type ZONE_GOAL_COALITION
|
||||
-- @extends Functional.ZoneGoal#ZONE_GOAL
|
||||
|
||||
|
||||
--- # ZONE_GOAL_COALITION class, extends @{ZoneGoal#ZONE_GOAL}
|
||||
--
|
||||
-- ZONE_GOAL_COALITION models processes that have a Goal with a defined achievement involving a Zone for a Coalition.
|
||||
-- Derived classes implement the ways how the achievements can be realized.
|
||||
--
|
||||
-- ## 1. ZONE_GOAL_COALITION constructor
|
||||
--
|
||||
-- * @{#ZONE_GOAL_COALITION.New}(): Creates a new ZONE_GOAL_COALITION object.
|
||||
--
|
||||
-- ## 2. ZONE_GOAL_COALITION is a finite state machine (FSM).
|
||||
--
|
||||
-- ### 2.1 ZONE_GOAL_COALITION States
|
||||
--
|
||||
-- ### 2.2 ZONE_GOAL_COALITION Events
|
||||
--
|
||||
-- ### 2.3 ZONE_GOAL_COALITION State Machine
|
||||
--
|
||||
-- @field #ZONE_GOAL_COALITION
|
||||
ZONE_GOAL_COALITION = {
|
||||
ClassName = "ZONE_GOAL_COALITION",
|
||||
}
|
||||
|
||||
--- @field #table ZONE_GOAL_COALITION.States
|
||||
ZONE_GOAL_COALITION.States = {}
|
||||
|
||||
--- ZONE_GOAL_COALITION Constructor.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @param Core.Zone#ZONE Zone A @{Zone} object with the goal to be achieved.
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition The initial coalition owning the zone.
|
||||
-- @return #ZONE_GOAL_COALITION
|
||||
function ZONE_GOAL_COALITION:New( Zone, Coalition )
|
||||
|
||||
local self = BASE:Inherit( self, ZONE_GOAL:New( Zone ) ) -- #ZONE_GOAL_COALITION
|
||||
self:F( { Zone = Zone, Coalition = Coalition } )
|
||||
|
||||
self:SetCoalition( Coalition )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Set the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @param DCSCoalition.DCSCoalition#coalition Coalition
|
||||
function ZONE_GOAL_COALITION:SetCoalition( Coalition )
|
||||
self.Coalition = Coalition
|
||||
end
|
||||
|
||||
|
||||
--- Get the owning coalition of the zone.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @return DCSCoalition.DCSCoalition#coalition Coalition.
|
||||
function ZONE_GOAL_COALITION:GetCoalition()
|
||||
return self.Coalition
|
||||
end
|
||||
|
||||
|
||||
--- Get the owning coalition name of the zone.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
-- @return #string Coalition name.
|
||||
function ZONE_GOAL_COALITION:GetCoalitionName()
|
||||
|
||||
if self.Coalition == coalition.side.BLUE then
|
||||
return "Blue"
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.RED then
|
||||
return "Red"
|
||||
end
|
||||
|
||||
if self.Coalition == coalition.side.NEUTRAL then
|
||||
return "Neutral"
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
|
||||
--- Check status Coalition ownership.
|
||||
-- @param #ZONE_GOAL_COALITION self
|
||||
function ZONE_GOAL_COALITION:StatusZone()
|
||||
|
||||
local State = self:GetState()
|
||||
self:E( { State = self:GetState() } )
|
||||
|
||||
self.Zone:Scan( { Object.Category.UNIT, Object.Category.STATIC } )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -13,80 +13,7 @@
|
||||
|
||||
|
||||
|
||||
--- The REPORT class
|
||||
-- @type REPORT
|
||||
-- @extends Core.Base#BASE
|
||||
REPORT = {
|
||||
ClassName = "REPORT",
|
||||
Title = "",
|
||||
}
|
||||
|
||||
--- Create a new REPORT.
|
||||
-- @param #REPORT self
|
||||
-- @param #string Title
|
||||
-- @return #REPORT
|
||||
function REPORT:New( Title )
|
||||
|
||||
local self = BASE:Inherit( self, BASE:New() ) -- #REPORT
|
||||
|
||||
self.Report = {}
|
||||
|
||||
Title = Title or ""
|
||||
if Title then
|
||||
self.Title = Title
|
||||
end
|
||||
|
||||
self:SetIndent( 3 )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Has the REPORT Text?
|
||||
-- @param #REPORT self
|
||||
-- @return #boolean
|
||||
function REPORT:HasText() --R2.1
|
||||
|
||||
return #self.Report > 0
|
||||
end
|
||||
|
||||
|
||||
--- Set indent of a REPORT.
|
||||
-- @param #REPORT self
|
||||
-- @param #number Indent
|
||||
-- @return #REPORT
|
||||
function REPORT:SetIndent( Indent ) --R2.1
|
||||
self.Indent = Indent
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Add a new line to a REPORT.
|
||||
-- @param #REPORT self
|
||||
-- @param #string Text
|
||||
-- @return #REPORT
|
||||
function REPORT:Add( Text )
|
||||
self.Report[#self.Report+1] = Text
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add a new line to a REPORT.
|
||||
-- @param #REPORT self
|
||||
-- @param #string Text
|
||||
-- @return #REPORT
|
||||
function REPORT:AddIndent( Text ) --R2.1
|
||||
self.Report[#self.Report+1] = string.rep(" ", self.Indent ) .. Text:gsub("\n","\n"..string.rep( " ", self.Indent ) )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Produces the text of the report, taking into account an optional delimeter, which is \n by default.
|
||||
-- @param #REPORT self
|
||||
-- @param #string Delimiter (optional) A delimiter text.
|
||||
-- @return #string The report text.
|
||||
function REPORT:Text( Delimiter )
|
||||
Delimiter = Delimiter or "\n"
|
||||
local ReportText = ( self.Title ~= "" and self.Title .. Delimiter or self.Title ) .. table.concat( self.Report, Delimiter ) or ""
|
||||
return ReportText
|
||||
end
|
||||
|
||||
--- The COMMANDCENTER class
|
||||
-- @type COMMANDCENTER
|
||||
@@ -207,6 +134,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
||||
local PlayerGroup = EventData.IniGroup -- The GROUP object should be filled!
|
||||
Mission:JoinUnit( PlayerUnit, PlayerGroup )
|
||||
end
|
||||
self:SetMenu()
|
||||
end
|
||||
)
|
||||
|
||||
@@ -260,6 +188,8 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
||||
)
|
||||
|
||||
self:SetMenu()
|
||||
|
||||
_SETTINGS:SetSystemMenu( CommandCenterPositionable )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -428,10 +358,20 @@ end
|
||||
-- @param #COMMANDCENTER self
|
||||
-- @param #string Message
|
||||
-- @param Wrapper.Group#GROUP TaskGroup
|
||||
-- @param #sring Name (optional) The name of the Group used as a prefix for the message to the Group. If not provided, there will be nothing shown.
|
||||
function COMMANDCENTER:MessageToGroup( Message, TaskGroup )
|
||||
|
||||
self:GetPositionable():MessageToGroup( Message , 15, TaskGroup, self:GetName() )
|
||||
self:GetPositionable():MessageToGroup( Message, 15, TaskGroup, self:GetName() )
|
||||
|
||||
end
|
||||
|
||||
--- Send a CC message of a specified type to a GROUP.
|
||||
-- @param #COMMANDCENTER self
|
||||
-- @param #string Message
|
||||
-- @param Wrapper.Group#GROUP TaskGroup
|
||||
-- @param Core.Message#MESSAGE.MessageType MessageType The type of the message, resulting in automatic time duration and prefix of the message.
|
||||
function COMMANDCENTER:MessageTypeToGroup( Message, TaskGroup, MessageType )
|
||||
|
||||
self:GetPositionable():MessageTypeToGroup( Message, MessageType, TaskGroup, self:GetName() )
|
||||
|
||||
end
|
||||
|
||||
@@ -447,6 +387,20 @@ function COMMANDCENTER:MessageToCoalition( Message )
|
||||
end
|
||||
|
||||
|
||||
--- Send a CC message of a specified type to the coalition of the CC.
|
||||
-- @param #COMMANDCENTER self
|
||||
-- @param #string Message The message.
|
||||
-- @param Core.Message#MESSAGE.MessageType MessageType The type of the message, resulting in automatic time duration and prefix of the message.
|
||||
function COMMANDCENTER:MessageTypeToCoalition( Message, MessageType )
|
||||
|
||||
local CCCoalition = self:GetPositionable():GetCoalition()
|
||||
--TODO: Fix coalition bug!
|
||||
|
||||
self:GetPositionable():MessageTypeToCoalition( Message, MessageType, CCCoalition )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Report the status of all MISSIONs to a GROUP.
|
||||
-- Each Mission is listed, with an indication how many Tasks are still to be completed.
|
||||
-- @param #COMMANDCENTER self
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
-- ---------------------------------
|
||||
-- Derived DETECTION_MANAGER classes will reports detected units using the method @{DetectionManager#DETECTION_MANAGER.ReportDetected}(). This method implements polymorphic behaviour.
|
||||
--
|
||||
-- The time interval in seconds of the reporting can be changed using the methods @{DetectionManager#DETECTION_MANAGER.SetReportInterval}().
|
||||
-- The time interval in seconds of the reporting can be changed using the methods @{DetectionManager#DETECTION_MANAGER.SetRefreshTimeInterval}().
|
||||
-- To control how long a reporting message is displayed, use @{DetectionManager#DETECTION_MANAGER.SetReportDisplayTime}().
|
||||
-- Derived classes need to implement the method @{DetectionManager#DETECTION_MANAGER.GetReportDisplayTime}() to use the correct display time for displayed messages during a report.
|
||||
--
|
||||
@@ -126,7 +126,7 @@ do -- DETECTION MANAGER
|
||||
|
||||
self:AddTransition( "Started", "Report", "Started" )
|
||||
|
||||
self:SetReportInterval( 30 )
|
||||
self:SetRefreshTimeInterval( 30 )
|
||||
self:SetReportDisplayTime( 25 )
|
||||
|
||||
self:E( { Detection = Detection } )
|
||||
@@ -143,19 +143,19 @@ do -- DETECTION MANAGER
|
||||
|
||||
self:E( "onafterReport" )
|
||||
|
||||
self:__Report( -self._ReportInterval )
|
||||
self:__Report( -self._RefreshTimeInterval )
|
||||
|
||||
self:ProcessDetected( self.Detection )
|
||||
end
|
||||
|
||||
--- Set the reporting time interval.
|
||||
-- @param #DETECTION_MANAGER self
|
||||
-- @param #number ReportInterval The interval in seconds when a report needs to be done.
|
||||
-- @param #number RefreshTimeInterval The interval in seconds when a report needs to be done.
|
||||
-- @return #DETECTION_MANAGER self
|
||||
function DETECTION_MANAGER:SetReportInterval( ReportInterval )
|
||||
function DETECTION_MANAGER:SetRefreshTimeInterval( RefreshTimeInterval )
|
||||
self:F2()
|
||||
|
||||
self._ReportInterval = ReportInterval
|
||||
self._RefreshTimeInterval = RefreshTimeInterval
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -264,14 +264,14 @@ function MISSION:New( CommandCenter, MissionName, MissionPriority, MissionBriefi
|
||||
end
|
||||
|
||||
|
||||
-- FSM function for a MISSION
|
||||
--- FSM function for a MISSION
|
||||
-- @param #MISSION self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
function MISSION:onenterCOMPLETED( From, Event, To )
|
||||
|
||||
self:GetCommandCenter():MessageToCoalition( self:GetName() .. " has been completed! Good job guys!" )
|
||||
self:GetCommandCenter():MessageTypeToCoalition( self:GetName() .. " has been completed! Good job guys!", MESSAGE.Type.Information )
|
||||
end
|
||||
|
||||
--- Gets the mission name.
|
||||
@@ -450,7 +450,7 @@ do -- Group Assignment
|
||||
local MissionGroupName = MissionGroup:GetName()
|
||||
|
||||
self.AssignedGroups[MissionGroupName] = nil
|
||||
self:E( string.format( "Mission %s is unassigned to %s", MissionName, MissionGroupName ) )
|
||||
--self:E( string.format( "Mission %s is unassigned to %s", MissionName, MissionGroupName ) )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -475,7 +475,23 @@ function MISSION:RemoveTaskMenu( Task )
|
||||
end
|
||||
|
||||
|
||||
--- Gets the mission menu for the coalition.
|
||||
--- Gets the root mission menu for the TaskGroup.
|
||||
-- @param #MISSION self
|
||||
-- @return Core.Menu#MENU_COALITION self
|
||||
function MISSION:GetRootMenu( TaskGroup ) -- R2.2
|
||||
|
||||
local CommandCenter = self:GetCommandCenter()
|
||||
local CommandCenterMenu = CommandCenter:GetMenu()
|
||||
|
||||
local MissionName = self:GetName()
|
||||
--local MissionMenu = CommandCenterMenu:GetMenu( MissionName )
|
||||
|
||||
self.MissionMenu = self.MissionMenu or MENU_COALITION:New( self.MissionCoalition, self:GetName(), CommandCenterMenu )
|
||||
|
||||
return self.MissionMenu
|
||||
end
|
||||
|
||||
--- Gets the mission menu for the TaskGroup.
|
||||
-- @param #MISSION self
|
||||
-- @return Core.Menu#MENU_COALITION self
|
||||
function MISSION:GetMenu( TaskGroup ) -- R2.1 -- Changed Menu Structure
|
||||
@@ -486,27 +502,28 @@ function MISSION:GetMenu( TaskGroup ) -- R2.1 -- Changed Menu Structure
|
||||
local MissionName = self:GetName()
|
||||
--local MissionMenu = CommandCenterMenu:GetMenu( MissionName )
|
||||
|
||||
self.MissionMenu = self.MissionMenu or {}
|
||||
self.MissionMenu[TaskGroup] = self.MissionMenu[TaskGroup] or {}
|
||||
self.MissionGroupMenu = self.MissionGroupMenu or {}
|
||||
self.MissionGroupMenu[TaskGroup] = self.MissionGroupMenu[TaskGroup] or {}
|
||||
|
||||
local Menu = self.MissionMenu[TaskGroup]
|
||||
local GroupMenu = self.MissionGroupMenu[TaskGroup]
|
||||
|
||||
Menu.MainMenu = Menu.MainMenu or MENU_GROUP:New( TaskGroup, self:GetName(), CommandCenterMenu )
|
||||
Menu.BriefingMenu = Menu.BriefingMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Mission Briefing", Menu.MainMenu, self.MenuReportBriefing, self, TaskGroup )
|
||||
self.MissionMenu = self.MissionMenu or MENU_COALITION:New( self.MissionCoalition, self:GetName(), CommandCenterMenu )
|
||||
|
||||
GroupMenu.BriefingMenu = GroupMenu.BriefingMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Mission Briefing", self.MissionMenu, self.MenuReportBriefing, self, TaskGroup )
|
||||
|
||||
Menu.TaskReportsMenu = Menu.TaskReportsMenu or MENU_GROUP:New( TaskGroup, "Task Reports", Menu.MainMenu )
|
||||
Menu.ReportTasksMenu = Menu.ReportTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Tasks", Menu.TaskReportsMenu, self.MenuReportTasksSummary, self, TaskGroup )
|
||||
Menu.ReportPlannedTasksMenu = Menu.ReportPlannedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Planned Tasks", Menu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Planned" )
|
||||
Menu.ReportAssignedTasksMenu = Menu.ReportAssignedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Assigned Tasks", Menu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Assigned" )
|
||||
Menu.ReportSuccessTasksMenu = Menu.ReportSuccessTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Successful Tasks", Menu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Success" )
|
||||
Menu.ReportFailedTasksMenu = Menu.ReportFailedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Failed Tasks", Menu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Failed" )
|
||||
Menu.ReportHeldTasksMenu = Menu.ReportHeldTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Held Tasks", Menu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Hold" )
|
||||
GroupMenu.TaskReportsMenu = GroupMenu.TaskReportsMenu or MENU_GROUP:New( TaskGroup, "Task Reports", self.MissionMenu )
|
||||
GroupMenu.ReportTasksMenu = GroupMenu.ReportTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksSummary, self, TaskGroup )
|
||||
GroupMenu.ReportPlannedTasksMenu = GroupMenu.ReportPlannedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Planned Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Planned" )
|
||||
GroupMenu.ReportAssignedTasksMenu = GroupMenu.ReportAssignedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Assigned Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Assigned" )
|
||||
GroupMenu.ReportSuccessTasksMenu = GroupMenu.ReportSuccessTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Successful Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Success" )
|
||||
GroupMenu.ReportFailedTasksMenu = GroupMenu.ReportFailedTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Failed Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Failed" )
|
||||
GroupMenu.ReportHeldTasksMenu = GroupMenu.ReportHeldTasksMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Held Tasks", GroupMenu.TaskReportsMenu, self.MenuReportTasksPerStatus, self, TaskGroup, "Hold" )
|
||||
|
||||
Menu.PlayerReportsMenu = Menu.PlayerReportsMenu or MENU_GROUP:New( TaskGroup, "Statistics Reports", Menu.MainMenu )
|
||||
Menu.ReportMissionHistory = Menu.ReportPlayersHistory or MENU_GROUP_COMMAND:New( TaskGroup, "Report Mission Progress", Menu.PlayerReportsMenu, self.MenuReportPlayersProgress, self, TaskGroup )
|
||||
Menu.ReportPlayersPerTaskMenu = Menu.ReportPlayersPerTaskMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Players per Task", Menu.PlayerReportsMenu, self.MenuReportPlayersPerTask, self, TaskGroup )
|
||||
GroupMenu.PlayerReportsMenu = GroupMenu.PlayerReportsMenu or MENU_GROUP:New( TaskGroup, "Statistics Reports", self.MissionMenu )
|
||||
GroupMenu.ReportMissionHistory = GroupMenu.ReportPlayersHistory or MENU_GROUP_COMMAND:New( TaskGroup, "Report Mission Progress", GroupMenu.PlayerReportsMenu, self.MenuReportPlayersProgress, self, TaskGroup )
|
||||
GroupMenu.ReportPlayersPerTaskMenu = GroupMenu.ReportPlayersPerTaskMenu or MENU_GROUP_COMMAND:New( TaskGroup, "Report Players per Task", GroupMenu.PlayerReportsMenu, self.MenuReportPlayersPerTask, self, TaskGroup )
|
||||
|
||||
return Menu.MainMenu
|
||||
return self.MissionMenu
|
||||
end
|
||||
|
||||
|
||||
@@ -843,8 +860,9 @@ end
|
||||
|
||||
--- Create a summary report of the Mission (one line).
|
||||
-- @param #MISSION self
|
||||
-- @param Wrapper.Group#GROUP ReportGroup
|
||||
-- @return #string
|
||||
function MISSION:ReportSummary()
|
||||
function MISSION:ReportSummary( ReportGroup )
|
||||
|
||||
local Report = REPORT:New()
|
||||
|
||||
@@ -857,9 +875,9 @@ function MISSION:ReportSummary()
|
||||
Report:Add( string.format( '%s - %s - Task Overview Report', Name, Status ) )
|
||||
|
||||
-- Determine how many tasks are remaining.
|
||||
for TaskID, Task in pairs( self:GetTasks() ) do
|
||||
for TaskID, Task in UTILS.spairs( self:GetTasks(), function( t, a, b ) return t[a]:ReportOrder( ReportGroup ) < t[b]:ReportOrder( ReportGroup ) end ) do
|
||||
local Task = Task -- Tasking.Task#TASK
|
||||
Report:Add( "- " .. Task:ReportSummary() )
|
||||
Report:Add( "- " .. Task:ReportSummary( ReportGroup ) )
|
||||
end
|
||||
|
||||
return Report:Text()
|
||||
@@ -870,6 +888,8 @@ end
|
||||
-- @return #string
|
||||
function MISSION:ReportOverview( ReportGroup, TaskStatus )
|
||||
|
||||
self:F( { TaskStatus = TaskStatus } )
|
||||
|
||||
local Report = REPORT:New()
|
||||
|
||||
-- List the name of the mission.
|
||||
@@ -881,12 +901,17 @@ function MISSION:ReportOverview( ReportGroup, TaskStatus )
|
||||
Report:Add( string.format( '%s - %s - %s Tasks Report', Name, Status, TaskStatus ) )
|
||||
|
||||
-- Determine how many tasks are remaining.
|
||||
local TasksRemaining = 0
|
||||
for TaskID, Task in pairs( self:GetTasks() ) do
|
||||
local Tasks = 0
|
||||
for TaskID, Task in UTILS.spairs( self:GetTasks(), function( t, a, b ) return t[a]:ReportOrder( ReportGroup ) < t[b]:ReportOrder( ReportGroup ) end ) do
|
||||
local Task = Task -- Tasking.Task#TASK
|
||||
if Task:Is( TaskStatus ) then
|
||||
Report:Add( string.rep( "-", 140 ) )
|
||||
Report:Add( " - " .. Task:ReportOverview( ReportGroup ) )
|
||||
end
|
||||
Tasks = Tasks + 1
|
||||
if Tasks >= 8 then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return Report:Text()
|
||||
@@ -935,7 +960,7 @@ function MISSION:MenuReportBriefing( ReportGroup )
|
||||
|
||||
local Report = self:ReportBriefing()
|
||||
|
||||
self:GetCommandCenter():MessageToGroup( Report, ReportGroup )
|
||||
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Briefing )
|
||||
end
|
||||
|
||||
|
||||
@@ -945,9 +970,9 @@ end
|
||||
-- @param Wrapper.Group#GROUP ReportGroup
|
||||
function MISSION:MenuReportTasksSummary( ReportGroup )
|
||||
|
||||
local Report = self:ReportSummary()
|
||||
local Report = self:ReportSummary( ReportGroup )
|
||||
|
||||
self:GetCommandCenter():MessageToGroup( Report, ReportGroup )
|
||||
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Overview )
|
||||
end
|
||||
|
||||
|
||||
@@ -960,7 +985,7 @@ function MISSION:MenuReportTasksPerStatus( ReportGroup, TaskStatus )
|
||||
|
||||
local Report = self:ReportOverview( ReportGroup, TaskStatus )
|
||||
|
||||
self:GetCommandCenter():MessageToGroup( Report, ReportGroup )
|
||||
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Overview )
|
||||
end
|
||||
|
||||
|
||||
@@ -970,7 +995,7 @@ function MISSION:MenuReportPlayersPerTask( ReportGroup )
|
||||
|
||||
local Report = self:ReportPlayersPerTask()
|
||||
|
||||
self:GetCommandCenter():MessageToGroup( Report, ReportGroup )
|
||||
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Overview )
|
||||
end
|
||||
|
||||
--- @param #MISSION self
|
||||
@@ -979,7 +1004,7 @@ function MISSION:MenuReportPlayersProgress( ReportGroup )
|
||||
|
||||
local Report = self:ReportPlayersProgress()
|
||||
|
||||
self:GetCommandCenter():MessageToGroup( Report, ReportGroup )
|
||||
self:GetCommandCenter():MessageTypeToGroup( Report, ReportGroup, MESSAGE.Type.Overview )
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -175,28 +175,34 @@ function TASK:New( Mission, SetGroupAssign, TaskName, TaskType, TaskBriefing )
|
||||
--- Goal Handler OnBefore for TASK
|
||||
-- @function [parent=#TASK] OnBeforeGoal
|
||||
-- @param #TASK self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player.
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @return #boolean
|
||||
|
||||
--- Goal Handler OnAfter for TASK
|
||||
-- @function [parent=#TASK] OnAfterGoal
|
||||
-- @param #TASK self
|
||||
-- @param Wrapper.Controllable#CONTROLLABLE Controllable
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player.
|
||||
-- @param #string PlayerName The name of the player.
|
||||
|
||||
--- Goal Trigger for TASK
|
||||
-- @function [parent=#TASK] Goal
|
||||
-- @param #TASK self
|
||||
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player.
|
||||
-- @param #string PlayerName The name of the player.
|
||||
|
||||
--- Goal Asynchronous Trigger for TASK
|
||||
-- @function [parent=#TASK] __Goal
|
||||
-- @param #TASK self
|
||||
-- @param #number Delay
|
||||
-- @param Wrapper.Unit#UNIT PlayerUnit The @{Unit} of the player.
|
||||
-- @param #string PlayerName The name of the player.
|
||||
|
||||
|
||||
|
||||
@@ -272,7 +278,7 @@ function TASK:JoinUnit( PlayerUnit, PlayerGroup )
|
||||
-- Check if the PlayerGroup is already assigned to the Task. If yes, the PlayerGroup is added to the Task.
|
||||
-- If the PlayerGroup is not assigned to the Task, the menu needs to be set. In that case, the PlayerUnit will become the GroupPlayer leader.
|
||||
if self:IsStatePlanned() or self:IsStateReplanned() then
|
||||
self:SetMenuForGroup( PlayerGroup )
|
||||
--self:SetMenuForGroup( PlayerGroup )
|
||||
--self:MessageToGroups( PlayerUnit:GetPlayerName() .. " is planning to join Task " .. self:GetName() )
|
||||
end
|
||||
if self:IsStateAssigned() then
|
||||
@@ -309,7 +315,7 @@ function TASK:AbortGroup( PlayerGroup )
|
||||
self:E( { IsGroupAssigned = IsGroupAssigned } )
|
||||
if IsGroupAssigned then
|
||||
local PlayerName = PlayerGroup:GetUnit(1):GetPlayerName()
|
||||
self:MessageToGroups( PlayerName .. " aborted Task " .. self:GetName() )
|
||||
--self:MessageToGroups( PlayerName .. " aborted Task " .. self:GetName() )
|
||||
self:UnAssignFromGroup( PlayerGroup )
|
||||
--self:Abort()
|
||||
|
||||
@@ -469,7 +475,7 @@ do -- Group Assignment
|
||||
local TaskGroupName = TaskGroup:GetName()
|
||||
|
||||
self.AssignedGroups[TaskGroupName] = nil
|
||||
self:E( string.format( "Task %s is unassigned to %s", TaskName, TaskGroupName ) )
|
||||
--self:E( string.format( "Task %s is unassigned to %s", TaskName, TaskGroupName ) )
|
||||
|
||||
-- Set the group to be assigned at mission level. This allows to decide the menu options on mission level for this group.
|
||||
self:GetMission():ClearGroupAssignment( TaskGroup )
|
||||
@@ -479,9 +485,9 @@ do -- Group Assignment
|
||||
SetAssignedGroups:ForEachGroup(
|
||||
function( AssignedGroup )
|
||||
if self:IsGroupAssigned(AssignedGroup) then
|
||||
self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is unassigned from group %s.", TaskName, TaskGroupName ), AssignedGroup )
|
||||
--self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is unassigned from group %s.", TaskName, TaskGroupName ), AssignedGroup )
|
||||
else
|
||||
self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is unassigned from your group.", TaskName ), AssignedGroup )
|
||||
--self:GetMission():GetCommandCenter():MessageToGroup( string.format( "Task %s is unassigned from your group.", TaskName ), AssignedGroup )
|
||||
end
|
||||
end
|
||||
)
|
||||
@@ -530,8 +536,9 @@ do -- Group Assignment
|
||||
|
||||
--- UnAssign the @{Task} from a @{Group}.
|
||||
-- @param #TASK self
|
||||
-- @param Wrapper.Group#GROUP TaskGroup
|
||||
function TASK:UnAssignFromGroup( TaskGroup )
|
||||
self:F2( { TaskGroup } )
|
||||
self:F2( { TaskGroup = TaskGroup:GetName() } )
|
||||
|
||||
self:ClearGroupAssignment( TaskGroup )
|
||||
|
||||
@@ -539,7 +546,7 @@ do -- Group Assignment
|
||||
for UnitID, UnitData in pairs( TaskUnits ) do
|
||||
local TaskUnit = UnitData -- Wrapper.Unit#UNIT
|
||||
local PlayerName = TaskUnit:GetPlayerName()
|
||||
if PlayerName ~= nil or PlayerName ~= "" then
|
||||
if PlayerName ~= nil and PlayerName ~= "" then -- Only remove units that have players!
|
||||
self:UnAssignFromUnit( TaskUnit )
|
||||
end
|
||||
end
|
||||
@@ -573,7 +580,6 @@ function TASK:AssignToUnit( TaskUnit )
|
||||
|
||||
-- Assign a new FsmUnit to TaskUnit.
|
||||
local FsmUnit = self:SetStateMachine( TaskUnit, FsmTemplate:Copy( TaskUnit, self ) ) -- Core.Fsm#FSM_PROCESS
|
||||
self:E({"Address FsmUnit", tostring( FsmUnit ) } )
|
||||
|
||||
FsmUnit:SetStartState( "Planned" )
|
||||
|
||||
@@ -738,13 +744,16 @@ function TASK:SetPlannedMenuForGroup( TaskGroup, MenuTime )
|
||||
|
||||
--local MissionMenu = Mission:GetMenu( TaskGroup )
|
||||
|
||||
local TaskPlannedMenu = MENU_GROUP:New( TaskGroup, "Planned Tasks", MissionMenu ):SetTime( MenuTime )
|
||||
local TaskTypeMenu = MENU_GROUP:New( TaskGroup, TaskType, TaskPlannedMenu ):SetTime( MenuTime ):SetRemoveParent( true )
|
||||
local TaskTypeMenu = MENU_GROUP:New( TaskGroup, TaskText, TaskTypeMenu ):SetTime( MenuTime ):SetRemoveParent( true )
|
||||
local ReportTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Status" ), TaskTypeMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true )
|
||||
self.MenuPlanned = self.MenuPlanned or {}
|
||||
self.MenuPlanned[TaskGroup] = MENU_GROUP:New( TaskGroup, "Join Planned Task", MissionMenu, Mission.MenuReportTasksPerStatus, Mission, TaskGroup, "Planned" ):SetTime( MenuTime ):SetTag( "Tasking" )
|
||||
local TaskTypeMenu = MENU_GROUP:New( TaskGroup, TaskType, self.MenuPlanned[TaskGroup] ):SetTime( MenuTime ):SetTag( "Tasking" ):SetRemoveParent( true )
|
||||
local TaskTypeMenu = MENU_GROUP:New( TaskGroup, TaskText, TaskTypeMenu ):SetTime( MenuTime ):SetTag( "Tasking" ):SetRemoveParent( true )
|
||||
local ReportTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Status" ), TaskTypeMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ):SetRemoveParent( true )
|
||||
|
||||
if not Mission:IsGroupAssigned( TaskGroup ) then
|
||||
local JoinTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Join Task" ), TaskTypeMenu, self.MenuAssignToGroup, { self = self, TaskGroup = TaskGroup } ):SetTime( MenuTime ):SetRemoveParent( true )
|
||||
self:F( { "Replacing Join Task menu" } )
|
||||
local JoinTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Join Task" ), TaskTypeMenu, self.MenuAssignToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ):SetRemoveParent( true )
|
||||
local MarkTaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Mark Task on Map" ), TaskTypeMenu, self.MenuMarkToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ):SetRemoveParent( true )
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -775,9 +784,10 @@ function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime )
|
||||
-- local MissionMenu = MENU_GROUP:New( TaskGroup, MissionName, CommandCenterMenu ):SetTime( MenuTime )
|
||||
-- local MissionMenu = Mission:GetMenu( TaskGroup )
|
||||
|
||||
local TaskAssignedMenu = MENU_GROUP:New( TaskGroup, string.format( "Assigned Task %s", TaskName ), MissionMenu ):SetTime( MenuTime )
|
||||
local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Status" ), TaskAssignedMenu, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true )
|
||||
local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Abort Group from Task" ), TaskAssignedMenu, self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ):SetRemoveParent( true )
|
||||
self.MenuAssigned = self.MenuAssigned or {}
|
||||
self.MenuAssigned[TaskGroup] = MENU_GROUP:New( TaskGroup, string.format( "Assigned Task %s", TaskName ), MissionMenu ):SetTime( MenuTime ):SetTag( "Tasking" )
|
||||
local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Status" ), self.MenuAssigned[TaskGroup], self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ):SetRemoveParent( true )
|
||||
local TaskMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Abort Group from Task" ), self.MenuAssigned[TaskGroup], self.MenuTaskAbort, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" ):SetRemoveParent( true )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -791,9 +801,7 @@ function TASK:RemoveMenu( MenuTime )
|
||||
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
local TaskGroup = TaskGroup -- Wrapper.Group#GROUP
|
||||
if TaskGroup:IsAlive() and TaskGroup:GetPlayerNames() then
|
||||
self:RefreshMenus( TaskGroup, MenuTime )
|
||||
end
|
||||
self:RefreshMenus( TaskGroup, MenuTime )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -814,15 +822,18 @@ function TASK:RefreshMenus( TaskGroup, MenuTime )
|
||||
local MissionMenu = Mission:GetMenu( TaskGroup )
|
||||
|
||||
local TaskName = self:GetName()
|
||||
local PlannedMenu = MissionMenu:GetMenu( "Planned Tasks" )
|
||||
local AssignedMenu = MissionMenu:GetMenu( string.format( "Assigned Task %s", TaskName ) )
|
||||
self.MenuPlanned = self.MenuPlanned or {}
|
||||
local PlannedMenu = self.MenuPlanned[TaskGroup]
|
||||
|
||||
self.MenuAssigned = self.MenuAssigned or {}
|
||||
local AssignedMenu = self.MenuAssigned[TaskGroup]
|
||||
|
||||
if PlannedMenu then
|
||||
PlannedMenu:Remove( MenuTime )
|
||||
PlannedMenu:Remove( MenuTime , "Tasking")
|
||||
end
|
||||
|
||||
if AssignedMenu then
|
||||
AssignedMenu:Remove( MenuTime )
|
||||
AssignedMenu:Remove( MenuTime, "Tasking" )
|
||||
end
|
||||
|
||||
end
|
||||
@@ -846,16 +857,44 @@ function TASK:RemoveAssignedMenuForGroup( TaskGroup )
|
||||
|
||||
end
|
||||
|
||||
function TASK.MenuAssignToGroup( MenuParam )
|
||||
--- @param #TASK self
|
||||
-- @param Wrapper.Group#GROUP TaskGroup
|
||||
function TASK:MenuAssignToGroup( TaskGroup )
|
||||
|
||||
local self = MenuParam.self
|
||||
local TaskGroup = MenuParam.TaskGroup
|
||||
|
||||
self:E( "Assigned menu selected")
|
||||
self:E( "Join Task menu selected")
|
||||
|
||||
self:AssignToGroup( TaskGroup )
|
||||
end
|
||||
|
||||
--- @param #TASK self
|
||||
-- @param Wrapper.Group#GROUP TaskGroup
|
||||
function TASK:MenuMarkToGroup( TaskGroup )
|
||||
|
||||
self:E( "Mark Task menu selected")
|
||||
|
||||
self:UpdateTaskInfo()
|
||||
|
||||
local Report = REPORT:New():SetIndent( 0 )
|
||||
|
||||
-- List the name of the Task.
|
||||
local Name = self:GetName()
|
||||
Report:Add( "Task " .. Name .. ": " .. self:GetTaskBriefing() .. "\n" )
|
||||
|
||||
for TaskInfoID, TaskInfo in pairs( self.TaskInfo, function( t, a, b ) return t[a].TaskInfoOrder < t[b].TaskInfoOrder end ) do
|
||||
|
||||
local ReportText = self:GetMarkInfo( TaskInfoID, TaskInfo )
|
||||
if ReportText then
|
||||
Report:Add( ReportText )
|
||||
end
|
||||
end
|
||||
|
||||
local TargetCoordinate = self:GetInfo( "Coordinate" ) -- Core.Point#COORDINATE
|
||||
local MarkText = Report:Text( ", " )
|
||||
self:F( { Coordinate = TargetCoordinate, MarkText = MarkText } )
|
||||
TargetCoordinate:MarkToGroup( MarkText, TaskGroup )
|
||||
--Coordinate:MarkToAll( Briefing )
|
||||
end
|
||||
|
||||
--- Report the task status.
|
||||
-- @param #TASK self
|
||||
function TASK:MenuTaskStatus( TaskGroup )
|
||||
@@ -863,7 +902,7 @@ function TASK:MenuTaskStatus( TaskGroup )
|
||||
local ReportText = self:ReportDetails( TaskGroup )
|
||||
|
||||
self:T( ReportText )
|
||||
self:GetMission():GetCommandCenter():MessageToGroup( ReportText, TaskGroup )
|
||||
self:GetMission():GetCommandCenter():MessageTypeToGroup( ReportText, TaskGroup, MESSAGE.Type.Detailed )
|
||||
|
||||
end
|
||||
|
||||
@@ -947,7 +986,7 @@ end
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @return #TASK self
|
||||
function TASK:RemoveStateMachine( TaskUnit )
|
||||
self:F( { TaskUnit, self.Fsm[TaskUnit] ~= nil } )
|
||||
self:F( { TaskUnit = TaskUnit:GetName(), HasFsm = ( self.Fsm[TaskUnit] ~= nil ) } )
|
||||
|
||||
--self:E( self.Fsm )
|
||||
--for TaskUnitT, Fsm in pairs( self.Fsm ) do
|
||||
@@ -956,13 +995,16 @@ function TASK:RemoveStateMachine( TaskUnit )
|
||||
--self.Fsm[TaskUnit] = nil
|
||||
--end
|
||||
|
||||
self.Fsm[TaskUnit]:Remove()
|
||||
self.Fsm[TaskUnit] = nil
|
||||
if self.Fsm[TaskUnit] then
|
||||
self.Fsm[TaskUnit]:Remove()
|
||||
self.Fsm[TaskUnit] = nil
|
||||
end
|
||||
|
||||
collectgarbage()
|
||||
self:E( "Garbage Collected, Processes should be finalized now ...")
|
||||
end
|
||||
|
||||
|
||||
--- Checks if there is a FiniteStateMachine assigned to Task@{Unit} for @{Task}
|
||||
-- @param #TASK self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
@@ -1016,10 +1058,26 @@ end
|
||||
|
||||
--- Sets the Information on the Task
|
||||
-- @param #TASK self
|
||||
-- @param #string TaskInfo
|
||||
function TASK:SetInfo( TaskInfo, TaskInfoText )
|
||||
-- @param #string TaskInfo The key and title of the task information.
|
||||
-- @param #string TaskInfoText The Task info text.
|
||||
-- @param #number TaskInfoOrder The ordering, a number between 0 and 99.
|
||||
function TASK:SetInfo( TaskInfo, TaskInfoText, TaskInfoOrder )
|
||||
|
||||
self.TaskInfo[TaskInfo] = TaskInfoText
|
||||
self.TaskInfo = self.TaskInfo or {}
|
||||
self.TaskInfo[TaskInfo] = self.TaskInfo[TaskInfo] or {}
|
||||
self.TaskInfo[TaskInfo].TaskInfoText = TaskInfoText
|
||||
self.TaskInfo[TaskInfo].TaskInfoOrder = TaskInfoOrder
|
||||
end
|
||||
|
||||
--- Gets the Information of the Task
|
||||
-- @param #TASK self
|
||||
-- @param #string TaskInfo The key and title of the task information.
|
||||
-- @return #string TaskInfoText The Task info text.
|
||||
function TASK:GetInfo( TaskInfo )
|
||||
|
||||
self.TaskInfo = self.TaskInfo or {}
|
||||
self.TaskInfo[TaskInfo] = self.TaskInfo[TaskInfo] or {}
|
||||
return self.TaskInfo[TaskInfo].TaskInfoText
|
||||
end
|
||||
|
||||
--- Gets the Type of the Task
|
||||
@@ -1181,9 +1239,11 @@ end
|
||||
-- @param #string To
|
||||
function TASK:onenterAssigned( From, Event, To, PlayerUnit, PlayerName )
|
||||
|
||||
self:E( { "Task Assigned", self.Dispatcher } )
|
||||
|
||||
|
||||
--- This test is required, because the state transition will be fired also when the state does not change in case of an event.
|
||||
if From ~= "Assigned" then
|
||||
self:E( { From, Event, To, PlayerUnit:GetName(), PlayerName } )
|
||||
|
||||
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " is assigned." )
|
||||
|
||||
-- Set the total Progress to be achieved.
|
||||
@@ -1198,7 +1258,7 @@ function TASK:onenterAssigned( From, Event, To, PlayerUnit, PlayerName )
|
||||
self:GetMission():__Start( 1 )
|
||||
|
||||
-- When the task is assigned, the task goal needs to be checked of the derived classes.
|
||||
self:__Goal( -10 ) -- Polymorphic
|
||||
self:__Goal( -10, PlayerUnit, PlayerName ) -- Polymorphic
|
||||
|
||||
self:SetMenu()
|
||||
end
|
||||
@@ -1239,6 +1299,23 @@ function TASK:onenterAborted( From, Event, To )
|
||||
|
||||
end
|
||||
|
||||
--- FSM function for a TASK
|
||||
-- @param #TASK self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
function TASK:onenterCancelled( From, Event, To )
|
||||
|
||||
self:E( "Task Cancelled" )
|
||||
|
||||
if From ~= "Cancelled" then
|
||||
self:GetMission():GetCommandCenter():MessageToCoalition( "Task " .. self:GetName() .. " has been cancelled! The tactical situation has changed." )
|
||||
self:UnAssignFromGroups()
|
||||
self:SetMenu()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- FSM function for a TASK
|
||||
-- @param #TASK self
|
||||
-- @param #string From
|
||||
@@ -1313,7 +1390,7 @@ function TASK:onbeforeTimeOut( From, Event, To )
|
||||
return false
|
||||
end
|
||||
|
||||
do -- Dispatcher
|
||||
do -- Links
|
||||
|
||||
--- Set dispatcher of a task
|
||||
-- @param #TASK self
|
||||
@@ -1323,6 +1400,19 @@ do -- Dispatcher
|
||||
self.Dispatcher = Dispatcher
|
||||
end
|
||||
|
||||
--- Set detection of a task
|
||||
-- @param #TASK self
|
||||
-- @param Function.Detection#DETECTION_BASE Detection
|
||||
-- @param #number DetectedItemIndex
|
||||
-- @return #TASK
|
||||
function TASK:SetDetection( Detection, DetectedItemIndex )
|
||||
|
||||
self:E({DetectedItemIndex,Detection})
|
||||
|
||||
self.Detection = Detection
|
||||
self.DetectedItemIndex = DetectedItemIndex
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
do -- Reporting
|
||||
@@ -1330,55 +1420,74 @@ do -- Reporting
|
||||
--- Create a summary report of the Task.
|
||||
-- List the Task Name and Status
|
||||
-- @param #TASK self
|
||||
-- @param Wrapper.Group#GROUP ReportGroup
|
||||
-- @return #string
|
||||
function TASK:ReportSummary() --R2.1 fixed report. Now nicely formatted and contains the info required.
|
||||
function TASK:ReportSummary( ReportGroup )
|
||||
|
||||
local Report = REPORT:New()
|
||||
|
||||
-- List the name of the Task.
|
||||
local Name = self:GetName()
|
||||
Report:Add( "Task " .. self:GetName() )
|
||||
|
||||
-- Determine the status of the Task.
|
||||
local Status = "<" .. self:GetState() .. ">"
|
||||
Report:Add( "State: <" .. self:GetState() .. ">" )
|
||||
|
||||
Report:Add( 'Task ' .. Name .. ' - State ' .. Status )
|
||||
|
||||
return Report:Text()
|
||||
if self.TaskInfo["Coordinate"] then
|
||||
local TaskInfoIDText = string.format( "%s: ", "Coordinate" )
|
||||
local TaskCoord = self.TaskInfo["Coordinate"].TaskInfoText -- Core.Point#COORDINATE
|
||||
Report:Add( TaskInfoIDText .. TaskCoord:ToString( ReportGroup, nil, self ) )
|
||||
end
|
||||
|
||||
return Report:Text( ', ' )
|
||||
end
|
||||
|
||||
--- Create an overiew report of the Task.
|
||||
-- List the Task Name and Status
|
||||
-- @param #TASK self
|
||||
-- @return #string
|
||||
function TASK:ReportOverview( ReportGroup ) --R2.1 fixed report. Now nicely formatted and contains the info required.
|
||||
function TASK:ReportOverview( ReportGroup )
|
||||
|
||||
self:UpdateTaskInfo()
|
||||
|
||||
-- List the name of the Task.
|
||||
local Name = self:GetName()
|
||||
local Report = REPORT:New( Name )
|
||||
local TaskName = self:GetName()
|
||||
local Report = REPORT:New()
|
||||
|
||||
local Line = 0
|
||||
local LineReport = REPORT:New()
|
||||
|
||||
-- Determine the status of the Task.
|
||||
local Status = "<" .. self:GetState() .. ">"
|
||||
|
||||
for TaskInfoID, TaskInfo in pairs( self.TaskInfo ) do
|
||||
for TaskInfoID, TaskInfo in UTILS.spairs( self.TaskInfo, function( t, a, b ) return t[a].TaskInfoOrder < t[b].TaskInfoOrder end ) do
|
||||
|
||||
self:F( { TaskInfo = TaskInfo } )
|
||||
|
||||
if Line < math.floor( TaskInfo.TaskInfoOrder / 10 ) then
|
||||
if Line ~= 0 then
|
||||
Report:AddIndent( LineReport:Text( ", " ) )
|
||||
else
|
||||
Report:Add( "Task " .. TaskName .. ", " .. LineReport:Text( ", " ) )
|
||||
end
|
||||
LineReport = REPORT:New()
|
||||
Line = math.floor( TaskInfo.TaskInfoOrder / 10 )
|
||||
end
|
||||
|
||||
local TaskInfoIDText = string.format( "%s: ", TaskInfoID )
|
||||
|
||||
if type(TaskInfo) == "string" then
|
||||
Report:Add( TaskInfoIDText .. TaskInfo )
|
||||
|
||||
if type( TaskInfo.TaskInfoText ) == "string" then
|
||||
LineReport:Add( TaskInfoIDText .. TaskInfo.TaskInfoText )
|
||||
elseif type(TaskInfo) == "table" then
|
||||
if TaskInfoID == "Coordinates" then
|
||||
local FromCoordinate = ReportGroup:GetUnit(1):GetCoordinate()
|
||||
local ToCoordinate = TaskInfo -- Core.Point#COORDINATE
|
||||
if TaskInfoID == "Coordinate" then
|
||||
local ToCoordinate = TaskInfo.TaskInfoText -- Core.Point#COORDINATE
|
||||
--Report:Add( TaskInfoIDText )
|
||||
Report:Add( ToCoordinate:ToString( ReportGroup ) )
|
||||
LineReport:Add( TaskInfoIDText .. ToCoordinate:ToString( ReportGroup, nil, self ) )
|
||||
--Report:AddIndent( ToCoordinate:ToStringBULLS( ReportGroup:GetCoalition() ) )
|
||||
else
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Report:AddIndent( LineReport:Text( ", " ) )
|
||||
|
||||
return Report:Text( ", ")
|
||||
return Report:Text()
|
||||
end
|
||||
|
||||
--- Create a count of the players in the Task.
|
||||
@@ -1430,6 +1539,8 @@ end
|
||||
-- @return #string
|
||||
function TASK:ReportDetails( ReportGroup )
|
||||
|
||||
self:UpdateTaskInfo()
|
||||
|
||||
local Report = REPORT:New():SetIndent( 3 )
|
||||
|
||||
-- List the name of the Task.
|
||||
@@ -1438,6 +1549,8 @@ function TASK:ReportDetails( ReportGroup )
|
||||
-- Determine the status of the Task.
|
||||
local Status = "<" .. self:GetState() .. ">"
|
||||
|
||||
Report:Add( "Task " .. Name .. " - " .. Status .. " - Detailed Report" )
|
||||
|
||||
-- Loop each Unit active in the Task, and find Player Names.
|
||||
local PlayerNames = self:GetPlayerNames()
|
||||
|
||||
@@ -1446,30 +1559,21 @@ function TASK:ReportDetails( ReportGroup )
|
||||
PlayerReport:Add( "Group " .. PlayerGroup:GetCallsign() .. ": " .. PlayerName )
|
||||
end
|
||||
local Players = PlayerReport:Text()
|
||||
|
||||
Report:Add( "Task: " .. Name .. " - " .. Status .. " - Detailed Report" )
|
||||
Report:Add( " - Players:" )
|
||||
Report:AddIndent( Players )
|
||||
|
||||
for TaskInfoID, TaskInfo in pairs( self.TaskInfo ) do
|
||||
if Players ~= "" then
|
||||
Report:Add( " - Players assigned:" )
|
||||
Report:AddIndent( Players )
|
||||
end
|
||||
|
||||
for TaskInfoID, TaskInfo in pairs( self.TaskInfo, function( t, a, b ) return t[a].TaskInfoOrder < t[b].TaskInfoOrder end ) do
|
||||
|
||||
local TaskInfoIDText = string.format( " - %s: ", TaskInfoID )
|
||||
|
||||
if type(TaskInfo) == "string" then
|
||||
Report:Add( TaskInfoIDText .. TaskInfo )
|
||||
elseif type(TaskInfo) == "table" then
|
||||
if TaskInfoID == "Coordinates" then
|
||||
local FromCoordinate = ReportGroup:GetUnit(1):GetCoordinate()
|
||||
local ToCoordinate = TaskInfo -- Core.Point#COORDINATE
|
||||
Report:Add( TaskInfoIDText )
|
||||
Report:AddIndent( ToCoordinate:ToStringBRA( FromCoordinate ) .. ", " .. TaskInfo:ToStringAspect( FromCoordinate ) )
|
||||
Report:AddIndent( ToCoordinate:ToStringBULLS( ReportGroup:GetCoalition() ) )
|
||||
else
|
||||
end
|
||||
local ReportText = self:GetReportDetail( ReportGroup, TaskInfoID, TaskInfo )
|
||||
if ReportText then
|
||||
Report:Add( ReportText )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
return Report:Text()
|
||||
end
|
||||
|
||||
|
||||
287
Moose Development/Moose/Tasking/TaskZoneCapture.lua
Normal file
287
Moose Development/Moose/Tasking/TaskZoneCapture.lua
Normal file
@@ -0,0 +1,287 @@
|
||||
--- **Tasking** - The TASK_Protect models tasks for players to protect or capture specific zones.
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- ### Author: **Sven Van de Velde (FlightControl)**
|
||||
--
|
||||
-- ### Contributions: MillerTime
|
||||
--
|
||||
-- ====
|
||||
--
|
||||
-- @module TaskZoneCapture
|
||||
|
||||
do -- TASK_ZONE_GOAL
|
||||
|
||||
--- The TASK_ZONE_GOAL class
|
||||
-- @type TASK_ZONE_GOAL
|
||||
-- @field Core.ZoneGoal#ZONE_GOAL ZoneGoal
|
||||
-- @extends Tasking.Task#TASK
|
||||
|
||||
--- # TASK_ZONE_GOAL class, extends @{Task#TASK}
|
||||
--
|
||||
-- The TASK_ZONE_GOAL class defines the task to protect or capture a protection zone.
|
||||
-- The TASK_ZONE_GOAL is implemented using a @{Fsm#FSM_TASK}, and has the following statuses:
|
||||
--
|
||||
-- * **None**: Start of the process
|
||||
-- * **Planned**: The A2G task is planned.
|
||||
-- * **Assigned**: The A2G task is assigned to a @{Group#GROUP}.
|
||||
-- * **Success**: The A2G task is successfully completed.
|
||||
-- * **Failed**: The A2G task has failed. This will happen if the player exists the task early, without communicating a possible cancellation to HQ.
|
||||
--
|
||||
-- ## Set the scoring of achievements in an A2G attack.
|
||||
--
|
||||
-- Scoring or penalties can be given in the following circumstances:
|
||||
--
|
||||
-- * @{#TASK_ZONE_GOAL.SetScoreOnDestroy}(): Set a score when a target in scope of the A2G attack, has been destroyed.
|
||||
-- * @{#TASK_ZONE_GOAL.SetScoreOnSuccess}(): Set a score when all the targets in scope of the A2G attack, have been destroyed.
|
||||
-- * @{#TASK_ZONE_GOAL.SetPenaltyOnFailed}(): Set a penalty when the A2G attack has failed.
|
||||
--
|
||||
-- @field #TASK_ZONE_GOAL
|
||||
TASK_ZONE_GOAL = {
|
||||
ClassName = "TASK_ZONE_GOAL",
|
||||
}
|
||||
|
||||
--- Instantiates a new TASK_ZONE_GOAL.
|
||||
-- @param #TASK_ZONE_GOAL self
|
||||
-- @param Tasking.Mission#MISSION Mission
|
||||
-- @param Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned.
|
||||
-- @param #string TaskName The name of the Task.
|
||||
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal
|
||||
-- @return #TASK_ZONE_GOAL self
|
||||
function TASK_ZONE_GOAL:New( Mission, SetGroup, TaskName, ZoneGoal, TaskType, TaskBriefing )
|
||||
local self = BASE:Inherit( self, TASK:New( Mission, SetGroup, TaskName, TaskType, TaskBriefing ) ) -- #TASK_ZONE_GOAL
|
||||
self:F()
|
||||
|
||||
self.ZoneGoal = ZoneGoal
|
||||
self.TaskType = TaskType
|
||||
|
||||
local Fsm = self:GetUnitProcess()
|
||||
|
||||
|
||||
Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "StartMonitoring", Rejected = "Reject" } )
|
||||
|
||||
Fsm:AddTransition( "Assigned", "StartMonitoring", "Monitoring" )
|
||||
Fsm:AddTransition( "Monitoring", "Monitor", "Monitoring", {} )
|
||||
Fsm:AddTransition( "Monitoring", "RouteTo", "Monitoring" )
|
||||
Fsm:AddProcess( "Monitoring", "RouteToZone", ACT_ROUTE_ZONE:New(), {} )
|
||||
|
||||
--Fsm:AddTransition( "Accounted", "DestroyedAll", "Accounted" )
|
||||
--Fsm:AddTransition( "Accounted", "Success", "Success" )
|
||||
Fsm:AddTransition( "Rejected", "Reject", "Aborted" )
|
||||
Fsm:AddTransition( "Failed", "Fail", "Failed" )
|
||||
|
||||
self:SetTargetZone( self.ZoneGoal:GetZone() )
|
||||
|
||||
--- Test
|
||||
-- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task#TASK_ZONE_GOAL Task
|
||||
function Fsm:onafterStartMonitoring( TaskUnit, Task )
|
||||
self:E( { self } )
|
||||
self:__Monitor( 0.1 )
|
||||
self:__RouteTo( 0.1 )
|
||||
end
|
||||
|
||||
--- Monitor Loop
|
||||
-- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task#TASK_ZONE_GOAL Task
|
||||
function Fsm:onafterMonitor( TaskUnit, Task )
|
||||
self:E( { self } )
|
||||
self:__Monitor( 15 )
|
||||
end
|
||||
|
||||
--- Test
|
||||
-- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_A2G#TASK_ZONE_GOAL Task
|
||||
function Fsm:onafterRouteTo( TaskUnit, Task )
|
||||
self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
|
||||
-- Determine the first Unit from the self.TargetSetUnit
|
||||
|
||||
if Task:GetTargetZone( TaskUnit ) then
|
||||
self:__RouteTo( 0.1 )
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
--- @param #TASK_ZONE_GOAL self
|
||||
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal Engine.
|
||||
function TASK_ZONE_GOAL:SetProtect( ZoneGoal )
|
||||
|
||||
self.ZoneGoal = ZoneGoal -- Core.ZoneGoal#ZONE_GOAL
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #TASK_ZONE_GOAL self
|
||||
function TASK_ZONE_GOAL:GetPlannedMenuText()
|
||||
return self:GetStateString() .. " - " .. self:GetTaskName() .. " ( " .. self.ZoneGoal:GetZoneName() .. " )"
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_ZONE_GOAL self
|
||||
-- @param Core.Zone#ZONE_BASE TargetZone The Zone object where the Target is located on the map.
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
function TASK_ZONE_GOAL:SetTargetZone( TargetZone, TaskUnit )
|
||||
|
||||
local ProcessUnit = self:GetUnitProcess( TaskUnit )
|
||||
|
||||
local ActRouteZone = ProcessUnit:GetProcess( "Monitoring", "RouteToZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE
|
||||
ActRouteZone:SetZone( TargetZone )
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_ZONE_GOAL self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @return Core.Zone#ZONE_BASE The Zone object where the Target is located on the map.
|
||||
function TASK_ZONE_GOAL:GetTargetZone( TaskUnit )
|
||||
|
||||
local ProcessUnit = self:GetUnitProcess( TaskUnit )
|
||||
|
||||
local ActRouteZone = ProcessUnit:GetProcess( "Monitoring", "RouteToZone" ) -- Actions.Act_Route#ACT_ROUTE_ZONE
|
||||
return ActRouteZone:GetZone()
|
||||
end
|
||||
|
||||
function TASK_ZONE_GOAL:SetGoalTotal( GoalTotal )
|
||||
|
||||
self.GoalTotal = GoalTotal
|
||||
end
|
||||
|
||||
function TASK_ZONE_GOAL:GetGoalTotal()
|
||||
|
||||
return self.GoalTotal
|
||||
end
|
||||
|
||||
function TASK_ZONE_GOAL:GetMarkInfo( TaskInfoID, TaskInfo )
|
||||
|
||||
if type( TaskInfo.TaskInfoText ) == "string" then
|
||||
return string.format( "%s: %s", TaskInfoID, TaskInfo.TaskInfoText )
|
||||
elseif type( TaskInfo ) == "table" then
|
||||
if TaskInfoID == "Coordinate" then
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function TASK_ZONE_GOAL:GetReportDetail( ReportGroup, TaskInfoID, TaskInfo )
|
||||
|
||||
if type( TaskInfo.TaskInfoText ) == "string" then
|
||||
return string.format( " - %s: %s", TaskInfoID, TaskInfo.TaskInfoText )
|
||||
elseif type(TaskInfo) == "table" then
|
||||
if TaskInfoID == "Coordinate" then
|
||||
local FromCoordinate = ReportGroup:GetUnit(1):GetCoordinate()
|
||||
local ToCoordinate = TaskInfo.TaskInfoText -- Core.Point#COORDINATE
|
||||
return string.format( " - %s: %s", TaskInfoID, ToCoordinate:ToString( ReportGroup:GetUnit( 1 ), nil, self ) )
|
||||
else
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
do -- TASK_ZONE_CAPTURE
|
||||
|
||||
--- The TASK_ZONE_CAPTURE class
|
||||
-- @type TASK_ZONE_CAPTURE
|
||||
-- @field Core.ZoneGoalCoalition#ZONE_GOAL_COALITION ZoneGoal
|
||||
-- @extends #TASK_ZONE_GOAL
|
||||
|
||||
--- # TASK_ZONE_CAPTURE class, extends @{TaskZoneGoal#TASK_ZONE_GOAL}
|
||||
--
|
||||
-- The TASK_ZONE_CAPTURE class defines an Suppression or Extermination of Air Defenses task for a human player to be executed.
|
||||
-- These tasks are important to be executed as they will help to achieve air superiority at the vicinity.
|
||||
--
|
||||
-- The TASK_ZONE_CAPTURE is used by the @{Task_A2G_Dispatcher#TASK_A2G_DISPATCHER} to automatically create SEAD tasks
|
||||
-- based on detected enemy ground targets.
|
||||
--
|
||||
-- @field #TASK_ZONE_CAPTURE
|
||||
TASK_ZONE_CAPTURE = {
|
||||
ClassName = "TASK_ZONE_CAPTURE",
|
||||
}
|
||||
|
||||
|
||||
--- Instantiates a new TASK_ZONE_CAPTURE.
|
||||
-- @param #TASK_ZONE_CAPTURE self
|
||||
-- @param Tasking.Mission#MISSION Mission
|
||||
-- @param Core.Set#SET_GROUP SetGroup The set of groups for which the Task can be assigned.
|
||||
-- @param #string TaskName The name of the Task.
|
||||
-- @param Core.ZoneGoalCoalition#ZONE_GOAL_COALITION ZoneGoalCoalition
|
||||
-- @param #string TaskBriefing The briefing of the task.
|
||||
-- @return #TASK_ZONE_CAPTURE self
|
||||
function TASK_ZONE_CAPTURE:New( Mission, SetGroup, TaskName, ZoneGoalCoalition, TaskBriefing)
|
||||
local self = BASE:Inherit( self, TASK_ZONE_GOAL:New( Mission, SetGroup, TaskName, ZoneGoalCoalition, "CAPTURE", TaskBriefing ) ) -- #TASK_ZONE_CAPTURE
|
||||
self:F()
|
||||
|
||||
Mission:AddTask( self )
|
||||
|
||||
self.TaskCoalition = ZoneGoalCoalition:GetCoalition()
|
||||
self.TaskCoalitionName = ZoneGoalCoalition:GetCoalitionName()
|
||||
self.TaskZoneName = ZoneGoalCoalition:GetZoneName()
|
||||
|
||||
ZoneGoalCoalition:MonitorDestroyedUnits()
|
||||
|
||||
self:SetBriefing(
|
||||
TaskBriefing or
|
||||
"Capture Zone " .. self.TaskZoneName
|
||||
)
|
||||
|
||||
self:UpdateTaskInfo()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Instantiates a new TASK_ZONE_CAPTURE.
|
||||
-- @param #TASK_ZONE_CAPTURE self
|
||||
function TASK_ZONE_CAPTURE:UpdateTaskInfo()
|
||||
|
||||
|
||||
local ZoneCoordinate = self.ZoneGoal:GetZone():GetCoordinate()
|
||||
self:SetInfo( "Coordinate", ZoneCoordinate, 0 )
|
||||
self:SetInfo( "Zone Name", self.ZoneGoal:GetZoneName(), 10 )
|
||||
self:SetInfo( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11 )
|
||||
end
|
||||
|
||||
|
||||
function TASK_ZONE_CAPTURE:ReportOrder( ReportGroup )
|
||||
local Coordinate = self:GetInfo( "Coordinate" )
|
||||
--local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
|
||||
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
|
||||
|
||||
return Distance
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_ZONE_CAPTURE self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
function TASK_ZONE_CAPTURE:OnAfterGoal( From, Event, To, PlayerUnit, PlayerName )
|
||||
|
||||
self:E( { PlayerUnit = PlayerUnit } )
|
||||
|
||||
if self.ZoneGoal then
|
||||
if self.ZoneGoal.Goal:IsAchieved() then
|
||||
self:Success()
|
||||
local TotalContributions = self.ZoneGoal.Goal:GetTotalContributions()
|
||||
local PlayerContributions = self.ZoneGoal.Goal:GetPlayerContributions()
|
||||
self:E( { TotalContributions = TotalContributions, PlayerContributions = PlayerContributions } )
|
||||
for PlayerName, PlayerContribution in pairs( PlayerContributions ) do
|
||||
local Scoring = self:GetScoring()
|
||||
if Scoring then
|
||||
Scoring:_AddMissionGoalScore( self.Mission, PlayerName, "Zone " .. self.ZoneGoal:GetZoneName() .." captured", PlayerContribution * 200 / TotalContributions )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:__Goal( -10, PlayerUnit, PlayerName )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -75,7 +75,7 @@ do -- TASK_A2A
|
||||
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "Engage", "Engaging" )
|
||||
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "HoldAtRendezVous", "HoldingAtRendezVous" )
|
||||
|
||||
Fsm:AddProcess ( "Engaging", "Account", ACT_ACCOUNT_DEADS:New( self.TargetSetUnit, self.TaskType ), {} )
|
||||
Fsm:AddProcess ( "Engaging", "Account", ACT_ACCOUNT_DEADS:New(), {} )
|
||||
Fsm:AddTransition( "Engaging", "RouteToTarget", "Engaging" )
|
||||
Fsm:AddProcess( "Engaging", "RouteToTargetZone", ACT_ROUTE_ZONE:New(), {} )
|
||||
Fsm:AddProcess( "Engaging", "RouteToTargetPoint", ACT_ROUTE_POINT:New(), {} )
|
||||
@@ -277,6 +277,35 @@ do -- TASK_A2A
|
||||
return self.GoalTotal
|
||||
end
|
||||
|
||||
function TASK_A2A:GetMarkInfo( TaskInfoID, TaskInfo )
|
||||
|
||||
if type( TaskInfo.TaskInfoText ) == "string" then
|
||||
if TaskInfoID == "Targets" then
|
||||
else
|
||||
return string.format( "%s: %s", TaskInfoID, TaskInfo.TaskInfoText )
|
||||
end
|
||||
elseif type( TaskInfo ) == "table" then
|
||||
if TaskInfoID == "Coordinate" then
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function TASK_A2A:GetReportDetail( ReportGroup, TaskInfoID, TaskInfo )
|
||||
|
||||
if type( TaskInfo.TaskInfoText ) == "string" then
|
||||
return string.format( "%s: %s", TaskInfoID, TaskInfo.TaskInfoText )
|
||||
elseif type(TaskInfo) == "table" then
|
||||
if TaskInfoID == "Coordinate" then
|
||||
local FromCoordinate = ReportGroup:GetUnit(1):GetCoordinate()
|
||||
local ToCoordinate = TaskInfo.TaskInfoText -- Core.Point#COORDINATE
|
||||
return string.format( " - %s: %s", TaskInfoID, ToCoordinate:ToString( ReportGroup:GetUnit(1), nil, self ) )
|
||||
else
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
@@ -328,16 +357,48 @@ do -- TASK_A2A_INTERCEPT
|
||||
"Intercept incoming intruders.\n"
|
||||
)
|
||||
|
||||
local TargetCoordinate = TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinates", TargetCoordinate )
|
||||
|
||||
self:SetInfo( "Threat", "[" .. string.rep( "■", TargetSetUnit:CalculateThreatLevelA2G() ) .. "]" )
|
||||
local DetectedItemsCount = TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ) )
|
||||
self:UpdateTaskInfo()
|
||||
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
function TASK_A2A_INTERCEPT:UpdateTaskInfo()
|
||||
|
||||
local TargetCoordinate = self.Detection and self.Detection:GetDetectedItemCoordinate( self.DetectedItemIndex ) or self.TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinate", TargetCoordinate, 0 )
|
||||
|
||||
self:SetInfo( "Threat", "[" .. string.rep( "■", self.Detection and self.Detection:GetDetectedItemThreatLevel( self.DetectedItemIndex ) or self.TargetSetUnit:CalculateThreatLevelA2G() ) .. "]", 11 )
|
||||
|
||||
if self.Detection then
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local ReportTypes = REPORT:New()
|
||||
local TargetTypes = {}
|
||||
for TargetUnitName, TargetUnit in pairs( self.TargetSetUnit:GetSet() ) do
|
||||
local TargetType = self.Detection:GetDetectedUnitTypeName( TargetUnit )
|
||||
if not TargetTypes[TargetType] then
|
||||
TargetTypes[TargetType] = TargetType
|
||||
ReportTypes:Add( TargetType )
|
||||
end
|
||||
end
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, ReportTypes:Text( ", " ) ), 10 )
|
||||
else
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = self.TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ), 10 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2A_INTERCEPT self
|
||||
-- @param Wrapper.Group#GROUP ReportGroup
|
||||
function TASK_A2A_INTERCEPT:ReportOrder( ReportGroup )
|
||||
self:F( { TaskInfo = self.TaskInfo } )
|
||||
local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
|
||||
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
|
||||
|
||||
return Distance
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2A_INTERCEPT self
|
||||
@@ -439,7 +500,7 @@ do -- TASK_A2A_SWEEP
|
||||
-- @param #string TaskBriefing The briefing of the task.
|
||||
-- @return #TASK_A2A_SWEEP self
|
||||
function TASK_A2A_SWEEP:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing )
|
||||
local self = BASE:Inherit( self, TASK_A2A:New( Mission, SetGroup, TaskName, TargetSetUnit, "INTERCEPT", TaskBriefing ) ) -- #TASK_A2A_SWEEP
|
||||
local self = BASE:Inherit( self, TASK_A2A:New( Mission, SetGroup, TaskName, TargetSetUnit, "SWEEP", TaskBriefing ) ) -- #TASK_A2A_SWEEP
|
||||
self:F()
|
||||
|
||||
Mission:AddTask( self )
|
||||
@@ -451,17 +512,47 @@ do -- TASK_A2A_SWEEP
|
||||
"Perform a fighter sweep. Incoming intruders were detected and could be hiding at the location.\n"
|
||||
)
|
||||
|
||||
local TargetCoordinate = TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinates", TargetCoordinate )
|
||||
|
||||
self:SetInfo( "Assumed Threat", "[" .. string.rep( "■", TargetSetUnit:CalculateThreatLevelA2G() ) .. "]" )
|
||||
local DetectedItemsCount = TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Lost Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ) )
|
||||
|
||||
self:UpdateTaskInfo()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
function TASK_A2A_SWEEP:UpdateTaskInfo()
|
||||
|
||||
local TargetCoordinate = self.Detection and self.Detection:GetDetectedItemCoordinate( self.DetectedItemIndex ) or self.TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinate", TargetCoordinate, 0 )
|
||||
|
||||
self:SetInfo( "Assumed Threat", "[" .. string.rep( "■", self.Detection and self.Detection:GetDetectedItemThreatLevel( self.DetectedItemIndex ) or self.TargetSetUnit:CalculateThreatLevelA2G() ) .. "]", 11 )
|
||||
|
||||
if self.Detection then
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local ReportTypes = REPORT:New()
|
||||
local TargetTypes = {}
|
||||
for TargetUnitName, TargetUnit in pairs( self.TargetSetUnit:GetSet() ) do
|
||||
local TargetType = self.Detection:GetDetectedUnitTypeName( TargetUnit )
|
||||
if not TargetTypes[TargetType] then
|
||||
TargetTypes[TargetType] = TargetType
|
||||
ReportTypes:Add( TargetType )
|
||||
end
|
||||
end
|
||||
self:SetInfo( "Lost Targets", string.format( "%d of %s", DetectedItemsCount, ReportTypes:Text( ", " ) ), 10 )
|
||||
else
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = self.TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Lost Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ), 10 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function TASK_A2A_SWEEP:ReportOrder( ReportGroup )
|
||||
local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
|
||||
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
|
||||
|
||||
return Distance
|
||||
end
|
||||
|
||||
--- @param #TASK_A2A_SWEEP self
|
||||
function TASK_A2A_SWEEP:onafterGoal( TaskUnit, From, Event, To )
|
||||
local TargetSetUnit = self.TargetSetUnit -- Core.Set#SET_UNIT
|
||||
@@ -570,17 +661,46 @@ do -- TASK_A2A_ENGAGE
|
||||
"Bogeys are nearby! Players close by are ordered to ENGAGE the intruders!\n"
|
||||
)
|
||||
|
||||
local TargetCoordinate = TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinates", TargetCoordinate )
|
||||
|
||||
self:SetInfo( "Threat", "[" .. string.rep( "■", TargetSetUnit:CalculateThreatLevelA2G() ) .. "]" )
|
||||
local DetectedItemsCount = TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ) )
|
||||
self:UpdateTaskInfo()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
function TASK_A2A_ENGAGE:UpdateTaskInfo()
|
||||
|
||||
local TargetCoordinate = self.Detection and self.Detection:GetDetectedItemCoordinate( self.DetectedItemIndex ) or self.TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinate", TargetCoordinate, 0 )
|
||||
|
||||
self:SetInfo( "Threat", "[" .. string.rep( "■", self.Detection and self.Detection:GetDetectedItemThreatLevel( self.DetectedItemIndex ) or self.TargetSetUnit:CalculateThreatLevelA2G() ) .. "]", 11 )
|
||||
|
||||
if self.Detection then
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local ReportTypes = REPORT:New()
|
||||
local TargetTypes = {}
|
||||
for TargetUnitName, TargetUnit in pairs( self.TargetSetUnit:GetSet() ) do
|
||||
local TargetType = self.Detection:GetDetectedUnitTypeName( TargetUnit )
|
||||
if not TargetTypes[TargetType] then
|
||||
TargetTypes[TargetType] = TargetType
|
||||
ReportTypes:Add( TargetType )
|
||||
end
|
||||
end
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, ReportTypes:Text( ", " ) ), 10 )
|
||||
else
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = self.TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ), 10 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function TASK_A2A_ENGAGE:ReportOrder( ReportGroup )
|
||||
local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
|
||||
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
|
||||
|
||||
return Distance
|
||||
end
|
||||
|
||||
--- @param #TASK_A2A_ENGAGE self
|
||||
function TASK_A2A_ENGAGE:onafterGoal( TaskUnit, From, Event, To )
|
||||
local TargetSetUnit = self.TargetSetUnit -- Core.Set#SET_UNIT
|
||||
|
||||
@@ -93,7 +93,7 @@ do -- TASK_A2A_DISPATCHER
|
||||
--
|
||||
-- local EWRDetection = DETECTION_AREAS:New( EWRSet, 6000 )
|
||||
-- EWRDetection:SetFriendliesRange( 10000 )
|
||||
-- EWRDetection:SetDetectionInterval(30)
|
||||
-- EWRDetection:SetRefreshTimeInterval(30)
|
||||
--
|
||||
-- -- Setup the A2A dispatcher, and initialize it.
|
||||
-- A2ADispatcher = TASK_A2A_DISPATCHER:New( Mission, AttackGroups, EWRDetection )
|
||||
@@ -197,7 +197,7 @@ do -- TASK_A2A_DISPATCHER
|
||||
-- TODO: Check detection through radar.
|
||||
self.Detection:FilterCategories( Unit.Category.AIRPLANE, Unit.Category.HELICOPTER )
|
||||
self.Detection:InitDetectRadar( true )
|
||||
self.Detection:SetDetectionInterval( 30 )
|
||||
self.Detection:SetRefreshTimeInterval( 30 )
|
||||
|
||||
self:AddTransition( "Started", "Assign", "Started" )
|
||||
|
||||
@@ -382,9 +382,7 @@ do -- TASK_A2A_DISPATCHER
|
||||
end
|
||||
|
||||
if DetectedItemChanged == true or Remove then
|
||||
--self:E( "Removing Tasking: " .. Task:GetTaskName() )
|
||||
Mission:RemoveTask( Task )
|
||||
self.Tasks[DetectedItemIndex] = nil
|
||||
Task = self:RemoveTask( DetectedItemIndex )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -482,6 +480,11 @@ do -- TASK_A2A_DISPATCHER
|
||||
return PlayersCount, PlayerTypesReport
|
||||
end
|
||||
|
||||
function TASK_A2A_DISPATCHER:RemoveTask( TaskIndex )
|
||||
self.Mission:RemoveTask( self.Tasks[TaskIndex] )
|
||||
self.Tasks[TaskIndex] = nil
|
||||
end
|
||||
|
||||
|
||||
--- Assigns tasks in relation to the detected items to the @{Set#SET_GROUP}.
|
||||
-- @param #TASK_A2A_DISPATCHER self
|
||||
@@ -510,8 +513,7 @@ do -- TASK_A2A_DISPATCHER
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
Mission:GetCommandCenter():MessageToGroup( string.format( "Obsolete A2A task %s for %s removed.", TaskText, Mission:GetName() ), TaskGroup )
|
||||
end
|
||||
Mission:RemoveTask( Task )
|
||||
self.Tasks[TaskIndex] = nil
|
||||
Task = self:RemoveTask( TaskIndex )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -538,21 +540,24 @@ do -- TASK_A2A_DISPATCHER
|
||||
local TargetSetUnit = self:EvaluateENGAGE( DetectedItem ) -- Returns a SetUnit if there are targets to be INTERCEPTed...
|
||||
if TargetSetUnit then
|
||||
Task = TASK_A2A_ENGAGE:New( Mission, self.SetGroup, string.format( "ENGAGE.%03d", DetectedID ), TargetSetUnit )
|
||||
Task:SetDetection( Detection, TaskIndex )
|
||||
else
|
||||
local TargetSetUnit = self:EvaluateINTERCEPT( DetectedItem ) -- Returns a SetUnit if there are targets to be INTERCEPTed...
|
||||
if TargetSetUnit then
|
||||
Task = TASK_A2A_INTERCEPT:New( Mission, self.SetGroup, string.format( "INTERCEPT.%03d", DetectedID ), TargetSetUnit )
|
||||
Task:SetDetection( Detection, TaskIndex )
|
||||
else
|
||||
local TargetSetUnit = self:EvaluateSWEEP( DetectedItem ) -- Returns a SetUnit
|
||||
if TargetSetUnit then
|
||||
Task = TASK_A2A_SWEEP:New( Mission, self.SetGroup, string.format( "SWEEP.%03d", DetectedID ), TargetSetUnit )
|
||||
Task:SetDetection( Detection, TaskIndex )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Task then
|
||||
self.Tasks[TaskIndex] = Task
|
||||
Task:SetTargetZone( DetectedZone, DetectedSet:GetFirst():GetAltitude(), DetectedSet:GetFirst():GetHeading() )
|
||||
Task:SetTargetZone( DetectedZone, DetectedItem.Coordinate.y, DetectedItem.Coordinate.Heading )
|
||||
Task:SetDispatcher( self )
|
||||
Mission:AddTask( Task )
|
||||
|
||||
@@ -565,9 +570,9 @@ do -- TASK_A2A_DISPATCHER
|
||||
|
||||
if Task then
|
||||
local FriendliesCount, FriendliesReport = self:GetFriendliesNearBy( DetectedItem )
|
||||
Task:SetInfo( "Friendlies", string.format( "%d ( %s )", FriendliesCount, FriendliesReport:Text( "," ) ) )
|
||||
Task:SetInfo( "Friendlies", string.format( "%d ( %s )", FriendliesCount, FriendliesReport:Text( "," ) ), 30 )
|
||||
local PlayersCount, PlayersReport = self:GetPlayerFriendliesNearBy( DetectedItem )
|
||||
Task:SetInfo( "Players", string.format( "%d ( %s )", PlayersCount, PlayersReport:Text( "," ) ) )
|
||||
Task:SetInfo( "Players", string.format( "%d ( %s )", PlayersCount, PlayersReport:Text( "," ) ), 31 )
|
||||
end
|
||||
|
||||
-- OK, so the tasking has been done, now delete the changes reported for the area.
|
||||
|
||||
@@ -75,7 +75,7 @@ do -- TASK_A2G
|
||||
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "Engage", "Engaging" )
|
||||
Fsm:AddTransition( { "ArrivedAtRendezVous", "HoldingAtRendezVous" }, "HoldAtRendezVous", "HoldingAtRendezVous" )
|
||||
|
||||
Fsm:AddProcess ( "Engaging", "Account", ACT_ACCOUNT_DEADS:New( self.TargetSetUnit, self.TaskType ), {} )
|
||||
Fsm:AddProcess ( "Engaging", "Account", ACT_ACCOUNT_DEADS:New(), {} )
|
||||
Fsm:AddTransition( "Engaging", "RouteToTarget", "Engaging" )
|
||||
Fsm:AddProcess( "Engaging", "RouteToTargetZone", ACT_ROUTE_ZONE:New(), {} )
|
||||
Fsm:AddProcess( "Engaging", "RouteToTargetPoint", ACT_ROUTE_POINT:New(), {} )
|
||||
@@ -141,9 +141,9 @@ do -- TASK_A2G
|
||||
else
|
||||
local TargetUnit = Task.TargetSetUnit:GetFirst() -- Wrapper.Unit#UNIT
|
||||
if TargetUnit then
|
||||
local Coordinate = TargetUnit:GetCoordinate()
|
||||
local Coordinate = TargetUnit:GetPointVec3()
|
||||
self:T( { TargetCoordinate = Coordinate, Coordinate:GetX(), Coordinate:GetY(), Coordinate:GetZ() } )
|
||||
Task:SetTargetCoordinate( TargetUnit:GetCoordinate(), TaskUnit )
|
||||
Task:SetTargetCoordinate( Coordinate, TaskUnit )
|
||||
end
|
||||
self:__RouteToTargetPoint( 0.1 )
|
||||
end
|
||||
@@ -165,6 +165,15 @@ do -- TASK_A2G
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
--- @param #TASK_A2G self
|
||||
-- @param Core.Set#SET_UNIT TargetSetUnit The set of targets.
|
||||
function TASK_A2G:SetTargetSetUnit( TargetSetUnit )
|
||||
|
||||
self.TargetSetUnit = TargetSetUnit
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #TASK_A2G self
|
||||
function TASK_A2G:GetPlannedMenuText()
|
||||
@@ -276,6 +285,36 @@ do -- TASK_A2G
|
||||
|
||||
return self.GoalTotal
|
||||
end
|
||||
|
||||
function TASK_A2G:GetMarkInfo( TaskInfoID, TaskInfo )
|
||||
|
||||
if type( TaskInfo.TaskInfoText ) == "string" then
|
||||
if TaskInfoID == "Targets" then
|
||||
else
|
||||
return string.format( "%s: %s", TaskInfoID, TaskInfo.TaskInfoText )
|
||||
end
|
||||
elseif type( TaskInfo ) == "table" then
|
||||
if TaskInfoID == "Coordinate" then
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
function TASK_A2G:GetReportDetail( ReportGroup, TaskInfoID, TaskInfo )
|
||||
|
||||
if type( TaskInfo.TaskInfoText ) == "string" then
|
||||
return string.format( "%s: %s", TaskInfoID, TaskInfo.TaskInfoText )
|
||||
elseif type(TaskInfo) == "table" then
|
||||
if TaskInfoID == "Coordinate" then
|
||||
local FromCoordinate = ReportGroup:GetUnit(1):GetCoordinate()
|
||||
local ToCoordinate = TaskInfo.TaskInfoText -- Core.Point#COORDINATE
|
||||
return string.format( " - %s: %s", TaskInfoID, ToCoordinate:ToString( ReportGroup:GetUnit(1), nil, self ) )
|
||||
else
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -308,7 +347,7 @@ do -- TASK_A2G_SEAD
|
||||
-- @param Core.Set#SET_UNIT TargetSetUnit
|
||||
-- @param #string TaskBriefing The briefing of the task.
|
||||
-- @return #TASK_A2G_SEAD self
|
||||
function TASK_A2G_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing )
|
||||
function TASK_A2G_SEAD:New( Mission, SetGroup, TaskName, TargetSetUnit, TaskBriefing)
|
||||
local self = BASE:Inherit( self, TASK_A2G:New( Mission, SetGroup, TaskName, TargetSetUnit, "SEAD", TaskBriefing ) ) -- #TASK_A2G_SEAD
|
||||
self:F()
|
||||
|
||||
@@ -316,20 +355,55 @@ do -- TASK_A2G_SEAD
|
||||
|
||||
self:SetBriefing(
|
||||
TaskBriefing or
|
||||
"Execute a Suppression of Enemy Air Defenses.\n"
|
||||
"Execute a Suppression of Enemy Air Defenses."
|
||||
)
|
||||
|
||||
local TargetCoordinate = TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinates", TargetCoordinate )
|
||||
|
||||
self:SetInfo( "Threat", "[" .. string.rep( "■", TargetSetUnit:CalculateThreatLevelA2G() ) .. "]" )
|
||||
local DetectedItemsCount = TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ) )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function TASK_A2G_SEAD:UpdateTaskInfo()
|
||||
|
||||
|
||||
local TargetCoordinate = self.Detection and self.Detection:GetDetectedItemCoordinate( self.DetectedItemIndex ) or self.TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinate", TargetCoordinate, 0 )
|
||||
|
||||
local ThreatLevel, ThreatText
|
||||
if self.Detection then
|
||||
ThreatLevel, ThreatText = self.Detection:GetDetectedItemThreatLevel( self.DetectedItemIndex )
|
||||
else
|
||||
ThreatLevel, ThreatText = self.TargetSetUnit:CalculateThreatLevelA2G()
|
||||
end
|
||||
self:SetInfo( "Threat", ThreatText .. " [" .. string.rep( "■", ThreatLevel ) .. "]", 11 )
|
||||
|
||||
if self.Detection then
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local ReportTypes = REPORT:New()
|
||||
local TargetTypes = {}
|
||||
for TargetUnitName, TargetUnit in pairs( self.TargetSetUnit:GetSet() ) do
|
||||
local TargetType = self.Detection:GetDetectedUnitTypeName( TargetUnit )
|
||||
if not TargetTypes[TargetType] then
|
||||
TargetTypes[TargetType] = TargetType
|
||||
ReportTypes:Add( TargetType )
|
||||
end
|
||||
end
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, ReportTypes:Text( ", " ) ), 10 )
|
||||
else
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = self.TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ), 10 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function TASK_A2G_SEAD:ReportOrder( ReportGroup )
|
||||
local Coordinate = self:GetInfo( "Coordinate" )
|
||||
--local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
|
||||
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
|
||||
|
||||
return Distance
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2G_SEAD self
|
||||
function TASK_A2G_SEAD:onafterGoal( TaskUnit, From, Event, To )
|
||||
local TargetSetUnit = self.TargetSetUnit -- Core.Set#SET_UNIT
|
||||
@@ -341,7 +415,7 @@ do -- TASK_A2G_SEAD
|
||||
self:__Goal( -10 )
|
||||
end
|
||||
|
||||
--- Set a score when a target in scope of the A2A attack, has been destroyed .
|
||||
--- Set a score when a target in scope of the A2G attack, has been destroyed .
|
||||
-- @param #TASK_A2G_SEAD self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @param #number Score The score in points to be granted when task process has been achieved.
|
||||
@@ -357,7 +431,7 @@ do -- TASK_A2G_SEAD
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a score when all the targets in scope of the A2A attack, have been destroyed.
|
||||
--- Set a score when all the targets in scope of the A2G attack, have been destroyed.
|
||||
-- @param #TASK_A2G_SEAD self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @param #number Score The score in points.
|
||||
@@ -373,7 +447,7 @@ do -- TASK_A2G_SEAD
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a penalty when the A2A attack has failed.
|
||||
--- Set a penalty when the A2G attack has failed.
|
||||
-- @param #TASK_A2G_SEAD self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @param #number Penalty The penalty in points, must be a negative value!
|
||||
@@ -429,19 +503,66 @@ do -- TASK_A2G_BAI
|
||||
|
||||
self:SetBriefing(
|
||||
TaskBriefing or
|
||||
"Execute a Battlefield Air Interdiction of a group of enemy targets.\n"
|
||||
"Execute a Battlefield Air Interdiction of a group of enemy targets."
|
||||
)
|
||||
|
||||
local TargetCoordinate = TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinates", TargetCoordinate )
|
||||
|
||||
self:SetInfo( "Threat", "[" .. string.rep( "■", TargetSetUnit:CalculateThreatLevelA2G() ) .. "]" )
|
||||
local DetectedItemsCount = TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ) )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
function TASK_A2G_BAI:UpdateTaskInfo()
|
||||
|
||||
self:E({self.Detection, self.DetectedItemIndex})
|
||||
|
||||
local TargetCoordinate = self.Detection and self.Detection:GetDetectedItemCoordinate( self.DetectedItemIndex ) or self.TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinate", TargetCoordinate, 0 )
|
||||
|
||||
local ThreatLevel, ThreatText
|
||||
if self.Detection then
|
||||
ThreatLevel, ThreatText = self.Detection:GetDetectedItemThreatLevel( self.DetectedItemIndex )
|
||||
else
|
||||
ThreatLevel, ThreatText = self.TargetSetUnit:CalculateThreatLevelA2G()
|
||||
end
|
||||
self:SetInfo( "Threat", ThreatText .. " [" .. string.rep( "■", ThreatLevel ) .. "]", 11 )
|
||||
|
||||
if self.Detection then
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local ReportTypes = REPORT:New()
|
||||
local TargetTypes = {}
|
||||
for TargetUnitName, TargetUnit in pairs( self.TargetSetUnit:GetSet() ) do
|
||||
local TargetType = self.Detection:GetDetectedUnitTypeName( TargetUnit )
|
||||
if not TargetTypes[TargetType] then
|
||||
TargetTypes[TargetType] = TargetType
|
||||
ReportTypes:Add( TargetType )
|
||||
end
|
||||
end
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, ReportTypes:Text( ", " ) ), 10 )
|
||||
else
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = self.TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ), 10 )
|
||||
end
|
||||
|
||||
local TargetCoordinate = self:GetInfo( "Coordinate" ) -- Core.Point#COORDINATE
|
||||
|
||||
local Velocity = self.TargetSetUnit:GetVelocityVec3()
|
||||
local Heading = self.TargetSetUnit:GetHeading()
|
||||
|
||||
TargetCoordinate:SetHeading( Heading )
|
||||
TargetCoordinate:SetVelocity( Velocity )
|
||||
|
||||
self:SetInfo( "Position", "Targets are" .. TargetCoordinate:GetMovingText() .. ".", 12 )
|
||||
|
||||
end
|
||||
|
||||
|
||||
function TASK_A2G_BAI:ReportOrder( ReportGroup )
|
||||
local Coordinate = self:GetInfo( "Coordinate" )
|
||||
--local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
|
||||
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
|
||||
|
||||
return Distance
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2G_BAI self
|
||||
function TASK_A2G_BAI:onafterGoal( TaskUnit, From, Event, To )
|
||||
@@ -454,7 +575,7 @@ do -- TASK_A2G_BAI
|
||||
self:__Goal( -10 )
|
||||
end
|
||||
|
||||
--- Set a score when a target in scope of the A2A attack, has been destroyed .
|
||||
--- Set a score when a target in scope of the A2G attack, has been destroyed .
|
||||
-- @param #TASK_A2G_BAI self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @param #number Score The score in points to be granted when task process has been achieved.
|
||||
@@ -470,7 +591,7 @@ do -- TASK_A2G_BAI
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a score when all the targets in scope of the A2A attack, have been destroyed.
|
||||
--- Set a score when all the targets in scope of the A2G attack, have been destroyed.
|
||||
-- @param #TASK_A2G_BAI self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @param #number Score The score in points.
|
||||
@@ -486,7 +607,7 @@ do -- TASK_A2G_BAI
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a penalty when the A2A attack has failed.
|
||||
--- Set a penalty when the A2G attack has failed.
|
||||
-- @param #TASK_A2G_BAI self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @param #number Penalty The penalty in points, must be a negative value!
|
||||
@@ -541,20 +662,56 @@ do -- TASK_A2G_CAS
|
||||
|
||||
self:SetBriefing(
|
||||
TaskBriefing or
|
||||
"Execute a Close Air Support for a group of enemy targets.\n" ..
|
||||
"Beware of friendlies at the vicinity!\n"
|
||||
"Execute a Close Air Support for a group of enemy targets. " ..
|
||||
"Beware of friendlies at the vicinity! "
|
||||
)
|
||||
|
||||
local TargetCoordinate = TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinates", TargetCoordinate )
|
||||
|
||||
self:SetInfo( "Threat", "[" .. string.rep( "■", TargetSetUnit:CalculateThreatLevelA2G() ) .. "]" )
|
||||
local DetectedItemsCount = TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ) )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function TASK_A2G_CAS:UpdateTaskInfo()
|
||||
|
||||
local TargetCoordinate = ( self.Detection and self.Detection:GetDetectedItemCoordinate( self.DetectedItemIndex ) ) or self.TargetSetUnit:GetFirst():GetCoordinate()
|
||||
self:SetInfo( "Coordinate", TargetCoordinate, 0 )
|
||||
|
||||
local ThreatLevel, ThreatText
|
||||
if self.Detection then
|
||||
ThreatLevel, ThreatText = self.Detection:GetDetectedItemThreatLevel( self.DetectedItemIndex )
|
||||
else
|
||||
ThreatLevel, ThreatText = self.TargetSetUnit:CalculateThreatLevelA2G()
|
||||
end
|
||||
self:SetInfo( "Threat", ThreatText .. " [" .. string.rep( "■", ThreatLevel ) .. "]", 11 )
|
||||
|
||||
if self.Detection then
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local ReportTypes = REPORT:New()
|
||||
local TargetTypes = {}
|
||||
for TargetUnitName, TargetUnit in pairs( self.TargetSetUnit:GetSet() ) do
|
||||
local TargetType = self.Detection:GetDetectedUnitTypeName( TargetUnit )
|
||||
if not TargetTypes[TargetType] then
|
||||
TargetTypes[TargetType] = TargetType
|
||||
ReportTypes:Add( TargetType )
|
||||
end
|
||||
end
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, ReportTypes:Text( ", " ) ), 10 )
|
||||
else
|
||||
local DetectedItemsCount = self.TargetSetUnit:Count()
|
||||
local DetectedItemsTypes = self.TargetSetUnit:GetTypeNames()
|
||||
self:SetInfo( "Targets", string.format( "%d of %s", DetectedItemsCount, DetectedItemsTypes ), 10 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param #TASK_A2G_CAS self
|
||||
function TASK_A2G_CAS:ReportOrder( ReportGroup )
|
||||
|
||||
local Coordinate = self:GetInfo( "Coordinate" )
|
||||
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
|
||||
|
||||
return Distance
|
||||
end
|
||||
|
||||
|
||||
--- @param #TASK_A2G_CAS self
|
||||
function TASK_A2G_CAS:onafterGoal( TaskUnit, From, Event, To )
|
||||
@@ -567,7 +724,7 @@ do -- TASK_A2G_CAS
|
||||
self:__Goal( -10 )
|
||||
end
|
||||
|
||||
--- Set a score when a target in scope of the A2A attack, has been destroyed .
|
||||
--- Set a score when a target in scope of the A2G attack, has been destroyed .
|
||||
-- @param #TASK_A2G_CAS self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @param #number Score The score in points to be granted when task process has been achieved.
|
||||
@@ -583,7 +740,7 @@ do -- TASK_A2G_CAS
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a score when all the targets in scope of the A2A attack, have been destroyed.
|
||||
--- Set a score when all the targets in scope of the A2G attack, have been destroyed.
|
||||
-- @param #TASK_A2G_CAS self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @param #number Score The score in points.
|
||||
@@ -599,7 +756,7 @@ do -- TASK_A2G_CAS
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set a penalty when the A2A attack has failed.
|
||||
--- Set a penalty when the A2G attack has failed.
|
||||
-- @param #TASK_A2G_CAS self
|
||||
-- @param #string PlayerName The name of the player.
|
||||
-- @param #number Penalty The penalty in points, must be a negative value!
|
||||
|
||||
@@ -59,6 +59,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
self.Mission = Mission
|
||||
|
||||
self.Detection:FilterCategories( Unit.Category.GROUND_UNIT, Unit.Category.SHIP )
|
||||
self.Detection:FilterFriendliesCategory( Unit.Category.GROUND_UNIT )
|
||||
|
||||
self:AddTransition( "Started", "Assign", "Started" )
|
||||
|
||||
@@ -81,7 +82,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
--- Creates a SEAD task when there are targets for it.
|
||||
-- @param #TASK_A2G_DISPATCHER self
|
||||
-- @param Functional.Detection#DETECTION_AREAS.DetectedItem DetectedItem
|
||||
-- @return Set#SET_UNIT TargetSetUnit: The target set of units.
|
||||
-- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units.
|
||||
-- @return #nil If there are no targets to be set.
|
||||
function TASK_A2G_DISPATCHER:EvaluateSEAD( DetectedItem )
|
||||
self:F( { DetectedItem.ItemID } )
|
||||
@@ -109,7 +110,8 @@ do -- TASK_A2G_DISPATCHER
|
||||
--- Creates a CAS task when there are targets for it.
|
||||
-- @param #TASK_A2G_DISPATCHER self
|
||||
-- @param Functional.Detection#DETECTION_AREAS.DetectedItem DetectedItem
|
||||
-- @return Tasking.Task#TASK
|
||||
-- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units.
|
||||
-- @return #nil If there are no targets to be set.
|
||||
function TASK_A2G_DISPATCHER:EvaluateCAS( DetectedItem )
|
||||
self:F( { DetectedItem.ItemID } )
|
||||
|
||||
@@ -120,8 +122,9 @@ do -- TASK_A2G_DISPATCHER
|
||||
-- Determine if the set has radar targets. If it does, construct a SEAD task.
|
||||
local GroundUnitCount = DetectedSet:HasGroundUnits()
|
||||
local FriendliesNearBy = self.Detection:IsFriendliesNearBy( DetectedItem )
|
||||
local RadarCount = DetectedSet:HasSEAD()
|
||||
|
||||
if GroundUnitCount > 0 and FriendliesNearBy == true then
|
||||
if RadarCount == 0 and GroundUnitCount > 0 and FriendliesNearBy == true then
|
||||
|
||||
-- Copy the Set
|
||||
local TargetSetUnit = SET_UNIT:New()
|
||||
@@ -137,7 +140,8 @@ do -- TASK_A2G_DISPATCHER
|
||||
--- Creates a BAI task when there are targets for it.
|
||||
-- @param #TASK_A2G_DISPATCHER self
|
||||
-- @param Functional.Detection#DETECTION_AREAS.DetectedItem DetectedItem
|
||||
-- @return Tasking.Task#TASK
|
||||
-- @return Core.Set#SET_UNIT TargetSetUnit: The target set of units.
|
||||
-- @return #nil If there are no targets to be set.
|
||||
function TASK_A2G_DISPATCHER:EvaluateBAI( DetectedItem, FriendlyCoalition )
|
||||
self:F( { DetectedItem.ItemID } )
|
||||
|
||||
@@ -148,8 +152,9 @@ do -- TASK_A2G_DISPATCHER
|
||||
-- Determine if the set has radar targets. If it does, construct a SEAD task.
|
||||
local GroundUnitCount = DetectedSet:HasGroundUnits()
|
||||
local FriendliesNearBy = self.Detection:IsFriendliesNearBy( DetectedItem )
|
||||
local RadarCount = DetectedSet:HasSEAD()
|
||||
|
||||
if GroundUnitCount > 0 and FriendliesNearBy == false then
|
||||
if RadarCount == 0 and GroundUnitCount > 0 and FriendliesNearBy == false then
|
||||
|
||||
-- Copy the Set
|
||||
local TargetSetUnit = SET_UNIT:New()
|
||||
@@ -162,6 +167,12 @@ do -- TASK_A2G_DISPATCHER
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
function TASK_A2G_DISPATCHER:RemoveTask( TaskIndex )
|
||||
self.Mission:RemoveTask( self.Tasks[TaskIndex] )
|
||||
self.Tasks[TaskIndex] = nil
|
||||
end
|
||||
|
||||
--- Evaluates the removal of the Task from the Mission.
|
||||
-- Can only occur when the DetectedItem is Changed AND the state of the Task is "Planned".
|
||||
-- @param #TASK_A2G_DISPATCHER self
|
||||
@@ -173,10 +184,9 @@ do -- TASK_A2G_DISPATCHER
|
||||
function TASK_A2G_DISPATCHER:EvaluateRemoveTask( Mission, Task, TaskIndex, DetectedItemChanged )
|
||||
|
||||
if Task then
|
||||
if Task:IsStatePlanned() and DetectedItemChanged == true then
|
||||
if ( Task:IsStatePlanned() and DetectedItemChanged == true ) or Task:IsStateCancelled() then
|
||||
--self:E( "Removing Tasking: " .. Task:GetTaskName() )
|
||||
Mission:RemoveTask( Task )
|
||||
self.Tasks[TaskIndex] = nil
|
||||
self:RemoveTask( TaskIndex )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -211,6 +221,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
Mission:GetCommandCenter():MessageToGroup( string.format( "Obsolete A2G task %s for %s removed.", TaskText, Mission:GetName() ), TaskGroup )
|
||||
end
|
||||
Task = self:RemoveTask( TaskIndex )
|
||||
Mission:RemoveTask( Task )
|
||||
self.Tasks[TaskIndex] = nil
|
||||
end
|
||||
@@ -224,20 +235,119 @@ do -- TASK_A2G_DISPATCHER
|
||||
local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT
|
||||
local DetectedZone = DetectedItem.Zone
|
||||
--self:E( { "Targets in DetectedItem", DetectedItem.ItemID, DetectedSet:Count(), tostring( DetectedItem ) } )
|
||||
DetectedSet:Flush()
|
||||
--DetectedSet:Flush()
|
||||
|
||||
local DetectedItemID = DetectedItem.ID
|
||||
local TaskIndex = DetectedItem.Index
|
||||
local DetectedItemChanged = DetectedItem.Changed
|
||||
|
||||
local Task = self.Tasks[TaskIndex]
|
||||
Task = self:EvaluateRemoveTask( Mission, Task, TaskIndex, DetectedItemChanged ) -- Task will be removed if it is planned and changed.
|
||||
self:E( { DetectedItemChanged = DetectedItemChanged, DetectedItemID = DetectedItemID, TaskIndex = TaskIndex } )
|
||||
|
||||
local Task = self.Tasks[TaskIndex] -- Tasking.Task_A2G#TASK_A2G
|
||||
|
||||
if Task then
|
||||
-- If there is a Task and the task was assigned, then we check if the task was changed ... If it was, we need to reevaluate the targets.
|
||||
if Task:IsStateAssigned() then
|
||||
if DetectedItemChanged == true then -- The detection has changed, thus a new TargetSet is to be evaluated and set
|
||||
local TargetsReport = REPORT:New()
|
||||
local TargetSetUnit = self:EvaluateSEAD( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed...
|
||||
if TargetSetUnit then
|
||||
if Task:IsInstanceOf( TASK_A2G_SEAD ) then
|
||||
Task:SetTargetSetUnit( TargetSetUnit )
|
||||
Task:UpdateTaskInfo()
|
||||
TargetsReport:Add( Detection:GetChangeText( DetectedItem ) )
|
||||
else
|
||||
Task:Cancel()
|
||||
end
|
||||
else
|
||||
local TargetSetUnit = self:EvaluateCAS( DetectedItem ) -- Returns a SetUnit if there are targets to be CASed...
|
||||
if TargetSetUnit then
|
||||
if Task:IsInstanceOf( TASK_A2G_CAS ) then
|
||||
Task:SetTargetSetUnit( TargetSetUnit )
|
||||
Task:SetDetection( Detection, TaskIndex )
|
||||
Task:UpdateTaskInfo()
|
||||
TargetsReport:Add( Detection:GetChangeText( DetectedItem ) )
|
||||
else
|
||||
Task:Cancel()
|
||||
Task = self:RemoveTask( TaskIndex )
|
||||
end
|
||||
else
|
||||
local TargetSetUnit = self:EvaluateBAI( DetectedItem ) -- Returns a SetUnit if there are targets to be BAIed...
|
||||
if TargetSetUnit then
|
||||
if Task:IsInstanceOf( TASK_A2G_BAI ) then
|
||||
Task:SetTargetSetUnit( TargetSetUnit )
|
||||
Task:SetDetection( Detection, TaskIndex )
|
||||
Task:UpdateTaskInfo()
|
||||
TargetsReport:Add( Detection:GetChangeText( DetectedItem ) )
|
||||
else
|
||||
Task:Cancel()
|
||||
Task = self:RemoveTask( TaskIndex )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Now we send to each group the changes, if any.
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
local TargetsText = TargetsReport:Text(", ")
|
||||
if ( Mission:IsGroupAssigned(TaskGroup) ) and TargetsText ~= "" then
|
||||
Mission:GetCommandCenter():MessageToGroup( string.format( "Task %s has change of targets:\n %s", Task:GetName(), TargetsText ), TaskGroup )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Task then
|
||||
if Task:IsStatePlanned() then
|
||||
if DetectedItemChanged == true then -- The detection has changed, thus a new TargetSet is to be evaluated and set
|
||||
if Task:IsInstanceOf( TASK_A2G_SEAD ) then
|
||||
local TargetSetUnit = self:EvaluateSEAD( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed...
|
||||
if TargetSetUnit then
|
||||
Task:SetTargetSetUnit( TargetSetUnit )
|
||||
Task:UpdateTaskInfo()
|
||||
else
|
||||
Task:Cancel()
|
||||
Task = self:RemoveTask( TaskIndex )
|
||||
end
|
||||
else
|
||||
if Task:IsInstanceOf( TASK_A2G_CAS ) then
|
||||
local TargetSetUnit = self:EvaluateCAS( DetectedItem ) -- Returns a SetUnit if there are targets to be CASed...
|
||||
if TargetSetUnit then
|
||||
Task:SetTargetSetUnit( TargetSetUnit )
|
||||
Task:SetDetection( Detection, TaskIndex )
|
||||
Task:UpdateTaskInfo()
|
||||
else
|
||||
Task:Cancel()
|
||||
Task = self:RemoveTask( TaskIndex )
|
||||
end
|
||||
else
|
||||
if Task:IsInstanceOf( TASK_A2G_BAI ) then
|
||||
local TargetSetUnit = self:EvaluateBAI( DetectedItem ) -- Returns a SetUnit if there are targets to be BAIed...
|
||||
if TargetSetUnit then
|
||||
Task:SetTargetSetUnit( TargetSetUnit )
|
||||
Task:SetDetection( Detection, TaskIndex )
|
||||
Task:UpdateTaskInfo()
|
||||
else
|
||||
Task:Cancel()
|
||||
Task = self:RemoveTask( TaskIndex )
|
||||
end
|
||||
else
|
||||
Task:Cancel()
|
||||
Task = self:RemoveTask( TaskIndex )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Evaluate SEAD
|
||||
if not Task then
|
||||
local TargetSetUnit = self:EvaluateSEAD( DetectedItem ) -- Returns a SetUnit if there are targets to be SEADed...
|
||||
if TargetSetUnit then
|
||||
Task = TASK_A2G_SEAD:New( Mission, self.SetGroup, string.format( "SEAD.%03d", DetectedItemID ), TargetSetUnit )
|
||||
Task:SetDetection( Detection, TaskIndex )
|
||||
end
|
||||
|
||||
-- Evaluate CAS
|
||||
@@ -245,6 +355,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
local TargetSetUnit = self:EvaluateCAS( DetectedItem ) -- Returns a SetUnit if there are targets to be CASed...
|
||||
if TargetSetUnit then
|
||||
Task = TASK_A2G_CAS:New( Mission, self.SetGroup, string.format( "CAS.%03d", DetectedItemID ), TargetSetUnit )
|
||||
Task:SetDetection( Detection, TaskIndex )
|
||||
end
|
||||
|
||||
-- Evaluate BAI
|
||||
@@ -252,6 +363,7 @@ do -- TASK_A2G_DISPATCHER
|
||||
local TargetSetUnit = self:EvaluateBAI( DetectedItem, self.Mission:GetCommandCenter():GetPositionable():GetCoalition() ) -- Returns a SetUnit if there are targets to be BAIed...
|
||||
if TargetSetUnit then
|
||||
Task = TASK_A2G_BAI:New( Mission, self.SetGroup, string.format( "BAI.%03d", DetectedItemID ), TargetSetUnit )
|
||||
Task:SetDetection( Detection, TaskIndex )
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -260,13 +372,13 @@ do -- TASK_A2G_DISPATCHER
|
||||
self.Tasks[TaskIndex] = Task
|
||||
Task:SetTargetZone( DetectedZone )
|
||||
Task:SetDispatcher( self )
|
||||
Task:UpdateTaskInfo()
|
||||
Mission:AddTask( Task )
|
||||
|
||||
TaskReport:Add( Task:GetName() )
|
||||
else
|
||||
self:E("This should not happen")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -278,7 +390,6 @@ do -- TASK_A2G_DISPATCHER
|
||||
Mission:GetCommandCenter():SetMenu()
|
||||
|
||||
local TaskText = TaskReport:Text(", ")
|
||||
|
||||
for TaskGroupID, TaskGroup in pairs( self.SetGroup:GetSet() ) do
|
||||
if ( not Mission:IsGroupAssigned(TaskGroup) ) and TaskText ~= "" then
|
||||
Mission:GetCommandCenter():MessageToGroup( string.format( "%s has tasks %s. Subscribe to a task using the radio menu.", Mission:GetName(), TaskText ), TaskGroup )
|
||||
|
||||
@@ -161,10 +161,15 @@ do -- TASK_CARGO
|
||||
self.TaskType = TaskType
|
||||
self.SmokeColor = SMOKECOLOR.Red
|
||||
|
||||
self.CargoItemCount = {} -- Map of Carriers having a cargo item count to check the cargo loading limits.
|
||||
self.CargoLimit = 2
|
||||
|
||||
self.DeployZones = {} -- setmetatable( {}, { __mode = "v" } ) -- weak table on value
|
||||
|
||||
|
||||
local Fsm = self:GetUnitProcess()
|
||||
|
||||
Fsm:SetStartState( "Planned" )
|
||||
|
||||
Fsm:AddProcess ( "Planned", "Accept", ACT_ASSIGN_ACCEPT:New( self.TaskBriefing ), { Assigned = "SelectAction", Rejected = "Reject" } )
|
||||
|
||||
@@ -202,12 +207,19 @@ do -- TASK_CARGO
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_CARGO#TASK_CARGO Task
|
||||
function Fsm:onafterSelectAction( TaskUnit, Task )
|
||||
self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
|
||||
|
||||
local TaskUnitName = TaskUnit:GetName()
|
||||
|
||||
self:E( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } )
|
||||
|
||||
local MenuTime = timer.getTime()
|
||||
|
||||
TaskUnit.Menu = MENU_GROUP:New( TaskUnit:GetGroup(), Task:GetName() .. " @ " .. TaskUnit:GetName() ):SetTime( MenuTime )
|
||||
|
||||
local CargoItemCount = TaskUnit:CargoItemCount()
|
||||
|
||||
--Task:GetMission():GetCommandCenter():MessageToGroup( "Cargo in carrier: " .. CargoItemCount, TaskUnit:GetGroup() )
|
||||
|
||||
|
||||
Task.SetCargo:ForEachCargo(
|
||||
|
||||
@@ -226,51 +238,37 @@ do -- TASK_CARGO
|
||||
-- Cargo
|
||||
-- ):SetTime(MenuTime)
|
||||
-- end
|
||||
|
||||
|
||||
|
||||
if Cargo:IsUnLoaded() then
|
||||
if Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then
|
||||
MENU_GROUP_COMMAND:New(
|
||||
TaskUnit:GetGroup(),
|
||||
"Board cargo " .. Cargo.Name,
|
||||
TaskUnit.Menu,
|
||||
self.MenuBoardCargo,
|
||||
self,
|
||||
Cargo
|
||||
):SetTime(MenuTime)
|
||||
else
|
||||
MENU_GROUP_COMMAND:New(
|
||||
TaskUnit:GetGroup(),
|
||||
"Route to Pickup cargo " .. Cargo.Name,
|
||||
TaskUnit.Menu,
|
||||
self.MenuRouteToPickup,
|
||||
self,
|
||||
Cargo
|
||||
):SetTime(MenuTime)
|
||||
if CargoItemCount < Task.CargoLimit then
|
||||
if Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then
|
||||
local NotInDeployZones = true
|
||||
for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do
|
||||
if Cargo:IsInZone( DeployZone ) then
|
||||
NotInDeployZones = false
|
||||
end
|
||||
end
|
||||
if NotInDeployZones then
|
||||
if not TaskUnit:InAir() then
|
||||
MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Board cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuBoardCargo, self, Cargo ):SetTime(MenuTime)
|
||||
end
|
||||
end
|
||||
else
|
||||
MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Route to Pickup cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuRouteToPickup, self, Cargo ):SetTime(MenuTime)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Cargo:IsLoaded() then
|
||||
|
||||
MENU_GROUP_COMMAND:New(
|
||||
TaskUnit:GetGroup(),
|
||||
"Unboard cargo " .. Cargo.Name,
|
||||
TaskUnit.Menu,
|
||||
self.MenuUnBoardCargo,
|
||||
self,
|
||||
Cargo
|
||||
):SetTime(MenuTime)
|
||||
|
||||
if not TaskUnit:InAir() then
|
||||
MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Unboard cargo " .. Cargo.Name, TaskUnit.Menu, self.MenuUnBoardCargo, self, Cargo ):SetTime(MenuTime)
|
||||
end
|
||||
-- Deployzones are optional zones that can be selected to request routing information.
|
||||
for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do
|
||||
if not Cargo:IsInZone( DeployZone ) then
|
||||
MENU_GROUP_COMMAND:New(
|
||||
TaskUnit:GetGroup(),
|
||||
"Route to Deploy cargo at " .. DeployZoneName,
|
||||
TaskUnit.Menu,
|
||||
self.MenuRouteToDeploy,
|
||||
self,
|
||||
DeployZone
|
||||
):SetTime(MenuTime)
|
||||
MENU_GROUP_COMMAND:New( TaskUnit:GetGroup(), "Route to Deploy cargo at " .. DeployZoneName, TaskUnit.Menu, self.MenuRouteToDeploy, self, DeployZone ):SetTime(MenuTime)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -284,9 +282,9 @@ do -- TASK_CARGO
|
||||
|
||||
self:__SelectAction( -15 )
|
||||
|
||||
--Task:GetMission():GetCommandCenter():MessageToGroup("Cargo menu is ready ...", TaskUnit:GetGroup() )
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
@@ -320,8 +318,7 @@ do -- TASK_CARGO
|
||||
--#Wrapper.Unit#UNIT
|
||||
|
||||
|
||||
--- Route to Cargo
|
||||
-- @param #FSM_PROCESS self
|
||||
--- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_Cargo#TASK_CARGO Task
|
||||
-- @param From
|
||||
@@ -341,15 +338,15 @@ do -- TASK_CARGO
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- @param #FSM_PROCESS self
|
||||
--- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_Cargo#TASK_CARGO Task
|
||||
function Fsm:onafterArriveAtPickup( TaskUnit, Task )
|
||||
self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
|
||||
if self.Cargo:IsAlive() then
|
||||
TaskUnit:Smoke( Task:GetSmokeColor(), 15 )
|
||||
self.Cargo:Smoke( Task:GetSmokeColor(), 15 )
|
||||
if TaskUnit:IsAir() then
|
||||
Task:GetMission():GetCommandCenter():MessageToGroup( "Land", TaskUnit:GetGroup() )
|
||||
self:__Land( -0.1, "Pickup" )
|
||||
else
|
||||
self:__SelectAction( -0.1 )
|
||||
@@ -358,8 +355,7 @@ do -- TASK_CARGO
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #FSM_PROCESS self
|
||||
--- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_Cargo#TASK_CARGO Task
|
||||
function Fsm:onafterCancelRouteToPickup( TaskUnit, Task )
|
||||
@@ -369,8 +365,7 @@ do -- TASK_CARGO
|
||||
end
|
||||
|
||||
|
||||
--- Route to DeployZone
|
||||
-- @param #FSM_PROCESS self
|
||||
--- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
function Fsm:onafterRouteToDeploy( TaskUnit, Task, From, Event, To, DeployZone )
|
||||
self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
|
||||
@@ -382,14 +377,14 @@ do -- TASK_CARGO
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #FSM_PROCESS self
|
||||
--- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_Cargo#TASK_CARGO Task
|
||||
function Fsm:onafterArriveAtDeploy( TaskUnit, Task )
|
||||
self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
|
||||
|
||||
if TaskUnit:IsAir() then
|
||||
Task:GetMission():GetCommandCenter():MessageToGroup( "Land", TaskUnit:GetGroup() )
|
||||
self:__Land( -0.1, "Deploy" )
|
||||
else
|
||||
self:__SelectAction( -0.1 )
|
||||
@@ -397,8 +392,7 @@ do -- TASK_CARGO
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #FSM_PROCESS self
|
||||
--- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_Cargo#TASK_CARGO Task
|
||||
function Fsm:onafterCancelRouteToDeploy( TaskUnit, Task )
|
||||
@@ -409,7 +403,7 @@ do -- TASK_CARGO
|
||||
|
||||
|
||||
|
||||
-- @param #FSM_PROCESS self
|
||||
--- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_Cargo#TASK_CARGO Task
|
||||
function Fsm:onafterLand( TaskUnit, Task, From, Event, To, Action )
|
||||
@@ -418,7 +412,6 @@ do -- TASK_CARGO
|
||||
if self.Cargo:IsAlive() then
|
||||
if self.Cargo:IsInRadius( TaskUnit:GetPointVec2() ) then
|
||||
if TaskUnit:InAir() then
|
||||
Task:GetMission():GetCommandCenter():MessageToGroup( "Land", TaskUnit:GetGroup() )
|
||||
self:__Land( -10, Action )
|
||||
else
|
||||
Task:GetMission():GetCommandCenter():MessageToGroup( "Landed ...", TaskUnit:GetGroup() )
|
||||
@@ -434,8 +427,7 @@ do -- TASK_CARGO
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
-- @param #FSM_PROCESS self
|
||||
--- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_Cargo#TASK_CARGO Task
|
||||
function Fsm:onafterLanded( TaskUnit, Task, From, Event, To, Action )
|
||||
@@ -458,8 +450,7 @@ do -- TASK_CARGO
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
-- @param #FSM_PROCESS self
|
||||
--- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_Cargo#TASK_CARGO Task
|
||||
function Fsm:onafterPrepareBoarding( TaskUnit, Task, From, Event, To, Cargo )
|
||||
@@ -471,8 +462,7 @@ do -- TASK_CARGO
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
-- @param #FSM_PROCESS self
|
||||
--- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_Cargo#TASK_CARGO Task
|
||||
function Fsm:onafterBoard( TaskUnit, Task )
|
||||
@@ -498,14 +488,18 @@ do -- TASK_CARGO
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #FSM_PROCESS self
|
||||
--- @param #FSM_PROCESS self
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_Cargo#TASK_CARGO Task
|
||||
function Fsm:onafterBoarded( TaskUnit, Task )
|
||||
self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
|
||||
|
||||
local TaskUnitName = TaskUnit:GetName()
|
||||
self:E( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } )
|
||||
|
||||
self.Cargo:MessageToGroup( "Boarded ...", TaskUnit:GetGroup() )
|
||||
|
||||
TaskUnit:AddCargo( self.Cargo )
|
||||
|
||||
self:__SelectAction( 1 )
|
||||
|
||||
-- TODO:I need to find a more decent solution for this.
|
||||
@@ -579,12 +573,28 @@ do -- TASK_CARGO
|
||||
-- @param Wrapper.Unit#UNIT TaskUnit
|
||||
-- @param Tasking.Task_Cargo#TASK_CARGO Task
|
||||
function Fsm:onafterUnBoarded( TaskUnit, Task )
|
||||
self:E( { TaskUnit = TaskUnit, Task = Task and Task:GetClassNameAndID() } )
|
||||
|
||||
local TaskUnitName = TaskUnit:GetName()
|
||||
self:E( { TaskUnit = TaskUnitName, Task = Task and Task:GetClassNameAndID() } )
|
||||
|
||||
self.Cargo:MessageToGroup( "UnBoarded ...", TaskUnit:GetGroup() )
|
||||
|
||||
TaskUnit:RemoveCargo( self.Cargo )
|
||||
|
||||
local NotInDeployZones = true
|
||||
for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do
|
||||
if self.Cargo:IsInZone( DeployZone ) then
|
||||
NotInDeployZones = false
|
||||
end
|
||||
end
|
||||
|
||||
if NotInDeployZones == false then
|
||||
self.Cargo:SetDeployed( true )
|
||||
end
|
||||
|
||||
-- TODO:I need to find a more decent solution for this.
|
||||
Task:E( { CargoDeployed = Task.CargoDeployed } )
|
||||
Task:E( { CargoDeployed = Task.CargoDeployed and "true" or "false" } )
|
||||
Task:E( { CargoIsAlive = self.Cargo:IsAlive() and "true" or "false" } )
|
||||
if self.Cargo:IsAlive() then
|
||||
if Task.CargoDeployed then
|
||||
Task:CargoDeployed( TaskUnit, self.Cargo, self.DeployZone )
|
||||
@@ -598,7 +608,17 @@ do -- TASK_CARGO
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Set a limit on the amount of cargo items that can be loaded into the Carriers.
|
||||
-- @param #TASK_CARGO self
|
||||
-- @param CargoLimit Specifies a number of cargo items that can be loaded in the helicopter.
|
||||
-- @return #TASK_CARGO
|
||||
function TASK_CARGO:SetCargoLimit( CargoLimit )
|
||||
self.CargoLimit = CargoLimit
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
---@param Color Might be SMOKECOLOR.Blue, SMOKECOLOR.Red SMOKECOLOR.Orange, SMOKECOLOR.White or SMOKECOLOR.Green
|
||||
function TASK_CARGO:SetSmokeColor(SmokeColor)
|
||||
@@ -770,6 +790,17 @@ do -- TASK_CARGO
|
||||
return self
|
||||
end
|
||||
|
||||
function TASK_CARGO:SetGoalTotal()
|
||||
|
||||
self.GoalTotal = self.SetCargo:Count()
|
||||
end
|
||||
|
||||
function TASK_CARGO:GetGoalTotal()
|
||||
|
||||
return self.GoalTotal
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -802,6 +833,8 @@ do -- TASK_CARGO_TRANSPORT
|
||||
self:AddTransition( "*", "CargoPickedUp", "*" )
|
||||
self:AddTransition( "*", "CargoDeployed", "*" )
|
||||
|
||||
self:E( { CargoDeployed = self.CargoDeployed ~= nil and "true" or "false" } )
|
||||
|
||||
--- OnBefore Transition Handler for Event CargoPickedUp.
|
||||
-- @function [parent=#TASK_CARGO_TRANSPORT] OnBeforeCargoPickedUp
|
||||
-- @param #TASK_CARGO_TRANSPORT self
|
||||
@@ -880,7 +913,7 @@ do -- TASK_CARGO_TRANSPORT
|
||||
local CargoType = Cargo:GetType()
|
||||
local CargoName = Cargo:GetName()
|
||||
local CargoCoordinate = Cargo:GetCoordinate()
|
||||
CargoReport:Add( string.format( '- "%s" (%s) at %s', CargoName, CargoType, CargoCoordinate:ToString() ) )
|
||||
CargoReport:Add( string.format( '- "%s" (%s) at %s', CargoName, CargoType, CargoCoordinate:ToStringMGRS() ) )
|
||||
end
|
||||
)
|
||||
|
||||
@@ -892,6 +925,12 @@ do -- TASK_CARGO_TRANSPORT
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function TASK_CARGO_TRANSPORT:ReportOrder( ReportGroup )
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #TASK_CARGO_TRANSPORT self
|
||||
@@ -908,27 +947,36 @@ do -- TASK_CARGO_TRANSPORT
|
||||
-- Loop the CargoSet (so evaluate each Cargo in the SET_CARGO ).
|
||||
for CargoID, CargoData in pairs( Set ) do
|
||||
local Cargo = CargoData -- Core.Cargo#CARGO
|
||||
|
||||
if Cargo:IsDeployed() then
|
||||
|
||||
-- Loop the DeployZones set for the TASK_CARGO_TRANSPORT.
|
||||
for DeployZoneID, DeployZone in pairs( DeployZones ) do
|
||||
|
||||
-- If there is a Cargo not in one of DeployZones, then not all Cargo is deployed.
|
||||
self:T( { Cargo.CargoObject } )
|
||||
if Cargo:IsInZone( DeployZone ) then
|
||||
else
|
||||
CargoDeployed = false
|
||||
-- Loop the DeployZones set for the TASK_CARGO_TRANSPORT.
|
||||
for DeployZoneID, DeployZone in pairs( DeployZones ) do
|
||||
|
||||
-- If there is a Cargo not in one of DeployZones, then not all Cargo is deployed.
|
||||
self:T( { Cargo.CargoObject } )
|
||||
if Cargo:IsInZone( DeployZone ) == false then
|
||||
CargoDeployed = false
|
||||
end
|
||||
end
|
||||
else
|
||||
CargoDeployed = false
|
||||
end
|
||||
end
|
||||
|
||||
return CargoDeployed
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
--- @param #TASK_CARGO_TRANSPORT self
|
||||
function TASK_CARGO_TRANSPORT:onafterGoal( TaskUnit, From, Event, To )
|
||||
local CargoSet = self.CargoSet
|
||||
|
||||
if self:IsAllCargoTransported() then
|
||||
self:Success()
|
||||
end
|
||||
|
||||
self:__Goal( -10 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -31,7 +31,72 @@ FLARECOLOR = trigger.flareColor -- #FLARECOLOR
|
||||
|
||||
--- Utilities static class.
|
||||
-- @type UTILS
|
||||
UTILS = {}
|
||||
UTILS = {
|
||||
_MarkID = 1
|
||||
}
|
||||
|
||||
--- Function to infer instance of an object
|
||||
--
|
||||
-- ### Examples:
|
||||
--
|
||||
-- * UTILS.IsInstanceOf( 'some text', 'string' ) will return true
|
||||
-- * UTILS.IsInstanceOf( some_function, 'function' ) will return true
|
||||
-- * UTILS.IsInstanceOf( 10, 'number' ) will return true
|
||||
-- * UTILS.IsInstanceOf( false, 'boolean' ) will return true
|
||||
-- * UTILS.IsInstanceOf( nil, 'nil' ) will return true
|
||||
--
|
||||
-- * UTILS.IsInstanceOf( ZONE:New( 'some zone', ZONE ) will return true
|
||||
-- * UTILS.IsInstanceOf( ZONE:New( 'some zone', 'ZONE' ) will return true
|
||||
-- * UTILS.IsInstanceOf( ZONE:New( 'some zone', 'zone' ) will return true
|
||||
-- * UTILS.IsInstanceOf( ZONE:New( 'some zone', 'BASE' ) will return true
|
||||
--
|
||||
-- * UTILS.IsInstanceOf( ZONE:New( 'some zone', 'GROUP' ) will return false
|
||||
--
|
||||
--
|
||||
-- @param object is the object to be evaluated
|
||||
-- @param className is the name of the class to evaluate (can be either a string or a Moose class)
|
||||
-- @return #boolean
|
||||
UTILS.IsInstanceOf = function( object, className )
|
||||
-- Is className NOT a string ?
|
||||
if not type( className ) == 'string' then
|
||||
|
||||
-- Is className a Moose class ?
|
||||
if type( className ) == 'table' and className.IsInstanceOf ~= nil then
|
||||
|
||||
-- Get the name of the Moose class as a string
|
||||
className = className.ClassName
|
||||
|
||||
-- className is neither a string nor a Moose class, throw an error
|
||||
else
|
||||
|
||||
-- I'm not sure if this should take advantage of MOOSE logging function, or throw an error for pcall
|
||||
local err_str = 'className parameter should be a string; parameter received: '..type( className )
|
||||
self:E( err_str )
|
||||
return false
|
||||
-- error( err_str )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- Is the object a Moose class instance ?
|
||||
if type( object ) == 'table' and object.IsInstanceOf ~= nil then
|
||||
|
||||
-- Use the IsInstanceOf method of the BASE class
|
||||
return object:IsInstanceOf( className )
|
||||
else
|
||||
|
||||
-- If the object is not an instance of a Moose class, evaluate against lua basic data types
|
||||
local basicDataTypes = { 'string', 'number', 'function', 'boolean', 'nil', 'table' }
|
||||
for _, basicDataType in ipairs( basicDataTypes ) do
|
||||
if className == basicDataType then
|
||||
return type( object ) == basicDataType
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check failed
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--from http://lua-users.org/wiki/CopyTable
|
||||
@@ -171,22 +236,36 @@ UTILS.FeetToMeters = function(feet)
|
||||
return feet*0.3048
|
||||
end
|
||||
|
||||
UTILS.MpsToKnots = function(mps)
|
||||
return mps*3600/1852
|
||||
UTILS.KnotsToKmph = function(knots)
|
||||
return knots* 1.852
|
||||
end
|
||||
|
||||
UTILS.MpsToKmph = function(mps)
|
||||
return mps*3.6
|
||||
UTILS.KmphToMps = function( kmph )
|
||||
return kmph / 3.6
|
||||
end
|
||||
|
||||
UTILS.KnotsToMps = function(knots)
|
||||
return knots*1852/3600
|
||||
UTILS.MpsToKmph = function( mps )
|
||||
return mps * 3.6
|
||||
end
|
||||
|
||||
UTILS.KmphToMps = function(kmph)
|
||||
return kmph/3.6
|
||||
UTILS.MiphToMps = function( miph )
|
||||
return miph * 0.44704
|
||||
end
|
||||
|
||||
UTILS.MpsToMiph = function( mps )
|
||||
return mps / 0.44704
|
||||
end
|
||||
|
||||
UTILS.MpsToKnots = function( mps )
|
||||
return mps * 3600 / 1852
|
||||
end
|
||||
|
||||
UTILS.KnotsToMps = function( knots )
|
||||
return knots * 1852 / 3600
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[acc:
|
||||
in DM: decimal point of minutes.
|
||||
In DMS: decimal point of seconds.
|
||||
@@ -238,12 +317,13 @@ UTILS.tostringLL = function( lat, lon, acc, DMS)
|
||||
end
|
||||
|
||||
local secFrmtStr -- create the formatting string for the seconds place
|
||||
if acc <= 0 then -- no decimal place.
|
||||
secFrmtStr = '%02d'
|
||||
else
|
||||
local width = 3 + acc -- 01.310 - that's a width of 6, for example.
|
||||
secFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
|
||||
end
|
||||
secFrmtStr = '%02d'
|
||||
-- if acc <= 0 then -- no decimal place.
|
||||
-- secFrmtStr = '%02d'
|
||||
-- else
|
||||
-- local width = 3 + acc -- 01.310 - that's a width of 6, for example.
|
||||
-- secFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
|
||||
-- end
|
||||
|
||||
return string.format('%02d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' '
|
||||
.. string.format('%02d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi
|
||||
@@ -327,3 +407,28 @@ function UTILS.spairs( t, order )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- get a new mark ID for markings
|
||||
function UTILS.GetMarkID()
|
||||
|
||||
UTILS._MarkID = UTILS._MarkID + 1
|
||||
return UTILS._MarkID
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Test if a Vec2 is in a radius of another Vec2
|
||||
function UTILS.IsInRadius( InVec2, Vec2, Radius )
|
||||
|
||||
local InRadius = ( ( InVec2.x - Vec2.x ) ^2 + ( InVec2.y - Vec2.y ) ^2 ) ^ 0.5 <= Radius
|
||||
|
||||
return InRadius
|
||||
end
|
||||
|
||||
-- Test if a Vec3 is in the sphere of another Vec3
|
||||
function UTILS.IsInSphere( InVec3, Vec3, Radius )
|
||||
|
||||
local InSphere = ( ( InVec3.x - Vec3.x ) ^2 + ( InVec3.y - Vec3.y ) ^2 + ( InVec3.z - Vec3.z ) ^2 ) ^ 0.5 <= Radius
|
||||
|
||||
return InSphere
|
||||
end
|
||||
|
||||
@@ -57,7 +57,33 @@ AIRBASE = {
|
||||
},
|
||||
}
|
||||
|
||||
--- @field Caucasus
|
||||
--- Enumeration to identify the airbases in the Caucasus region.
|
||||
--
|
||||
-- These are all airbases of Caucasus:
|
||||
--
|
||||
-- * AIRBASE.Caucasus.Gelendzhik
|
||||
-- * AIRBASE.Caucasus.Krasnodar_Pashkovsky
|
||||
-- * AIRBASE.Caucasus.Sukhumi_Babushara
|
||||
-- * AIRBASE.Caucasus.Gudauta
|
||||
-- * AIRBASE.Caucasus.Batumi
|
||||
-- * AIRBASE.Caucasus.Senaki_Kolkhi
|
||||
-- * AIRBASE.Caucasus.Kobuleti
|
||||
-- * AIRBASE.Caucasus.Kutaisi
|
||||
-- * AIRBASE.Caucasus.Tbilisi_Lochini
|
||||
-- * AIRBASE.Caucasus.Soganlug
|
||||
-- * AIRBASE.Caucasus.Vaziani
|
||||
-- * AIRBASE.Caucasus.Anapa_Vityazevo
|
||||
-- * AIRBASE.Caucasus.Krasnodar_Center
|
||||
-- * AIRBASE.Caucasus.Novorossiysk
|
||||
-- * AIRBASE.Caucasus.Krymsk
|
||||
-- * AIRBASE.Caucasus.Maykop_Khanskaya
|
||||
-- * AIRBASE.Caucasus.Sochi_Adler
|
||||
-- * AIRBASE.Caucasus.Mineralnye_Vody
|
||||
-- * AIRBASE.Caucasus.Nalchik
|
||||
-- * AIRBASE.Caucasus.Mozdok
|
||||
-- * AIRBASE.Caucasus.Beslan
|
||||
--
|
||||
-- @field Caucasus
|
||||
AIRBASE.Caucasus = {
|
||||
["Gelendzhik"] = "Gelendzhik",
|
||||
["Krasnodar_Pashkovsky"] = "Krasnodar-Pashkovsky",
|
||||
@@ -83,6 +109,28 @@ AIRBASE.Caucasus = {
|
||||
}
|
||||
|
||||
--- @field Nevada
|
||||
--
|
||||
-- These are all airbases of Nevada:
|
||||
--
|
||||
-- * AIRBASE.Nevada.Creech_AFB
|
||||
-- * AIRBASE.Nevada.Groom_Lake_AFB
|
||||
-- * AIRBASE.Nevada.McCarran_International_Airport
|
||||
-- * AIRBASE.Nevada.Nellis_AFB
|
||||
-- * AIRBASE.Nevada.Beatty_Airport
|
||||
-- * AIRBASE.Nevada.Boulder_City_Airport
|
||||
-- * AIRBASE.Nevada.Echo_Bay
|
||||
-- * AIRBASE.Nevada.Henderson_Executive_Airport
|
||||
-- * AIRBASE.Nevada.Jean_Airport
|
||||
-- * AIRBASE.Nevada.Laughlin_Airport
|
||||
-- * AIRBASE.Nevada.Lincoln_County
|
||||
-- * AIRBASE.Nevada.Mellan_Airstrip
|
||||
-- * AIRBASE.Nevada.Mesquite
|
||||
-- * AIRBASE.Nevada.Mina_Airport_3Q0
|
||||
-- * AIRBASE.Nevada.North_Las_Vegas
|
||||
-- * AIRBASE.Nevada.Pahute_Mesa_Airstrip
|
||||
-- * AIRBASE.Nevada.Tonopah_Airport
|
||||
-- * AIRBASE.Nevada.Tonopah_Test_Range_Airfield
|
||||
--
|
||||
AIRBASE.Nevada = {
|
||||
["Creech_AFB"] = "Creech AFB",
|
||||
["Groom_Lake_AFB"] = "Groom Lake AFB",
|
||||
@@ -105,6 +153,40 @@ AIRBASE.Nevada = {
|
||||
}
|
||||
|
||||
--- @field Normandy
|
||||
--
|
||||
-- These are all airbases of Normandy:
|
||||
--
|
||||
-- * AIRBASE.Normandy.Saint_Pierre_du_Mont
|
||||
-- * AIRBASE.Normandy.Lignerolles
|
||||
-- * AIRBASE.Normandy.Cretteville
|
||||
-- * AIRBASE.Normandy.Maupertus
|
||||
-- * AIRBASE.Normandy.Brucheville
|
||||
-- * AIRBASE.Normandy.Meautis
|
||||
-- * AIRBASE.Normandy.Cricqueville_en_Bessin
|
||||
-- * AIRBASE.Normandy.Lessay
|
||||
-- * AIRBASE.Normandy.Sainte_Laurent_sur_Mer
|
||||
-- * AIRBASE.Normandy.Biniville
|
||||
-- * AIRBASE.Normandy.Cardonville
|
||||
-- * AIRBASE.Normandy.Deux_Jumeaux
|
||||
-- * AIRBASE.Normandy.Chippelle
|
||||
-- * AIRBASE.Normandy.Beuzeville
|
||||
-- * AIRBASE.Normandy.Azeville
|
||||
-- * AIRBASE.Normandy.Picauville
|
||||
-- * AIRBASE.Normandy.Le_Molay
|
||||
-- * AIRBASE.Normandy.Longues_sur_Mer
|
||||
-- * AIRBASE.Normandy.Carpiquet
|
||||
-- * AIRBASE.Normandy.Bazenville
|
||||
-- * AIRBASE.Normandy.Sainte_Croix_sur_Mer
|
||||
-- * AIRBASE.Normandy.Beny_sur_Mer
|
||||
-- * AIRBASE.Normandy.Rucqueville
|
||||
-- * AIRBASE.Normandy.Sommervieu
|
||||
-- * AIRBASE.Normandy.Lantheuil
|
||||
-- * AIRBASE.Normandy.Evreux
|
||||
-- * AIRBASE.Normandy.Chailey
|
||||
-- * AIRBASE.Normandy.Needs_Oar_Point
|
||||
-- * AIRBASE.Normandy.Funtington
|
||||
-- * AIRBASE.Normandy.Tangmere
|
||||
-- * AIRBASE.Normandy.Ford
|
||||
AIRBASE.Normandy = {
|
||||
["Saint_Pierre_du_Mont"] = "Saint Pierre du Mont",
|
||||
["Lignerolles"] = "Lignerolles",
|
||||
@@ -149,6 +231,7 @@ function AIRBASE:Register( AirbaseName )
|
||||
|
||||
local self = BASE:Inherit( self, POSITIONABLE:New( AirbaseName ) )
|
||||
self.AirbaseName = AirbaseName
|
||||
self.AirbaseZone = ZONE_RADIUS:New( AirbaseName, self:GetVec2(), 2500 )
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -185,5 +268,12 @@ function AIRBASE:GetDCSObject()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Get the airbase zone.
|
||||
-- @param #AIRBASE self
|
||||
-- @return Core.Zone#ZONE_RADIUS The zone radius of the airbase.
|
||||
function AIRBASE:GetZone()
|
||||
return self.AirbaseZone
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -95,6 +95,22 @@
|
||||
-- * @{#CONTROLLABLE.TaskCondition}: Return a condition section for a controlled task.
|
||||
-- * @{#CONTROLLABLE.TaskControlled}: Return a Controlled Task taking a Task and a TaskCondition.
|
||||
--
|
||||
-- ### Call a function as a Task
|
||||
--
|
||||
-- A function can be called which is part of a Task. The method @{#CONTROLLABLE.TaskFunction}() prepares
|
||||
-- a Task that can call a GLOBAL function from within the Controller execution.
|
||||
-- This method can also be used to **embed a function call when a certain waypoint has been reached**.
|
||||
-- See below the **Tasks at Waypoints** section.
|
||||
--
|
||||
-- Demonstration Mission: [GRP-502 - Route at waypoint to random point](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/release-2-2-pre/GRP - Group Commands/GRP-502 - Route at waypoint to random point)
|
||||
--
|
||||
-- ### Tasks at Waypoints
|
||||
--
|
||||
-- Special Task methods are available to set tasks at certain waypoints.
|
||||
-- The method @{#CONTROLLABLE.SetTaskWaypoint}() helps preparing a Route, embedding a Task at the Waypoint of the Route.
|
||||
--
|
||||
-- This creates a Task element, with an action to call a function as part of a Wrapped Task.
|
||||
--
|
||||
-- ### Obtain the mission from controllable templates
|
||||
--
|
||||
-- Controllable templates contain complete mission descriptions. Sometimes you want to copy a complete mission from a controllable and assign it to another:
|
||||
@@ -108,7 +124,15 @@
|
||||
-- * @{#CONTROLLABLE.CommandDoScript}: Do Script command.
|
||||
-- * @{#CONTROLLABLE.CommandSwitchWayPoint}: Perform a switch waypoint command.
|
||||
--
|
||||
-- ## CONTROLLABLE Option methods
|
||||
-- ## Routing of Controllables
|
||||
--
|
||||
-- Different routing methods exist to route GROUPs and UNITs to different locations:
|
||||
--
|
||||
-- * @{#CONTROLLABLE.Route}(): Make the Controllable to follow a given route.
|
||||
-- * @{#CONTROLLABLE.RouteGroundTo}(): Make the GROUND Controllable to drive towards a specific coordinate.
|
||||
-- * @{#CONTROLLABLE.RouteAirTo}(): Make the AIR Controllable to fly towards a specific coordinate.
|
||||
--
|
||||
-- ## Option methods
|
||||
--
|
||||
-- Controllable **Option methods** change the behaviour of the Controllable while being alive.
|
||||
--
|
||||
@@ -257,6 +281,16 @@ function CONTROLLABLE:GetLife0()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns relative amount of fuel (from 0.0 to 1.0) the unit has in its internal tanks.
|
||||
-- This method returns nil to ensure polymorphic behaviour! This method needs to be overridden by GROUP or UNIT.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #nil The CONTROLLABLE is not existing or alive.
|
||||
function CONTROLLABLE:GetFuel()
|
||||
self:F( self.ControllableName )
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -334,16 +368,25 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime )
|
||||
|
||||
if DCSControllable then
|
||||
|
||||
local Controller = self:_GetController()
|
||||
local DCSControllableName = self:GetName()
|
||||
|
||||
-- When a controllable SPAWNs, it takes about a second to get the controllable in the simulator. Setting tasks to unspawned controllables provides unexpected results.
|
||||
-- Therefore we schedule the functions to set the mission and options for the Controllable.
|
||||
-- Controller.setTask( Controller, DCSTask )
|
||||
|
||||
if not WaitTime then
|
||||
Controller:setTask( DCSTask )
|
||||
local function SetTask( Controller, DCSTask )
|
||||
if self and self:IsAlive() then
|
||||
local Controller = self:_GetController()
|
||||
Controller:setTask( DCSTask )
|
||||
else
|
||||
BASE:E( DCSControllableName .. " is not alive anymore. Cannot set DCSTask " .. DCSTask )
|
||||
end
|
||||
end
|
||||
|
||||
if not WaitTime or WaitTime == 0 then
|
||||
SetTask( self, DCSTask )
|
||||
else
|
||||
self.TaskScheduler:Schedule( Controller, Controller.setTask, { DCSTask }, WaitTime )
|
||||
self.TaskScheduler:Schedule( self, SetTask, { DCSTask }, WaitTime )
|
||||
end
|
||||
|
||||
return self
|
||||
@@ -449,11 +492,11 @@ function CONTROLLABLE:TaskWrappedAction( DCSCommand, Index )
|
||||
self:F2( { DCSCommand } )
|
||||
|
||||
local DCSTaskWrappedAction
|
||||
|
||||
|
||||
DCSTaskWrappedAction = {
|
||||
id = "WrappedAction",
|
||||
enabled = true,
|
||||
number = Index,
|
||||
number = Index or 1,
|
||||
auto = false,
|
||||
params = {
|
||||
action = DCSCommand,
|
||||
@@ -464,6 +507,22 @@ function CONTROLLABLE:TaskWrappedAction( DCSCommand, Index )
|
||||
return DCSTaskWrappedAction
|
||||
end
|
||||
|
||||
--- Set a Task at a Waypoint using a Route list.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #table Waypoint The Waypoint!
|
||||
-- @param Dcs.DCSTasking.Task#Task Task The Task structure to be executed!
|
||||
-- @return Dcs.DCSTasking.Task#Task
|
||||
function CONTROLLABLE:SetTaskWaypoint( Waypoint, Task )
|
||||
|
||||
Waypoint.task = self:TaskCombo( { Task } )
|
||||
|
||||
self:T3( { Waypoint.task } )
|
||||
return Waypoint.task
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Executes a command action
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Dcs.DCSCommand#Command DCSCommand
|
||||
@@ -1480,6 +1539,84 @@ function CONTROLLABLE:TaskEmbarkToTransport( Point, Radius )
|
||||
return DCSTask
|
||||
end
|
||||
|
||||
--- This creates a Task element, with an action to call a function as part of a Wrapped Task.
|
||||
-- This Task can then be embedded at a Waypoint by calling the method @{#CONTROLLABLE.SetTaskWaypoint}.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #string FunctionString The function name embedded as a string that will be called.
|
||||
-- @param ... The variable arguments passed to the function when called! These arguments can be of any type!
|
||||
-- @return #CONTROLLABLE
|
||||
-- @usage
|
||||
--
|
||||
-- local ZoneList = {
|
||||
-- ZONE:New( "ZONE1" ),
|
||||
-- ZONE:New( "ZONE2" ),
|
||||
-- ZONE:New( "ZONE3" ),
|
||||
-- ZONE:New( "ZONE4" ),
|
||||
-- ZONE:New( "ZONE5" )
|
||||
-- }
|
||||
--
|
||||
-- GroundGroup = GROUP:FindByName( "Vehicle" )
|
||||
--
|
||||
-- --- @param Wrapper.Group#GROUP GroundGroup
|
||||
-- function RouteToZone( Vehicle, ZoneRoute )
|
||||
--
|
||||
-- local Route = {}
|
||||
--
|
||||
-- Vehicle:E( { ZoneRoute = ZoneRoute } )
|
||||
--
|
||||
-- Vehicle:MessageToAll( "Moving to zone " .. ZoneRoute:GetName(), 10 )
|
||||
--
|
||||
-- -- Get the current coordinate of the Vehicle
|
||||
-- local FromCoord = Vehicle:GetCoordinate()
|
||||
--
|
||||
-- -- Select a random Zone and get the Coordinate of the new Zone.
|
||||
-- local RandomZone = ZoneList[ math.random( 1, #ZoneList ) ] -- Core.Zone#ZONE
|
||||
-- local ToCoord = RandomZone:GetCoordinate()
|
||||
--
|
||||
-- -- Create a "ground route point", which is a "point" structure that can be given as a parameter to a Task
|
||||
-- Route[#Route+1] = FromCoord:WaypointGround( 72 )
|
||||
-- Route[#Route+1] = ToCoord:WaypointGround( 60, "Vee" )
|
||||
--
|
||||
-- local TaskRouteToZone = Vehicle:TaskFunction( "RouteToZone", RandomZone )
|
||||
--
|
||||
-- Vehicle:SetTaskWaypoint( Route, #Route, TaskRouteToZone ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||
--
|
||||
-- Vehicle:Route( Route, math.random( 10, 20 ) ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||
--
|
||||
-- end
|
||||
--
|
||||
-- RouteToZone( GroundGroup, ZoneList[1] )
|
||||
--
|
||||
function CONTROLLABLE:TaskFunction( FunctionString, ... )
|
||||
self:F2( { FunctionString, arg } )
|
||||
|
||||
local DCSTask
|
||||
|
||||
local DCSScript = {}
|
||||
DCSScript[#DCSScript+1] = "local MissionControllable = GROUP:Find( ... ) "
|
||||
|
||||
if arg and arg.n > 0 then
|
||||
local ArgumentKey = '_' .. tostring( arg ):match("table: (.*)")
|
||||
self:SetState( self, ArgumentKey, arg )
|
||||
DCSScript[#DCSScript+1] = "local Arguments = MissionControllable:GetState( MissionControllable, '" .. ArgumentKey .. "' ) "
|
||||
--DCSScript[#DCSScript+1] = "MissionControllable:ClearState( MissionControllable, '" .. ArgumentKey .. "' ) "
|
||||
DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable, unpack( Arguments ) )"
|
||||
else
|
||||
DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable )"
|
||||
end
|
||||
|
||||
DCSTask = self:TaskWrappedAction(
|
||||
self:CommandDoScript(
|
||||
table.concat( DCSScript )
|
||||
)
|
||||
)
|
||||
|
||||
self:T( DCSTask )
|
||||
|
||||
return DCSTask
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- (AIR + GROUND) Return a mission task from a mission template.
|
||||
@@ -1496,6 +1633,140 @@ function CONTROLLABLE:TaskMission( TaskMission )
|
||||
return DCSTask
|
||||
end
|
||||
|
||||
|
||||
do -- Patrol methods
|
||||
|
||||
--- (GROUND) Patrol iteratively using the waypoints the for the (parent) group.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE
|
||||
function CONTROLLABLE:PatrolRoute()
|
||||
|
||||
local PatrolGroup = self -- Wrapper.Group#GROUP
|
||||
|
||||
if not self:IsInstanceOf( "GROUP" ) then
|
||||
PatrolGroup = self:GetGroup() -- Wrapper.Group#GROUP
|
||||
end
|
||||
|
||||
self:E( { PatrolGroup = PatrolGroup:GetName() } )
|
||||
|
||||
if PatrolGroup:IsGround() or PatrolGroup:IsShip() then
|
||||
|
||||
local Waypoints = PatrolGroup:GetTemplateRoutePoints()
|
||||
|
||||
-- Calculate the new Route.
|
||||
local FromCoord = PatrolGroup:GetCoordinate()
|
||||
local From = FromCoord:WaypointGround( 120 )
|
||||
|
||||
table.insert( Waypoints, 1, From )
|
||||
|
||||
local TaskRoute = PatrolGroup:TaskFunction( "CONTROLLABLE.PatrolRoute" )
|
||||
|
||||
self:E({Waypoints = Waypoints})
|
||||
local Waypoint = Waypoints[#Waypoints]
|
||||
PatrolGroup:SetTaskWaypoint( Waypoint, TaskRoute ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||
|
||||
PatrolGroup:Route( Waypoints ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||
end
|
||||
end
|
||||
|
||||
--- (GROUND) Patrol randomly to the waypoints the for the (parent) group.
|
||||
-- A random waypoint will be picked and the group will move towards that point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE
|
||||
function CONTROLLABLE:PatrolRouteRandom( Speed, Formation, ToWaypoint )
|
||||
|
||||
local PatrolGroup = self -- Wrapper.Group#GROUP
|
||||
|
||||
if not self:IsInstanceOf( "GROUP" ) then
|
||||
PatrolGroup = self:GetGroup() -- Wrapper.Group#GROUP
|
||||
end
|
||||
|
||||
self:E( { PatrolGroup = PatrolGroup:GetName() } )
|
||||
|
||||
if PatrolGroup:IsGround() or PatrolGroup:IsShip() then
|
||||
|
||||
local Waypoints = PatrolGroup:GetTemplateRoutePoints()
|
||||
|
||||
-- Calculate the new Route.
|
||||
local FromCoord = PatrolGroup:GetCoordinate()
|
||||
local FromWaypoint = 1
|
||||
if ToWaypoint then
|
||||
FromWaypoint = ToWaypoint
|
||||
end
|
||||
|
||||
-- Loop until a waypoint has been found that is not the same as the current waypoint.
|
||||
-- Otherwise the object zon't move or drive in circles and the algorithm would not do exactly
|
||||
-- what it is supposed to do, which is making groups drive around.
|
||||
local ToWaypoint
|
||||
repeat
|
||||
-- Select a random waypoint and check if it is not the same waypoint as where the object is about.
|
||||
ToWaypoint = math.random( 1, #Waypoints )
|
||||
until( ToWaypoint ~= FromWaypoint )
|
||||
self:E( { FromWaypoint = FromWaypoint, ToWaypoint = ToWaypoint } )
|
||||
|
||||
local Waypoint = Waypoints[ToWaypoint] -- Select random waypoint.
|
||||
local ToCoord = COORDINATE:NewFromVec2( { x = Waypoint.x, y = Waypoint.y } )
|
||||
-- Create a "ground route point", which is a "point" structure that can be given as a parameter to a Task
|
||||
local Route = {}
|
||||
Route[#Route+1] = FromCoord:WaypointGround( 0 )
|
||||
Route[#Route+1] = ToCoord:WaypointGround( Speed, Formation )
|
||||
|
||||
|
||||
local TaskRouteToZone = PatrolGroup:TaskFunction( "CONTROLLABLE.PatrolRouteRandom", Speed, Formation, ToWaypoint )
|
||||
|
||||
PatrolGroup:SetTaskWaypoint( Route[#Route], TaskRouteToZone ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||
|
||||
PatrolGroup:Route( Route, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||
end
|
||||
end
|
||||
|
||||
--- (GROUND) Patrol randomly to the waypoints the for the (parent) group.
|
||||
-- A random waypoint will be picked and the group will move towards that point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE
|
||||
function CONTROLLABLE:PatrolZones( ZoneList, Speed, Formation )
|
||||
|
||||
if not type( ZoneList ) == "table" then
|
||||
ZoneList = { ZoneList }
|
||||
end
|
||||
|
||||
local PatrolGroup = self -- Wrapper.Group#GROUP
|
||||
|
||||
if not self:IsInstanceOf( "GROUP" ) then
|
||||
PatrolGroup = self:GetGroup() -- Wrapper.Group#GROUP
|
||||
end
|
||||
|
||||
self:E( { PatrolGroup = PatrolGroup:GetName() } )
|
||||
|
||||
if PatrolGroup:IsGround() or PatrolGroup:IsShip() then
|
||||
|
||||
local Waypoints = PatrolGroup:GetTemplateRoutePoints()
|
||||
local Waypoint = Waypoints[math.random( 1, #Waypoints )] -- Select random waypoint.
|
||||
|
||||
-- Calculate the new Route.
|
||||
local FromCoord = PatrolGroup:GetCoordinate()
|
||||
|
||||
-- Select a random Zone and get the Coordinate of the new Zone.
|
||||
local RandomZone = ZoneList[ math.random( 1, #ZoneList ) ] -- Core.Zone#ZONE
|
||||
local ToCoord = RandomZone:GetRandomCoordinate( 10 )
|
||||
|
||||
-- Create a "ground route point", which is a "point" structure that can be given as a parameter to a Task
|
||||
local Route = {}
|
||||
Route[#Route+1] = FromCoord:WaypointGround( 120 )
|
||||
Route[#Route+1] = ToCoord:WaypointGround( Speed, Formation )
|
||||
|
||||
|
||||
local TaskRouteToZone = PatrolGroup:TaskFunction( "CONTROLLABLE.PatrolZones", ZoneList, Speed, Formation )
|
||||
|
||||
PatrolGroup:SetTaskWaypoint( Route[#Route], TaskRouteToZone ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||
|
||||
PatrolGroup:Route( Route, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Return a Misson task to follow a given route defined by Points.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #table Points A table of route points.
|
||||
@@ -1620,19 +1891,16 @@ end
|
||||
|
||||
--- Make the controllable to follow a given route.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #table GoPoints A table of Route Points.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:Route( GoPoints )
|
||||
self:F2( GoPoints )
|
||||
-- @param #table Route A table of Route Points.
|
||||
-- @param #number DelaySeconds Wait for the specified seconds before executing the Route.
|
||||
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||
function CONTROLLABLE:Route( Route, DelaySeconds )
|
||||
self:F2( Route )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
|
||||
if DCSControllable then
|
||||
local Points = routines.utils.deepCopy( GoPoints )
|
||||
local MissionTask = { id = 'Mission', params = { route = { points = Points, }, }, }
|
||||
local Controller = self:_GetController()
|
||||
--Controller.setTask( Controller, MissionTask )
|
||||
self.TaskScheduler:Schedule( Controller, Controller.setTask, { MissionTask }, 1 )
|
||||
local RouteTask = self:TaskRoute( Route ) -- Create a RouteTask, that will route the CONTROLLABLE to the Route.
|
||||
self:SetTask( RouteTask, DelaySeconds or 1 ) -- Execute the RouteTask after the specified seconds (default is 1).
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1640,6 +1908,47 @@ function CONTROLLABLE:Route( GoPoints )
|
||||
end
|
||||
|
||||
|
||||
--- Make the GROUND Controllable to drive towards a specific point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
||||
-- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h.
|
||||
-- @param #string Formation (optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right".
|
||||
-- @param #number DelaySeconds Wait for the specified seconds before executing the Route.
|
||||
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||
function CONTROLLABLE:RouteGroundTo( ToCoordinate, Speed, Formation, DelaySeconds )
|
||||
|
||||
local FromCoordinate = self:GetCoordinate()
|
||||
|
||||
local FromWP = FromCoordinate:WaypointGround()
|
||||
local ToWP = ToCoordinate:WaypointGround( Speed, Formation )
|
||||
|
||||
self:Route( { FromWP, ToWP }, DelaySeconds )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Make the AIR Controllable fly towards a specific point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
||||
-- @param Core.Point#COORDINATE.RoutePointAltType AltType The altitude type.
|
||||
-- @param Core.Point#COORDINATE.RoutePointType Type The route point type.
|
||||
-- @param Core.Point#COORDINATE.RoutePointAction Action The route point action.
|
||||
-- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h.
|
||||
-- @param #number DelaySeconds Wait for the specified seconds before executing the Route.
|
||||
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||
function CONTROLLABLE:RouteAirTo( ToCoordinate, AltType, Type, Action, Speed, DelaySeconds )
|
||||
|
||||
local FromCoordinate = self:GetCoordinate()
|
||||
local FromWP = FromCoordinate:WaypointAir()
|
||||
|
||||
local ToWP = ToCoordinate:WaypointAir( AltType, Type, Action, Speed )
|
||||
|
||||
self:Route( { FromWP, ToWP }, DelaySeconds )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- (AIR + GROUND) Route the controllable to a given zone.
|
||||
-- The controllable final destination point can be randomized.
|
||||
@@ -2228,6 +2537,72 @@ function CONTROLLABLE:OptionROTVertical()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Alarm state to Auto: AI will automatically switch alarm states based on the presence of threats. The AI kind of cheats in this regard.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionAlarmStateAuto()
|
||||
self:F2( { self.ControllableName } )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller = self:_GetController()
|
||||
|
||||
if self:IsGround() then
|
||||
Controller:setOption(AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.AUTO)
|
||||
elseif self:IsShip() then
|
||||
Controller:setOption(AI.Option.Naval.id.ALARM_STATE, AI.Option.Naval.val.ALARM_STATE.AUTO)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Alarm state to Green: Group is not combat ready. Sensors are stowed if possible.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionAlarmStateGreen()
|
||||
self:F2( { self.ControllableName } )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller = self:_GetController()
|
||||
|
||||
if self:IsGround() then
|
||||
Controller:setOption(AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.GREEN)
|
||||
elseif self:IsShip() then
|
||||
Controller:setOption(AI.Option.Naval.id.ALARM_STATE, AI.Option.Naval.val.ALARM_STATE.GREEN)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Alarm state to Red: Group is combat ready and actively searching for targets.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:OptionAlarmStateRed()
|
||||
self:F2( { self.ControllableName } )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
if DCSControllable then
|
||||
local Controller = self:_GetController()
|
||||
|
||||
if self:IsGround() then
|
||||
Controller:setOption(AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.RED)
|
||||
elseif self:IsShip() then
|
||||
Controller:setOption(AI.Option.Naval.id.ALARM_STATE, AI.Option.Naval.val.ALARM_STATE.RED)
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Set RTB on bingo fuel.
|
||||
-- @param #CONTROLLABLE self
|
||||
@@ -2321,37 +2696,11 @@ function CONTROLLABLE:WayPointFunction( WayPoint, WayPointIndex, WayPointFunctio
|
||||
self:F2( { WayPoint, WayPointIndex, WayPointFunction } )
|
||||
|
||||
table.insert( self.WayPoints[WayPoint].task.params.tasks, WayPointIndex )
|
||||
self.WayPoints[WayPoint].task.params.tasks[WayPointIndex] = self:TaskFunction( WayPoint, WayPointIndex, WayPointFunction, arg )
|
||||
self.WayPoints[WayPoint].task.params.tasks[WayPointIndex] = self:TaskFunction( WayPointFunction, arg )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
function CONTROLLABLE:TaskFunction( WayPoint, WayPointIndex, FunctionString, FunctionArguments )
|
||||
self:F2( { WayPoint, WayPointIndex, FunctionString, FunctionArguments } )
|
||||
|
||||
local DCSTask
|
||||
|
||||
local DCSScript = {}
|
||||
DCSScript[#DCSScript+1] = "local MissionControllable = GROUP:Find( ... ) "
|
||||
|
||||
if FunctionArguments and #FunctionArguments > 0 then
|
||||
DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable, " .. table.concat( FunctionArguments, "," ) .. ")"
|
||||
else
|
||||
DCSScript[#DCSScript+1] = FunctionString .. "( MissionControllable )"
|
||||
end
|
||||
|
||||
DCSTask = self:TaskWrappedAction(
|
||||
self:CommandDoScript(
|
||||
table.concat( DCSScript )
|
||||
), WayPointIndex
|
||||
)
|
||||
|
||||
self:T( DCSTask )
|
||||
|
||||
return DCSTask
|
||||
|
||||
end
|
||||
|
||||
--- Executes the WayPoint plan.
|
||||
-- The function gets a WayPoint parameter, that you can use to restart the mission at a specific WayPoint.
|
||||
-- Note that when the WayPoint parameter is used, the new start mission waypoint of the controllable will be 1!
|
||||
@@ -2388,12 +2737,22 @@ function CONTROLLABLE:IsAirPlane()
|
||||
|
||||
if DCSObject then
|
||||
local Category = DCSObject:getDesc().category
|
||||
self:T( Category )
|
||||
return Category == Unit.Category.AIRPLANE
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function CONTROLLABLE:GetSize()
|
||||
|
||||
local DCSObject = self:GetDCSObject()
|
||||
|
||||
if DCSObject then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Message APIs
|
||||
@@ -104,15 +104,39 @@ GROUP.Takeoff = {
|
||||
GROUPTEMPLATE = {}
|
||||
|
||||
GROUPTEMPLATE.Takeoff = {
|
||||
[GROUP.Takeoff.Air] = "Turning Point",
|
||||
[GROUP.Takeoff.Runway] = "TakeOff",
|
||||
[GROUP.Takeoff.Hot] = "TakeOffParkingHot",
|
||||
[GROUP.Takeoff.Cold] = "TakeOffParking",
|
||||
[GROUP.Takeoff.Air] = { "Turning Point", "Turning Point" },
|
||||
[GROUP.Takeoff.Runway] = { "TakeOff", "From Runway" },
|
||||
[GROUP.Takeoff.Hot] = { "TakeOffParkingHot", "From Parking Area Hot" },
|
||||
[GROUP.Takeoff.Cold] = { "TakeOffParking", "From Parking Area" }
|
||||
}
|
||||
|
||||
--- Create a new GROUP from a DCSGroup
|
||||
--- Create a new GROUP from a given GroupTemplate as a parameter.
|
||||
-- Note that the GroupTemplate is NOT spawned into the mission.
|
||||
-- It is merely added to the @{Database}.
|
||||
-- @param #GROUP self
|
||||
-- @param Dcs.DCSWrapper.Group#Group GroupName The DCS Group name
|
||||
-- @param #table GroupTemplate The GroupTemplate Structure exactly as defined within the mission editor.
|
||||
-- @param Dcs.DCScoalition#coalition.side CoalitionSide The coalition.side of the group.
|
||||
-- @param Dcs.DCSGroup#Group.Category CategoryID The Group.Category of the group.
|
||||
-- @param Dcs.DCScountry#country.id CountryID the country.id of the group.
|
||||
-- @return #GROUP self
|
||||
function GROUP:NewTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID )
|
||||
local GroupName = GroupTemplate.name
|
||||
_DATABASE:_RegisterGroupTemplate( GroupTemplate, CategoryID, CountryID, CoalitionSide, GroupName )
|
||||
self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) )
|
||||
self:F2( GroupName )
|
||||
self.GroupName = GroupName
|
||||
|
||||
_DATABASE:AddGroup( GroupName )
|
||||
|
||||
self:SetEventPriority( 4 )
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Create a new GROUP from an existing Group in the Mission.
|
||||
-- @param #GROUP self
|
||||
-- @param #string GroupName The Group name
|
||||
-- @return #GROUP self
|
||||
function GROUP:Register( GroupName )
|
||||
self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) )
|
||||
@@ -224,6 +248,7 @@ function GROUP:Destroy()
|
||||
for Index, UnitData in pairs( DCSGroup:getUnits() ) do
|
||||
self:CreateEventCrash( timer.getTime(), UnitData )
|
||||
end
|
||||
USERFLAG:New( self:GetName() ):Set( 100 )
|
||||
DCSGroup:destroy()
|
||||
DCSGroup = nil
|
||||
end
|
||||
@@ -231,6 +256,7 @@ function GROUP:Destroy()
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Returns category of the DCS Group.
|
||||
-- @param #GROUP self
|
||||
-- @return Dcs.DCSWrapper.Group#Group.Category The category ID
|
||||
@@ -353,8 +379,13 @@ function GROUP:GetSize()
|
||||
|
||||
if DCSGroup then
|
||||
local GroupSize = DCSGroup:getSize()
|
||||
self:T3( GroupSize )
|
||||
return GroupSize
|
||||
|
||||
if GroupSize then
|
||||
self:T3( GroupSize )
|
||||
return GroupSize
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
@@ -502,7 +533,6 @@ end
|
||||
--- Returns a COORDINATE object indicating the point of the first UNIT of the GROUP within the mission.
|
||||
-- @param Wrapper.Group#GROUP self
|
||||
-- @return Core.Point#COORDINATE The COORDINATE of the GROUP.
|
||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||
function GROUP:GetCoordinate()
|
||||
self:F2( self.PositionableName )
|
||||
|
||||
@@ -560,6 +590,32 @@ function GROUP:GetHeading()
|
||||
|
||||
end
|
||||
|
||||
--- Returns relative amount of fuel (from 0.0 to 1.0) the group has in its internal tanks. If there are additional fuel tanks the value may be greater than 1.0.
|
||||
-- @param #GROUP self
|
||||
-- @return #number The relative amount of fuel (from 0.0 to 1.0).
|
||||
-- @return #nil The GROUP is not existing or alive.
|
||||
function GROUP:GetFuel()
|
||||
self:F( self.ControllableName )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
|
||||
if DCSControllable then
|
||||
local GroupSize = self:GetSize()
|
||||
local TotalFuel = 0
|
||||
for UnitID, UnitData in pairs( self:GetUnits() ) do
|
||||
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||
local UnitFuel = Unit:GetFuel()
|
||||
self:F( { Fuel = UnitFuel } )
|
||||
TotalFuel = TotalFuel + UnitFuel
|
||||
end
|
||||
local GroupFuel = TotalFuel / GroupSize
|
||||
return GroupFuel
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
do -- Is Zone methods
|
||||
|
||||
--- Returns true if all units of the group are within a @{Zone}.
|
||||
@@ -569,6 +625,8 @@ do -- Is Zone methods
|
||||
function GROUP:IsCompletelyInZone( Zone )
|
||||
self:F2( { self.GroupName, Zone } )
|
||||
|
||||
if not self:IsAlive() then return false end
|
||||
|
||||
for UnitID, UnitData in pairs( self:GetUnits() ) do
|
||||
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||
if Zone:IsVec3InZone( Unit:GetVec3() ) then
|
||||
@@ -590,6 +648,8 @@ function GROUP:IsPartlyInZone( Zone )
|
||||
local IsOneUnitInZone = false
|
||||
local IsOneUnitOutsideZone = false
|
||||
|
||||
if not self:IsAlive() then return false end
|
||||
|
||||
for UnitID, UnitData in pairs( self:GetUnits() ) do
|
||||
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||
if Zone:IsVec3InZone( Unit:GetVec3() ) then
|
||||
@@ -613,6 +673,8 @@ end
|
||||
function GROUP:IsNotInZone( Zone )
|
||||
self:F2( { self.GroupName, Zone } )
|
||||
|
||||
if not self:IsAlive() then return true end
|
||||
|
||||
for UnitID, UnitData in pairs( self:GetUnits() ) do
|
||||
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||
if Zone:IsVec3InZone( Unit:GetVec3() ) then
|
||||
@@ -631,6 +693,8 @@ function GROUP:CountInZone( Zone )
|
||||
self:F2( {self.GroupName, Zone} )
|
||||
local Count = 0
|
||||
|
||||
if not self:IsAlive() then return Count end
|
||||
|
||||
for UnitID, UnitData in pairs( self:GetUnits() ) do
|
||||
local Unit = UnitData -- Wrapper.Unit#UNIT
|
||||
if Zone:IsVec3InZone( Unit:GetVec3() ) then
|
||||
@@ -864,25 +928,28 @@ end
|
||||
-- @param #table Template The template of the Group retrieved with GROUP:GetTemplate()
|
||||
function GROUP:Respawn( Template )
|
||||
|
||||
local Vec3 = self:GetVec3()
|
||||
Template.x = Vec3.x
|
||||
Template.y = Vec3.z
|
||||
--Template.x = nil
|
||||
--Template.y = nil
|
||||
|
||||
self:E( #Template.units )
|
||||
for UnitID, UnitData in pairs( self:GetUnits() ) do
|
||||
local GroupUnit = UnitData -- Wrapper.Unit#UNIT
|
||||
self:E( GroupUnit:GetName() )
|
||||
if GroupUnit:IsAlive() then
|
||||
local GroupUnitVec3 = GroupUnit:GetVec3()
|
||||
local GroupUnitHeading = GroupUnit:GetHeading()
|
||||
Template.units[UnitID].alt = GroupUnitVec3.y
|
||||
Template.units[UnitID].x = GroupUnitVec3.x
|
||||
Template.units[UnitID].y = GroupUnitVec3.z
|
||||
Template.units[UnitID].heading = GroupUnitHeading
|
||||
self:E( { UnitID, Template.units[UnitID], Template.units[UnitID] } )
|
||||
if self:IsAlive() then
|
||||
local Vec3 = self:GetVec3()
|
||||
Template.x = Vec3.x
|
||||
Template.y = Vec3.z
|
||||
--Template.x = nil
|
||||
--Template.y = nil
|
||||
|
||||
self:E( #Template.units )
|
||||
for UnitID, UnitData in pairs( self:GetUnits() ) do
|
||||
local GroupUnit = UnitData -- Wrapper.Unit#UNIT
|
||||
self:E( GroupUnit:GetName() )
|
||||
if GroupUnit:IsAlive() then
|
||||
local GroupUnitVec3 = GroupUnit:GetVec3()
|
||||
local GroupUnitHeading = GroupUnit:GetHeading()
|
||||
Template.units[UnitID].alt = GroupUnitVec3.y
|
||||
Template.units[UnitID].x = GroupUnitVec3.x
|
||||
Template.units[UnitID].y = GroupUnitVec3.z
|
||||
Template.units[UnitID].heading = GroupUnitHeading
|
||||
self:E( { UnitID, Template.units[UnitID], Template.units[UnitID] } )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:Destroy()
|
||||
@@ -897,10 +964,19 @@ end
|
||||
-- @return #table
|
||||
function GROUP:GetTemplate()
|
||||
local GroupName = self:GetName()
|
||||
self:E( GroupName )
|
||||
return _DATABASE:GetGroupTemplate( GroupName )
|
||||
return UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) )
|
||||
end
|
||||
|
||||
--- Returns the group template route.points[] (the waypoints) from the @{DATABASE} (_DATABASE object).
|
||||
-- @param #GROUP self
|
||||
-- @return #table
|
||||
function GROUP:GetTemplateRoutePoints()
|
||||
local GroupName = self:GetName()
|
||||
return UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ).route.points )
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Sets the controlled status in a Template.
|
||||
-- @param #GROUP self
|
||||
-- @param #boolean Controlled true is controlled, false is uncontrolled.
|
||||
@@ -1075,7 +1151,7 @@ do -- Route methods
|
||||
|
||||
local PointTo = {}
|
||||
local AirbasePointVec2 = RTBAirbase:GetPointVec2()
|
||||
local AirbaseAirPoint = AirbasePointVec2:RoutePointAir(
|
||||
local AirbaseAirPoint = AirbasePointVec2:WaypointAir(
|
||||
POINT_VEC3.RoutePointAltType.BARO,
|
||||
"Land",
|
||||
"Landing",
|
||||
@@ -1120,9 +1196,9 @@ do -- Event Handling
|
||||
-- @param Core.Event#EVENTS Event
|
||||
-- @param #function EventFunction (optional) The function to be called when the event occurs for the GROUP.
|
||||
-- @return #GROUP
|
||||
function GROUP:HandleEvent( Event, EventFunction )
|
||||
function GROUP:HandleEvent( Event, EventFunction, ... )
|
||||
|
||||
self:EventDispatcher():OnEventForGroup( self:GetName(), EventFunction, self, Event )
|
||||
self:EventDispatcher():OnEventForGroup( self:GetName(), EventFunction, self, Event, ... )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -1133,7 +1209,7 @@ do -- Event Handling
|
||||
-- @return #GROUP
|
||||
function GROUP:UnHandleEvent( Event )
|
||||
|
||||
self:EventDispatcher():Remove( self, Event )
|
||||
self:EventDispatcher():RemoveEvent( self, Event )
|
||||
|
||||
return self
|
||||
end
|
||||
@@ -1162,7 +1238,7 @@ do -- Players
|
||||
-- @return #nil The group has no players
|
||||
function GROUP:GetPlayerNames()
|
||||
|
||||
local PlayerNames = nil
|
||||
local PlayerNames = {}
|
||||
|
||||
local Units = self:GetUnits()
|
||||
for UnitID, UnitData in pairs( Units ) do
|
||||
@@ -1178,4 +1254,96 @@ do -- Players
|
||||
return PlayerNames
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--do -- Smoke
|
||||
--
|
||||
----- Signal a flare at the position of the GROUP.
|
||||
---- @param #GROUP self
|
||||
---- @param Utilities.Utils#FLARECOLOR FlareColor
|
||||
--function GROUP:Flare( FlareColor )
|
||||
-- self:F2()
|
||||
-- trigger.action.signalFlare( self:GetVec3(), FlareColor , 0 )
|
||||
--end
|
||||
--
|
||||
----- Signal a white flare at the position of the GROUP.
|
||||
---- @param #GROUP self
|
||||
--function GROUP:FlareWhite()
|
||||
-- self:F2()
|
||||
-- trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.White , 0 )
|
||||
--end
|
||||
--
|
||||
----- Signal a yellow flare at the position of the GROUP.
|
||||
---- @param #GROUP self
|
||||
--function GROUP:FlareYellow()
|
||||
-- self:F2()
|
||||
-- trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Yellow , 0 )
|
||||
--end
|
||||
--
|
||||
----- Signal a green flare at the position of the GROUP.
|
||||
---- @param #GROUP self
|
||||
--function GROUP:FlareGreen()
|
||||
-- self:F2()
|
||||
-- trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Green , 0 )
|
||||
--end
|
||||
--
|
||||
----- Signal a red flare at the position of the GROUP.
|
||||
---- @param #GROUP self
|
||||
--function GROUP:FlareRed()
|
||||
-- self:F2()
|
||||
-- local Vec3 = self:GetVec3()
|
||||
-- if Vec3 then
|
||||
-- trigger.action.signalFlare( Vec3, trigger.flareColor.Red, 0 )
|
||||
-- end
|
||||
--end
|
||||
--
|
||||
----- Smoke the GROUP.
|
||||
---- @param #GROUP self
|
||||
--function GROUP:Smoke( SmokeColor, Range )
|
||||
-- self:F2()
|
||||
-- if Range then
|
||||
-- trigger.action.smoke( self:GetRandomVec3( Range ), SmokeColor )
|
||||
-- else
|
||||
-- trigger.action.smoke( self:GetVec3(), SmokeColor )
|
||||
-- end
|
||||
--
|
||||
--end
|
||||
--
|
||||
----- Smoke the GROUP Green.
|
||||
---- @param #GROUP self
|
||||
--function GROUP:SmokeGreen()
|
||||
-- self:F2()
|
||||
-- trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Green )
|
||||
--end
|
||||
--
|
||||
----- Smoke the GROUP Red.
|
||||
---- @param #GROUP self
|
||||
--function GROUP:SmokeRed()
|
||||
-- self:F2()
|
||||
-- trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Red )
|
||||
--end
|
||||
--
|
||||
----- Smoke the GROUP White.
|
||||
---- @param #GROUP self
|
||||
--function GROUP:SmokeWhite()
|
||||
-- self:F2()
|
||||
-- trigger.action.smoke( self:GetVec3(), trigger.smokeColor.White )
|
||||
--end
|
||||
--
|
||||
----- Smoke the GROUP Orange.
|
||||
---- @param #GROUP self
|
||||
--function GROUP:SmokeOrange()
|
||||
-- self:F2()
|
||||
-- trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Orange )
|
||||
--end
|
||||
--
|
||||
----- Smoke the GROUP Blue.
|
||||
---- @param #GROUP self
|
||||
--function GROUP:SmokeBlue()
|
||||
-- self:F2()
|
||||
-- trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Blue )
|
||||
--end
|
||||
--
|
||||
--
|
||||
--
|
||||
--end
|
||||
@@ -83,15 +83,8 @@ end
|
||||
function IDENTIFIABLE:GetName()
|
||||
self:F2( self.IdentifiableName )
|
||||
|
||||
local DCSIdentifiable = self:GetDCSObject()
|
||||
|
||||
if DCSIdentifiable then
|
||||
local IdentifiableName = self.IdentifiableName
|
||||
return IdentifiableName
|
||||
end
|
||||
|
||||
self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" )
|
||||
return nil
|
||||
local IdentifiableName = self.IdentifiableName
|
||||
return IdentifiableName
|
||||
end
|
||||
|
||||
|
||||
@@ -166,6 +159,36 @@ function IDENTIFIABLE:GetCoalition()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns the name of the coalition of the Identifiable.
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return #string The name of the coalition.
|
||||
-- @return #nil The DCS Identifiable is not existing or alive.
|
||||
function IDENTIFIABLE:GetCoalitionName()
|
||||
self:F2( self.IdentifiableName )
|
||||
|
||||
local DCSIdentifiable = self:GetDCSObject()
|
||||
|
||||
if DCSIdentifiable then
|
||||
local IdentifiableCoalition = DCSIdentifiable:getCoalition()
|
||||
self:T3( IdentifiableCoalition )
|
||||
|
||||
if IdentifiableCoalition == coalition.side.BLUE then
|
||||
return "Blue"
|
||||
end
|
||||
|
||||
if IdentifiableCoalition == coalition.side.RED then
|
||||
return "Red"
|
||||
end
|
||||
|
||||
if IdentifiableCoalition == coalition.side.NEUTRAL then
|
||||
return "Neutral"
|
||||
end
|
||||
end
|
||||
|
||||
self:E( self.ClassName .. " " .. self.IdentifiableName .. " not found!" )
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns country of the Identifiable.
|
||||
-- @param #IDENTIFIABLE self
|
||||
-- @return Dcs.DCScountry#country.id The country identifier.
|
||||
|
||||
@@ -79,7 +79,7 @@ function OBJECT:Destroy()
|
||||
local DCSObject = self:GetDCSObject()
|
||||
|
||||
if DCSObject then
|
||||
|
||||
--BASE:CreateEventCrash( timer.getTime(), DCSObject )
|
||||
DCSObject:destroy()
|
||||
end
|
||||
|
||||
|
||||
@@ -10,13 +10,11 @@
|
||||
--
|
||||
-- @module Positionable
|
||||
|
||||
|
||||
--- The POSITIONABLE class
|
||||
-- @type POSITIONABLE
|
||||
--- @type POSITIONABLE.__ Methods which are not intended for mission designers, but which are used interally by the moose designer :-)
|
||||
-- @extends Wrapper.Identifiable#IDENTIFIABLE
|
||||
|
||||
--- @type POSITIONABLE
|
||||
-- @extends Wrapper.Identifiable#IDENTIFIABLE
|
||||
-- @field #string PositionableName The name of the measurable.
|
||||
-- @field Core.Spot#SPOT Spot The laser Spot.
|
||||
-- @field #number LaserCode The last assigned laser code.
|
||||
|
||||
|
||||
--- # POSITIONABLE class, extends @{Identifiable#IDENTIFIABLE}
|
||||
@@ -49,6 +47,14 @@ POSITIONABLE = {
|
||||
ClassName = "POSITIONABLE",
|
||||
PositionableName = "",
|
||||
}
|
||||
|
||||
--- @field #POSITIONABLE.__
|
||||
POSITIONABLE.__ = {}
|
||||
|
||||
--- @field #POSITIONABLE.__.Cargo
|
||||
POSITIONABLE.__.Cargo = {}
|
||||
|
||||
|
||||
--- A DCSPositionable
|
||||
-- @type DCSPositionable
|
||||
-- @field id_ The ID of the controllable in DCS
|
||||
@@ -150,7 +156,6 @@ end
|
||||
--- Returns a COORDINATE object indicating the point in 3D of the POSITIONABLE within the mission.
|
||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||
-- @return Core.Point#COORDINATE The COORDINATE of the POSITIONABLE.
|
||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||
function POSITIONABLE:GetCoordinate()
|
||||
self:F2( self.PositionableName )
|
||||
|
||||
@@ -159,8 +164,9 @@ function POSITIONABLE:GetCoordinate()
|
||||
if DCSPositionable then
|
||||
local PositionableVec3 = self:GetPositionVec3()
|
||||
|
||||
local PositionableCoordinate = POINT_VEC3:NewFromVec3( PositionableVec3 )
|
||||
local PositionableCoordinate = COORDINATE:NewFromVec3( PositionableVec3 )
|
||||
PositionableCoordinate:SetHeading( self:GetHeading() )
|
||||
PositionableCoordinate:SetVelocity( self:GetVelocityMPS() )
|
||||
|
||||
self:T2( PositionableCoordinate )
|
||||
return PositionableCoordinate
|
||||
@@ -320,16 +326,35 @@ function POSITIONABLE:InAir()
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Returns the POSITIONABLE velocity vector.
|
||||
|
||||
--- Returns the a @{Velocity} object from the positionable.
|
||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||
-- @return Dcs.DCSTypes#Vec3 The velocity vector
|
||||
-- @return Core.Velocity#VELOCITY Velocity The Velocity object.
|
||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||
function POSITIONABLE:GetVelocity()
|
||||
self:F2( self.PositionableName )
|
||||
|
||||
local DCSPositionable = self:GetDCSObject()
|
||||
|
||||
if DCSPositionable then
|
||||
local Velocity = VELOCITY:New( self )
|
||||
return Velocity
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Returns the POSITIONABLE velocity Vec3 vector.
|
||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||
-- @return Dcs.DCSTypes#Vec3 The velocity Vec3 vector
|
||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||
function POSITIONABLE:GetVelocityVec3()
|
||||
self:F2( self.PositionableName )
|
||||
|
||||
local DCSPositionable = self:GetDCSObject()
|
||||
|
||||
if DCSPositionable then
|
||||
local PositionableVelocityVec3 = DCSPositionable:getVelocity()
|
||||
self:T3( PositionableVelocityVec3 )
|
||||
@@ -365,40 +390,38 @@ end
|
||||
--- Returns the POSITIONABLE velocity in km/h.
|
||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||
-- @return #number The velocity in km/h
|
||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||
function POSITIONABLE:GetVelocityKMH()
|
||||
self:F2( self.PositionableName )
|
||||
|
||||
local DCSPositionable = self:GetDCSObject()
|
||||
|
||||
if DCSPositionable then
|
||||
local VelocityVec3 = self:GetVelocity()
|
||||
local VelocityVec3 = self:GetVelocityVec3()
|
||||
local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec
|
||||
local Velocity = Velocity * 3.6 -- now it is in km/h.
|
||||
self:T3( Velocity )
|
||||
return Velocity
|
||||
end
|
||||
|
||||
return nil
|
||||
return 0
|
||||
end
|
||||
|
||||
--- Returns the POSITIONABLE velocity in meters per second.
|
||||
-- @param Wrapper.Positionable#POSITIONABLE self
|
||||
-- @return #number The velocity in meters per second.
|
||||
-- @return #nil The POSITIONABLE is not existing or alive.
|
||||
function POSITIONABLE:GetVelocityMPS()
|
||||
self:F2( self.PositionableName )
|
||||
|
||||
local DCSPositionable = self:GetDCSObject()
|
||||
|
||||
if DCSPositionable then
|
||||
local VelocityVec3 = self:GetVelocity()
|
||||
local VelocityVec3 = self:GetVelocityVec3()
|
||||
local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec
|
||||
self:T3( Velocity )
|
||||
return Velocity
|
||||
end
|
||||
|
||||
return nil
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
@@ -412,8 +435,8 @@ function POSITIONABLE:GetMessageText( Message, Name ) --R2.1 added
|
||||
local DCSObject = self:GetDCSObject()
|
||||
if DCSObject then
|
||||
Name = Name and ( " (" .. Name .. ")" ) or ""
|
||||
local Callsign = string.format( "[%s]", self:GetCallsign() ~= "" and self:GetCallsign() or self:GetName() )
|
||||
local MessageText = Callsign .. Name .. ": " .. Message
|
||||
local Callsign = string.format( "%s", self:GetCallsign() ~= "" and self:GetCallsign() or self:GetName() )
|
||||
local MessageText = string.format("[%s%s]: %s", Callsign, Name, Message )
|
||||
return MessageText
|
||||
end
|
||||
|
||||
@@ -438,6 +461,23 @@ function POSITIONABLE:GetMessage( Message, Duration, Name ) --R2.1 changed calls
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns a message of a specified type with the callsign embedded (if there is one).
|
||||
-- @param #POSITIONABLE self
|
||||
-- @param #string Message The message text
|
||||
-- @param Core.Message#MESSAGE MessageType MessageType The message type.
|
||||
-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable.
|
||||
-- @return Core.Message#MESSAGE
|
||||
function POSITIONABLE:GetMessageType( Message, MessageType, Name ) -- R2.2 changed callsign and name and using GetMessageText
|
||||
|
||||
local DCSObject = self:GetDCSObject()
|
||||
if DCSObject then
|
||||
local MessageText = self:GetMessageText( Message, Name )
|
||||
return MESSAGE:NewType( MessageText, MessageType )
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Send a message to all coalitions.
|
||||
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||
-- @param #POSITIONABLE self
|
||||
@@ -468,12 +508,6 @@ function POSITIONABLE:MessageToCoalition( Message, Duration, MessageCoalition )
|
||||
|
||||
local DCSObject = self:GetDCSObject()
|
||||
if DCSObject then
|
||||
if MessageCoalition == coalition.side.BLUE then
|
||||
Name = "Blue coalition"
|
||||
end
|
||||
if MessageCoalition == coalition.side.RED then
|
||||
Name = "Red coalition"
|
||||
end
|
||||
self:GetMessage( Message, Duration, Name ):ToCoalition( MessageCoalition )
|
||||
end
|
||||
|
||||
@@ -481,6 +515,26 @@ function POSITIONABLE:MessageToCoalition( Message, Duration, MessageCoalition )
|
||||
end
|
||||
|
||||
|
||||
--- Send a message to a coalition.
|
||||
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @param #string Message The message text
|
||||
-- @param Core.Message#MESSAGE.Type MessageType The message type that determines the duration.
|
||||
-- @param Dcs.DCScoalition#coalition MessageCoalition The Coalition receiving the message.
|
||||
function POSITIONABLE:MessageTypeToCoalition( Message, MessageType, MessageCoalition )
|
||||
self:F2( { Message, MessageType } )
|
||||
|
||||
local Name = ""
|
||||
|
||||
local DCSObject = self:GetDCSObject()
|
||||
if DCSObject then
|
||||
self:GetMessageType( Message, MessageType, Name ):ToCoalition( MessageCoalition )
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Send a message to the red coalition.
|
||||
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||
-- @param #POSITIONABLE self
|
||||
@@ -553,6 +607,26 @@ function POSITIONABLE:MessageToGroup( Message, Duration, MessageGroup, Name )
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Send a message of a message type to a @{Group}.
|
||||
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @param #string Message The message text
|
||||
-- @param Core.Message#MESSAGE.Type MessageType The message type that determines the duration.
|
||||
-- @param Wrapper.Group#GROUP MessageGroup The GROUP object receiving the message.
|
||||
-- @param #string Name (optional) The Name of the sender. If not provided, the Name is the type of the Positionable.
|
||||
function POSITIONABLE:MessageTypeToGroup( Message, MessageType, MessageGroup, Name )
|
||||
self:F2( { Message, MessageType } )
|
||||
|
||||
local DCSObject = self:GetDCSObject()
|
||||
if DCSObject then
|
||||
if DCSObject:isExist() then
|
||||
self:GetMessageType( Message, MessageType, Name ):ToGroup( MessageGroup )
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Send a message to a @{Set#SET_GROUP}.
|
||||
-- The message will appear in the message area. The message will begin with the callsign of the group and the type of the first unit sending the message.
|
||||
-- @param #POSITIONABLE self
|
||||
@@ -679,5 +753,139 @@ function POSITIONABLE:GetLaserCode() --R2.1
|
||||
return self.LaserCode
|
||||
end
|
||||
|
||||
--- Add cargo.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @param Core.Cargo#CARGO Cargo
|
||||
-- @return #POSITIONABLE
|
||||
function POSITIONABLE:AddCargo( Cargo )
|
||||
self.__.Cargo[Cargo] = Cargo
|
||||
return self
|
||||
end
|
||||
|
||||
--- Remove cargo.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @param Core.Cargo#CARGO Cargo
|
||||
-- @return #POSITIONABLE
|
||||
function POSITIONABLE:RemoveCargo( Cargo )
|
||||
self.__.Cargo[Cargo] = nil
|
||||
return self
|
||||
end
|
||||
|
||||
--- Returns if carrier has given cargo.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return Core.Cargo#CARGO Cargo
|
||||
function POSITIONABLE:HasCargo( Cargo )
|
||||
return self.__.Cargo[Cargo]
|
||||
end
|
||||
|
||||
--- Clear all cargo.
|
||||
-- @param #POSITIONABLE self
|
||||
function POSITIONABLE:ClearCargo()
|
||||
self.__.Cargo = {}
|
||||
end
|
||||
|
||||
--- Get cargo item count.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return Core.Cargo#CARGO Cargo
|
||||
function POSITIONABLE:CargoItemCount()
|
||||
local ItemCount = 0
|
||||
for CargoName, Cargo in pairs( self.__.Cargo ) do
|
||||
ItemCount = ItemCount + Cargo:GetCount()
|
||||
end
|
||||
return ItemCount
|
||||
end
|
||||
|
||||
--- Signal a flare at the position of the POSITIONABLE.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @param Utilities.Utils#FLARECOLOR FlareColor
|
||||
function POSITIONABLE:Flare( FlareColor )
|
||||
self:F2()
|
||||
trigger.action.signalFlare( self:GetVec3(), FlareColor , 0 )
|
||||
end
|
||||
|
||||
--- Signal a white flare at the position of the POSITIONABLE.
|
||||
-- @param #POSITIONABLE self
|
||||
function POSITIONABLE:FlareWhite()
|
||||
self:F2()
|
||||
trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.White , 0 )
|
||||
end
|
||||
|
||||
--- Signal a yellow flare at the position of the POSITIONABLE.
|
||||
-- @param #POSITIONABLE self
|
||||
function POSITIONABLE:FlareYellow()
|
||||
self:F2()
|
||||
trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Yellow , 0 )
|
||||
end
|
||||
|
||||
--- Signal a green flare at the position of the POSITIONABLE.
|
||||
-- @param #POSITIONABLE self
|
||||
function POSITIONABLE:FlareGreen()
|
||||
self:F2()
|
||||
trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Green , 0 )
|
||||
end
|
||||
|
||||
--- Signal a red flare at the position of the POSITIONABLE.
|
||||
-- @param #POSITIONABLE self
|
||||
function POSITIONABLE:FlareRed()
|
||||
self:F2()
|
||||
local Vec3 = self:GetVec3()
|
||||
if Vec3 then
|
||||
trigger.action.signalFlare( Vec3, trigger.flareColor.Red, 0 )
|
||||
end
|
||||
end
|
||||
|
||||
--- Smoke the POSITIONABLE.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @param Utilities.Utils#SMOKECOLOR SmokeColor The color to smoke to positionable.
|
||||
-- @param #number Range The range in meters to randomize the smoking around the positionable.
|
||||
-- @param #number AddHeight The height in meters to add to the altitude of the positionable.
|
||||
function POSITIONABLE:Smoke( SmokeColor, Range, AddHeight )
|
||||
self:F2()
|
||||
if Range then
|
||||
local Vec3 = self:GetRandomVec3( Range )
|
||||
Vec3.y = Vec3.y + AddHeight or 0
|
||||
trigger.action.smoke( Vec3, SmokeColor )
|
||||
else
|
||||
local Vec3 = self:GetVec3()
|
||||
Vec3.y = Vec3.y + AddHeight or 0
|
||||
trigger.action.smoke( self:GetVec3(), SmokeColor )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Smoke the POSITIONABLE Green.
|
||||
-- @param #POSITIONABLE self
|
||||
function POSITIONABLE:SmokeGreen()
|
||||
self:F2()
|
||||
trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Green )
|
||||
end
|
||||
|
||||
--- Smoke the POSITIONABLE Red.
|
||||
-- @param #POSITIONABLE self
|
||||
function POSITIONABLE:SmokeRed()
|
||||
self:F2()
|
||||
trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Red )
|
||||
end
|
||||
|
||||
--- Smoke the POSITIONABLE White.
|
||||
-- @param #POSITIONABLE self
|
||||
function POSITIONABLE:SmokeWhite()
|
||||
self:F2()
|
||||
trigger.action.smoke( self:GetVec3(), trigger.smokeColor.White )
|
||||
end
|
||||
|
||||
--- Smoke the POSITIONABLE Orange.
|
||||
-- @param #POSITIONABLE self
|
||||
function POSITIONABLE:SmokeOrange()
|
||||
self:F2()
|
||||
trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Orange )
|
||||
end
|
||||
|
||||
--- Smoke the POSITIONABLE Blue.
|
||||
-- @param #POSITIONABLE self
|
||||
function POSITIONABLE:SmokeBlue()
|
||||
self:F2()
|
||||
trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Blue )
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ function STATIC:FindByName( StaticName, RaiseError )
|
||||
|
||||
if StaticFound then
|
||||
StaticFound:F3( { StaticName } )
|
||||
|
||||
return StaticFound
|
||||
end
|
||||
|
||||
@@ -92,4 +91,18 @@ end
|
||||
function STATIC:GetThreatLevel()
|
||||
|
||||
return 1, "Static"
|
||||
end
|
||||
end
|
||||
|
||||
--- Respawn the @{Unit} using a (tweaked) template of the parent Group.
|
||||
-- @param #UNIT self
|
||||
-- @param Core.Point#COORDINATE Coordinate The coordinate where to spawn the new Static.
|
||||
-- @param #number Heading The heading of the unit respawn.
|
||||
function STATIC:ReSpawn( Coordinate, Heading )
|
||||
|
||||
|
||||
-- todo: need to fix country
|
||||
local SpawnStatic = SPAWNSTATIC:NewFromStatic( self.StaticName, country.id.USA )
|
||||
|
||||
SpawnStatic:SpawnFromPointVec2( Coordinate, Heading, self.StaticName )
|
||||
end
|
||||
|
||||
|
||||
@@ -159,6 +159,27 @@ function UNIT:GetDCSObject()
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Destroys the UNIT.
|
||||
-- @param #UNIT self
|
||||
-- @return #nil The DCS Unit is not existing or alive.
|
||||
function UNIT:Destroy()
|
||||
self:F2( self.ObjectName )
|
||||
|
||||
local DCSObject = self:GetDCSObject()
|
||||
|
||||
if DCSObject then
|
||||
local UnitGroup = self:GetGroup()
|
||||
local UnitGroupName = UnitGroup:GetName()
|
||||
self:F( { UnitGroupName = UnitGroupName } )
|
||||
USERFLAG:New( UnitGroupName ):Set( 100 )
|
||||
--BASE:CreateEventCrash( timer.getTime(), DCSObject )
|
||||
DCSObject:destroy()
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Respawn the @{Unit} using a (tweaked) template of the parent Group.
|
||||
--
|
||||
-- This function will:
|
||||
@@ -486,12 +507,12 @@ function UNIT:GetRadar()
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
--- Returns relative amount of fuel (from 0.0 to 1.0) the unit has in its internal tanks. If there are additional fuel tanks the value may be greater than 1.0.
|
||||
--- Returns relative amount of fuel (from 0.0 to 1.0) the UNIT has in its internal tanks. If there are additional fuel tanks the value may be greater than 1.0.
|
||||
-- @param #UNIT self
|
||||
-- @return #number The relative amount of fuel (from 0.0 to 1.0).
|
||||
-- @return #nil The DCS Unit is not existing or alive.
|
||||
function UNIT:GetFuel()
|
||||
self:F2( self.UnitName )
|
||||
self:F( self.UnitName )
|
||||
|
||||
local DCSUnit = self:GetDCSObject()
|
||||
|
||||
@@ -536,7 +557,7 @@ function UNIT:GetLife()
|
||||
return UnitLife
|
||||
end
|
||||
|
||||
return nil
|
||||
return -1
|
||||
end
|
||||
|
||||
--- Returns the Unit's initial health.
|
||||
@@ -553,7 +574,7 @@ function UNIT:GetLife0()
|
||||
return UnitLife0
|
||||
end
|
||||
|
||||
return nil
|
||||
return 0
|
||||
end
|
||||
|
||||
--- Returns the category name of the #UNIT.
|
||||
@@ -598,122 +619,128 @@ end
|
||||
-- @param #UNIT self
|
||||
function UNIT:GetThreatLevel()
|
||||
|
||||
local Attributes = self:GetDesc().attributes
|
||||
self:T( Attributes )
|
||||
|
||||
local ThreatLevel = 0
|
||||
local ThreatText = ""
|
||||
|
||||
if self:IsGround() then
|
||||
local Descriptor = self:GetDesc()
|
||||
|
||||
self:T( "Ground" )
|
||||
if Descriptor then
|
||||
|
||||
local ThreatLevels = {
|
||||
"Unarmed",
|
||||
"Infantry",
|
||||
"Old Tanks & APCs",
|
||||
"Tanks & IFVs without ATGM",
|
||||
"Tanks & IFV with ATGM",
|
||||
"Modern Tanks",
|
||||
"AAA",
|
||||
"IR Guided SAMs",
|
||||
"SR SAMs",
|
||||
"MR SAMs",
|
||||
"LR SAMs"
|
||||
}
|
||||
local Attributes = Descriptor.attributes
|
||||
self:T( Attributes )
|
||||
|
||||
if self:IsGround() then
|
||||
|
||||
self:T( "Ground" )
|
||||
|
||||
if Attributes["LR SAM"] then ThreatLevel = 10
|
||||
elseif Attributes["MR SAM"] then ThreatLevel = 9
|
||||
elseif Attributes["SR SAM"] and
|
||||
not Attributes["IR Guided SAM"] then ThreatLevel = 8
|
||||
elseif ( Attributes["SR SAM"] or Attributes["MANPADS"] ) and
|
||||
Attributes["IR Guided SAM"] then ThreatLevel = 7
|
||||
elseif Attributes["AAA"] then ThreatLevel = 6
|
||||
elseif Attributes["Modern Tanks"] then ThreatLevel = 5
|
||||
elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and
|
||||
Attributes["ATGM"] then ThreatLevel = 4
|
||||
elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and
|
||||
not Attributes["ATGM"] then ThreatLevel = 3
|
||||
elseif Attributes["Old Tanks"] or Attributes["APC"] or Attributes["Artillery"] then ThreatLevel = 2
|
||||
elseif Attributes["Infantry"] then ThreatLevel = 1
|
||||
local ThreatLevels = {
|
||||
"Unarmed",
|
||||
"Infantry",
|
||||
"Old Tanks & APCs",
|
||||
"Tanks & IFVs without ATGM",
|
||||
"Tanks & IFV with ATGM",
|
||||
"Modern Tanks",
|
||||
"AAA",
|
||||
"IR Guided SAMs",
|
||||
"SR SAMs",
|
||||
"MR SAMs",
|
||||
"LR SAMs"
|
||||
}
|
||||
|
||||
|
||||
if Attributes["LR SAM"] then ThreatLevel = 10
|
||||
elseif Attributes["MR SAM"] then ThreatLevel = 9
|
||||
elseif Attributes["SR SAM"] and
|
||||
not Attributes["IR Guided SAM"] then ThreatLevel = 8
|
||||
elseif ( Attributes["SR SAM"] or Attributes["MANPADS"] ) and
|
||||
Attributes["IR Guided SAM"] then ThreatLevel = 7
|
||||
elseif Attributes["AAA"] then ThreatLevel = 6
|
||||
elseif Attributes["Modern Tanks"] then ThreatLevel = 5
|
||||
elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and
|
||||
Attributes["ATGM"] then ThreatLevel = 4
|
||||
elseif ( Attributes["Tanks"] or Attributes["IFV"] ) and
|
||||
not Attributes["ATGM"] then ThreatLevel = 3
|
||||
elseif Attributes["Old Tanks"] or Attributes["APC"] or Attributes["Artillery"] then ThreatLevel = 2
|
||||
elseif Attributes["Infantry"] then ThreatLevel = 1
|
||||
end
|
||||
|
||||
ThreatText = ThreatLevels[ThreatLevel+1]
|
||||
end
|
||||
|
||||
ThreatText = ThreatLevels[ThreatLevel+1]
|
||||
end
|
||||
|
||||
if self:IsAir() then
|
||||
|
||||
self:T( "Air" )
|
||||
|
||||
local ThreatLevels = {
|
||||
"Unarmed",
|
||||
"Tanker",
|
||||
"AWACS",
|
||||
"Transport Helicopter",
|
||||
"UAV",
|
||||
"Bomber",
|
||||
"Strategic Bomber",
|
||||
"Attack Helicopter",
|
||||
"Battleplane",
|
||||
"Multirole Fighter",
|
||||
"Fighter"
|
||||
}
|
||||
if self:IsAir() then
|
||||
|
||||
|
||||
if Attributes["Fighters"] then ThreatLevel = 10
|
||||
elseif Attributes["Multirole fighters"] then ThreatLevel = 9
|
||||
elseif Attributes["Battleplanes"] then ThreatLevel = 8
|
||||
elseif Attributes["Attack helicopters"] then ThreatLevel = 7
|
||||
elseif Attributes["Strategic bombers"] then ThreatLevel = 6
|
||||
elseif Attributes["Bombers"] then ThreatLevel = 5
|
||||
elseif Attributes["UAVs"] then ThreatLevel = 4
|
||||
elseif Attributes["Transport helicopters"] then ThreatLevel = 3
|
||||
elseif Attributes["AWACS"] then ThreatLevel = 2
|
||||
elseif Attributes["Tankers"] then ThreatLevel = 1
|
||||
self:T( "Air" )
|
||||
|
||||
local ThreatLevels = {
|
||||
"Unarmed",
|
||||
"Tanker",
|
||||
"AWACS",
|
||||
"Transport Helicopter",
|
||||
"UAV",
|
||||
"Bomber",
|
||||
"Strategic Bomber",
|
||||
"Attack Helicopter",
|
||||
"Battleplane",
|
||||
"Multirole Fighter",
|
||||
"Fighter"
|
||||
}
|
||||
|
||||
|
||||
if Attributes["Fighters"] then ThreatLevel = 10
|
||||
elseif Attributes["Multirole fighters"] then ThreatLevel = 9
|
||||
elseif Attributes["Battleplanes"] then ThreatLevel = 8
|
||||
elseif Attributes["Attack helicopters"] then ThreatLevel = 7
|
||||
elseif Attributes["Strategic bombers"] then ThreatLevel = 6
|
||||
elseif Attributes["Bombers"] then ThreatLevel = 5
|
||||
elseif Attributes["UAVs"] then ThreatLevel = 4
|
||||
elseif Attributes["Transport helicopters"] then ThreatLevel = 3
|
||||
elseif Attributes["AWACS"] then ThreatLevel = 2
|
||||
elseif Attributes["Tankers"] then ThreatLevel = 1
|
||||
end
|
||||
|
||||
ThreatText = ThreatLevels[ThreatLevel+1]
|
||||
end
|
||||
|
||||
ThreatText = ThreatLevels[ThreatLevel+1]
|
||||
end
|
||||
|
||||
if self:IsShip() then
|
||||
|
||||
self:T( "Ship" )
|
||||
|
||||
--["Aircraft Carriers"] = {"Heavy armed ships",},
|
||||
--["Cruisers"] = {"Heavy armed ships",},
|
||||
--["Destroyers"] = {"Heavy armed ships",},
|
||||
--["Frigates"] = {"Heavy armed ships",},
|
||||
--["Corvettes"] = {"Heavy armed ships",},
|
||||
--["Heavy armed ships"] = {"Armed ships", "Armed Air Defence", "HeavyArmoredUnits",},
|
||||
--["Light armed ships"] = {"Armed ships","NonArmoredUnits"},
|
||||
--["Armed ships"] = {"Ships"},
|
||||
--["Unarmed ships"] = {"Ships","HeavyArmoredUnits",},
|
||||
|
||||
local ThreatLevels = {
|
||||
"Unarmed ship",
|
||||
"Light armed ships",
|
||||
"Corvettes",
|
||||
"",
|
||||
"Frigates",
|
||||
"",
|
||||
"Cruiser",
|
||||
"",
|
||||
"Destroyer",
|
||||
"",
|
||||
"Aircraft Carrier"
|
||||
}
|
||||
|
||||
if self:IsShip() then
|
||||
|
||||
self:T( "Ship" )
|
||||
|
||||
--["Aircraft Carriers"] = {"Heavy armed ships",},
|
||||
--["Cruisers"] = {"Heavy armed ships",},
|
||||
--["Destroyers"] = {"Heavy armed ships",},
|
||||
--["Frigates"] = {"Heavy armed ships",},
|
||||
--["Corvettes"] = {"Heavy armed ships",},
|
||||
--["Heavy armed ships"] = {"Armed ships", "Armed Air Defence", "HeavyArmoredUnits",},
|
||||
--["Light armed ships"] = {"Armed ships","NonArmoredUnits"},
|
||||
--["Armed ships"] = {"Ships"},
|
||||
--["Unarmed ships"] = {"Ships","HeavyArmoredUnits",},
|
||||
|
||||
if Attributes["Aircraft Carriers"] then ThreatLevel = 10
|
||||
elseif Attributes["Destroyers"] then ThreatLevel = 8
|
||||
elseif Attributes["Cruisers"] then ThreatLevel = 6
|
||||
elseif Attributes["Frigates"] then ThreatLevel = 4
|
||||
elseif Attributes["Corvettes"] then ThreatLevel = 2
|
||||
elseif Attributes["Light armed ships"] then ThreatLevel = 1
|
||||
local ThreatLevels = {
|
||||
"Unarmed ship",
|
||||
"Light armed ships",
|
||||
"Corvettes",
|
||||
"",
|
||||
"Frigates",
|
||||
"",
|
||||
"Cruiser",
|
||||
"",
|
||||
"Destroyer",
|
||||
"",
|
||||
"Aircraft Carrier"
|
||||
}
|
||||
|
||||
|
||||
if Attributes["Aircraft Carriers"] then ThreatLevel = 10
|
||||
elseif Attributes["Destroyers"] then ThreatLevel = 8
|
||||
elseif Attributes["Cruisers"] then ThreatLevel = 6
|
||||
elseif Attributes["Frigates"] then ThreatLevel = 4
|
||||
elseif Attributes["Corvettes"] then ThreatLevel = 2
|
||||
elseif Attributes["Light armed ships"] then ThreatLevel = 1
|
||||
end
|
||||
|
||||
ThreatText = ThreatLevels[ThreatLevel+1]
|
||||
end
|
||||
|
||||
ThreatText = ThreatLevels[ThreatLevel+1]
|
||||
end
|
||||
|
||||
self:T2( ThreatLevel )
|
||||
@@ -734,10 +761,9 @@ function UNIT:IsInZone( Zone )
|
||||
if self:IsAlive() then
|
||||
local IsInZone = Zone:IsVec3InZone( self:GetVec3() )
|
||||
|
||||
self:T2( { IsInZone } )
|
||||
self:E( { Unit = self.UnitName, IsInZone = IsInZone } )
|
||||
return IsInZone
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -788,92 +814,6 @@ end
|
||||
|
||||
|
||||
|
||||
--- Signal a flare at the position of the UNIT.
|
||||
-- @param #UNIT self
|
||||
-- @param Utilities.Utils#FLARECOLOR FlareColor
|
||||
function UNIT:Flare( FlareColor )
|
||||
self:F2()
|
||||
trigger.action.signalFlare( self:GetVec3(), FlareColor , 0 )
|
||||
end
|
||||
|
||||
--- Signal a white flare at the position of the UNIT.
|
||||
-- @param #UNIT self
|
||||
function UNIT:FlareWhite()
|
||||
self:F2()
|
||||
trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.White , 0 )
|
||||
end
|
||||
|
||||
--- Signal a yellow flare at the position of the UNIT.
|
||||
-- @param #UNIT self
|
||||
function UNIT:FlareYellow()
|
||||
self:F2()
|
||||
trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Yellow , 0 )
|
||||
end
|
||||
|
||||
--- Signal a green flare at the position of the UNIT.
|
||||
-- @param #UNIT self
|
||||
function UNIT:FlareGreen()
|
||||
self:F2()
|
||||
trigger.action.signalFlare( self:GetVec3(), trigger.flareColor.Green , 0 )
|
||||
end
|
||||
|
||||
--- Signal a red flare at the position of the UNIT.
|
||||
-- @param #UNIT self
|
||||
function UNIT:FlareRed()
|
||||
self:F2()
|
||||
local Vec3 = self:GetVec3()
|
||||
if Vec3 then
|
||||
trigger.action.signalFlare( Vec3, trigger.flareColor.Red, 0 )
|
||||
end
|
||||
end
|
||||
|
||||
--- Smoke the UNIT.
|
||||
-- @param #UNIT self
|
||||
function UNIT:Smoke( SmokeColor, Range )
|
||||
self:F2()
|
||||
if Range then
|
||||
trigger.action.smoke( self:GetRandomVec3( Range ), SmokeColor )
|
||||
else
|
||||
trigger.action.smoke( self:GetVec3(), SmokeColor )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Smoke the UNIT Green.
|
||||
-- @param #UNIT self
|
||||
function UNIT:SmokeGreen()
|
||||
self:F2()
|
||||
trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Green )
|
||||
end
|
||||
|
||||
--- Smoke the UNIT Red.
|
||||
-- @param #UNIT self
|
||||
function UNIT:SmokeRed()
|
||||
self:F2()
|
||||
trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Red )
|
||||
end
|
||||
|
||||
--- Smoke the UNIT White.
|
||||
-- @param #UNIT self
|
||||
function UNIT:SmokeWhite()
|
||||
self:F2()
|
||||
trigger.action.smoke( self:GetVec3(), trigger.smokeColor.White )
|
||||
end
|
||||
|
||||
--- Smoke the UNIT Orange.
|
||||
-- @param #UNIT self
|
||||
function UNIT:SmokeOrange()
|
||||
self:F2()
|
||||
trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Orange )
|
||||
end
|
||||
|
||||
--- Smoke the UNIT Blue.
|
||||
-- @param #UNIT self
|
||||
function UNIT:SmokeBlue()
|
||||
self:F2()
|
||||
trigger.action.smoke( self:GetVec3(), trigger.smokeColor.Blue )
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Is methods
|
||||
|
||||
Reference in New Issue
Block a user