diff --git a/Moose Development/Moose/AI/AI_A2A.lua b/Moose Development/Moose/AI/AI_A2A.lua
index fac8b4eaa..42c21731b 100644
--- a/Moose Development/Moose/AI/AI_A2A.lua
+++ b/Moose Development/Moose/AI/AI_A2A.lua
@@ -248,6 +248,7 @@ function AI_A2A:New( AIGroup )
-- @param #AI_A2A self
-- @param #number Delay
+ self:AddTransition( "*", "Takeoff", "Airborne" )
self:AddTransition( "*", "Return", "Returning" )
self:AddTransition( "*", "Hold", "Holding" )
self:AddTransition( "*", "Home", "Home" )
@@ -263,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
diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua
index 2509721b9..7b4fb69c0 100644
--- a/Moose Development/Moose/AI/AI_A2A_Cap.lua
+++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua
@@ -141,7 +141,7 @@ 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
@@ -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 AIGroup 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( AIGroup, From, Event, To )
+
+ AIGroup:HandleEvent( EVENTS.Takeoff, nil, self )
+
+end
--- Set the Engage Zone which defines where the AI will engage bogies.
-- @param #AI_A2A_CAP self
diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua
index 4b5c1496e..040268722 100644
--- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua
+++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua
@@ -978,6 +978,7 @@ do -- AI_A2A_DISPATCHER
-- This will avoid the detection to still "know" the shot unit until the next detection.
-- Otherwise, a new intercept or engage may happen for an already shot plane!
+
self:HandleEvent( EVENTS.Crash, self.OnEventCrashOrDead )
self:HandleEvent( EVENTS.Dead, self.OnEventCrashOrDead )
@@ -1360,6 +1361,8 @@ do -- AI_A2A_DISPATCHER
-- @param #AI_A2A_DISPATCHER self
function AI_A2A_DISPATCHER:SetDefenderTask( SquadronName, Defender, Type, Fsm, Target )
+ self:F( { SquadronName = SquadronName, Defender = Defender:GetName() } )
+
self.DefenderTasks[Defender] = self.DefenderTasks[Defender] or {}
self.DefenderTasks[Defender].Type = Type
self.DefenderTasks[Defender].Fsm = Fsm
@@ -2526,15 +2529,18 @@ do -- AI_A2A_DISPATCHER
DetectedSet:Flush()
local DefenderTasks = self:GetDefenderTasks()
- for Defender, DefenderTask in pairs( DefenderTasks ) do
- local Defender = Defender -- Wrapper.Group#GROUP
+ for DefenderGroup, DefenderTask in pairs( DefenderTasks ) do
+ local Defender = DefenderGroup -- Wrapper.Group#GROUP
local DefenderTaskTarget = DefenderTask.Target
local DefenderSquadronName = DefenderTask.SquadronName
+
if DefenderTaskTarget and DefenderTaskTarget.Index == AttackerDetection.Index then
local Squadron = self:GetSquadron( DefenderSquadronName )
- local SquadronOverhead = Squadron.Overhead or self.DefenderDefault.Overhead
- DefenderCount = DefenderCount + Defender:GetSize() / SquadronOverhead
- self:E( "Defender Group Name: " .. Defender:GetName() .. ", Size: " .. Defender:GetSize() )
+ local SquadronOverhead = Squadron.Overhead or self.DefenderDefault.Overhead
+
+ local DefenderSize = Defender:GetInitialSize()
+ DefenderCount = DefenderCount + DefenderSize / SquadronOverhead
+ self:F( "Defender Group Name: " .. Defender:GetName() .. ", Size: " .. DefenderSize )
end
end
@@ -2622,10 +2628,21 @@ do -- AI_A2A_DISPATCHER
Fsm:SetDisengageRadius( self.DisengageRadius )
Fsm:SetTanker( DefenderSquadron.TankerName or self.DefenderDefault.TankerName )
Fsm:Start()
- Fsm:__Patrol( 2 )
self:SetDefenderTask( SquadronName, DefenderCAP, "CAP", Fsm )
+ function Fsm:onafterTakeoff( Defender, From, Event, To )
+ self:F({"GCI Birth", Defender:GetName()})
+ --self:GetParent(self).onafterBirth( self, Defender, From, Event, To )
+
+ local Dispatcher = Fsm:GetDispatcher() -- #AI_A2A_DISPATCHER
+ local Squadron = Dispatcher:GetSquadronFromDefender( Defender )
+
+ if Squadron then
+ Fsm:__Patrol( 2 ) -- Start Patrolling
+ end
+ end
+
function Fsm:onafterRTB( Defender, From, Event, To )
self:F({"CAP RTB", Defender:GetName()})
self:GetParent(self).onafterRTB( self, Defender, From, Event, To )
@@ -2721,7 +2738,7 @@ do -- AI_A2A_DISPATCHER
local SpawnCoord = DefenderSquadron.Airbase:GetCoordinate() -- Core.Point#COORDINATE
local AttackerCoord = AttackerUnit:GetCoordinate()
local InterceptCoord = AttackerDetection.InterceptCoord
- self:F({InterceptCoord = InterceptCoord})
+ self:F( { InterceptCoord = InterceptCoord } )
if InterceptCoord then
local InterceptDistance = SpawnCoord:Get2DDistance( InterceptCoord )
local AirbaseDistance = SpawnCoord:Get2DDistance( AttackerCoord )
@@ -2757,6 +2774,11 @@ do -- AI_A2A_DISPATCHER
self:F( { Grouping = DefenderGrouping, SquadronGrouping = DefenderSquadron.Grouping, DefaultGrouping = self.DefenderDefault.Grouping } )
self:F( { DefendersCount = DefenderCount, DefendersNeeded = DefendersNeeded } )
+ if DefendersNeeded > DefenderSquadron.Resources then
+ DefendersNeeded = DefenderSquadron.Resources
+ BreakLoop = true
+ end
+
while ( DefendersNeeded > 0 ) do
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Functional.Spawn#SPAWN
@@ -2769,14 +2791,14 @@ do -- AI_A2A_DISPATCHER
local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName )
local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod, DefenderSquadron.TakeoffAltitude or self.DefenderDefault.TakeoffAltitude ) -- Wrapper.Group#GROUP
- self:F( { GCIDefender = DefenderGCI:GetName() } )
+ self:E( { GCIDefender = DefenderGCI:GetName() } )
DefendersNeeded = DefendersNeeded - DefenderGrouping
self:AddDefenderToSquadron( DefenderSquadron, DefenderGCI, DefenderGrouping )
if DefenderGCI then
-
+
DefenderCount = DefenderCount - DefenderGrouping / DefenderOverhead
local Fsm = AI_A2A_GCI:New( DefenderGCI, Gci.EngageMinSpeed, Gci.EngageMaxSpeed )
@@ -2786,12 +2808,24 @@ do -- AI_A2A_DISPATCHER
Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold )
Fsm:SetDisengageRadius( self.DisengageRadius )
Fsm:Start()
- Fsm:__Engage( 2, AttackerDetection.Set ) -- Engage on the TargetSetUnit
self:SetDefenderTask( ClosestDefenderSquadronName, DefenderGCI, "GCI", Fsm, AttackerDetection )
+ function Fsm:onafterTakeoff( Defender, From, Event, To )
+ self:F({"GCI Birth", Defender:GetName()})
+ --self:GetParent(self).onafterBirth( self, Defender, From, Event, To )
+
+ local Dispatcher = Fsm:GetDispatcher() -- #AI_A2A_DISPATCHER
+ local Squadron = Dispatcher:GetSquadronFromDefender( Defender )
+ local DefenderTarget = Dispatcher:GetDefenderTaskTarget( Defender )
+
+ if DefenderTarget then
+ Fsm:__Engage( 2, DefenderTarget.Set ) -- Engage on the TargetSetUnit
+ end
+ end
+
function Fsm:onafterRTB( Defender, From, Event, To )
self:F({"GCI RTB", Defender:GetName()})
self:GetParent(self).onafterRTB( self, Defender, From, Event, To )
@@ -2920,7 +2954,11 @@ do -- AI_A2A_DISPATCHER
for AIGroup, DefenderTask in pairs( self:GetDefenderTasks() ) do
local AIGroup = AIGroup -- Wrapper.Group#GROUP
if not AIGroup:IsAlive() then
- self:ClearDefenderTask( AIGroup )
+ local DefenderTaskFsm = self:GetDefenderTaskFsm( AIGroup )
+ self:E( { Defender = AIGroup:GetName(), DefenderState = DefenderTaskFsm:GetState() } )
+ if not DefenderTaskFsm:Is( "Started" ) then
+ self:ClearDefenderTask( AIGroup )
+ end
else
if DefenderTask.Target then
local AttackerItem = Detection:GetDetectedItem( DefenderTask.Target.Index )
diff --git a/Moose Development/Moose/AI/AI_A2A_Gci.lua b/Moose Development/Moose/AI/AI_A2A_Gci.lua
index 5d0c415c7..7791ea72d 100644
--- a/Moose Development/Moose/AI/AI_A2A_Gci.lua
+++ b/Moose Development/Moose/AI/AI_A2A_Gci.lua
@@ -134,7 +134,7 @@ 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
@@ -295,6 +295,19 @@ 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 #string From The From State string.
+-- @param #string Event The Event string.
+-- @param #string To The To State string.
+function AI_A2A_GCI:onafterStart( AIGroup, From, Event, To )
+
+ AIGroup:HandleEvent( EVENTS.Takeoff, nil, self )
+
+end
+
+
--- onafter State Transition for Event Patrol.
-- @param #AI_A2A_GCI self
diff --git a/Moose Development/Moose/AI/AI_A2A_Patrol.lua b/Moose Development/Moose/AI/AI_A2A_Patrol.lua
index 92cd522d3..fa9888584 100644
--- a/Moose Development/Moose/AI/AI_A2A_Patrol.lua
+++ b/Moose Development/Moose/AI/AI_A2A_Patrol.lua
@@ -179,7 +179,7 @@ function AI_A2A_PATROL:New( AIGroup, PatrolZone, PatrolFloorAltitude, PatrolCeil
-- defafult PatrolAltType to "RADIO" if not specified
self.PatrolAltType = PatrolAltType or "RADIO"
- self:AddTransition( { "Started", "Refuelling" }, "Patrol", "Patrolling" )
+ self:AddTransition( { "Started", "Airborne", "Refuelling" }, "Patrol", "Patrolling" )
--- OnBefore Transition Handler for Event Patrol.
-- @function [parent=#AI_A2A_PATROL] OnBeforePatrol
diff --git a/Moose Development/Moose/AI/AI_CAP.lua b/Moose Development/Moose/AI/AI_CAP.lua
index ac5916064..e15a0dd7a 100644
--- a/Moose Development/Moose/AI/AI_CAP.lua
+++ b/Moose Development/Moose/AI/AI_CAP.lua
@@ -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.
@@ -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: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
diff --git a/Moose Development/Moose/AI/AI_CAS.lua b/Moose Development/Moose/AI/AI_CAS.lua
index bd6b0e18a..a62f6d28d 100644
--- a/Moose Development/Moose/AI/AI_CAS.lua
+++ b/Moose Development/Moose/AI/AI_CAS.lua
@@ -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.
@@ -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.
@@ -524,20 +531,8 @@ 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 )
-
- --- 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()
+
+ Controllable:Route( EngageRoute, 0.5 )
self:SetRefreshTimeInterval( 2 )
self:SetDetectionActivated()
diff --git a/Moose Development/Moose/Core/Base.lua b/Moose Development/Moose/Core/Base.lua
index b3853173d..d6f61b293 100644
--- a/Moose Development/Moose/Core/Base.lua
+++ b/Moose Development/Moose/Core/Base.lua
@@ -608,6 +608,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
diff --git a/Moose Development/Moose/Core/Event.lua b/Moose Development/Moose/Core/Event.lua
index 28a4ecf26..01235b650 100644
--- a/Moose Development/Moose/Core/Event.lua
+++ b/Moose Development/Moose/Core/Event.lua
@@ -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
@@ -950,7 +951,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
@@ -966,14 +967,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:RemoveEvent( EventClass, Event.id )
+ --self:RemoveEvent( EventClass, Event.id )
end
else
diff --git a/Moose Development/Moose/Core/Menu.lua b/Moose Development/Moose/Core/Menu.lua
index 20705583f..4faaa5507 100644
--- a/Moose Development/Moose/Core/Menu.lua
+++ b/Moose Development/Moose/Core/Menu.lua
@@ -139,11 +139,24 @@ do -- MENU_COMMAND_BASE
function MENU_COMMAND_BASE:New( MenuText, ParentMenu, CommandMenuFunction, CommandMenuArguments )
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:SetCommandMenuFunction( CommandMenuFunction )
self:SetCommandMenuArguments( CommandMenuArguments )
self.MenuCallHandler = function()
- self.CommandMenuFunction( unpack( self.CommandMenuArguments ) )
+ local function MenuFunction()
+ return self.CommandMenuFunction( unpack( self.CommandMenuArguments ) )
+ end
+ local Status, Result = xpcall( MenuFunction, ErrorHandler )
end
return self
diff --git a/Moose Development/Moose/Core/Point.lua b/Moose Development/Moose/Core/Point.lua
index 4589d98b6..58fdefccd 100644
--- a/Moose Development/Moose/Core/Point.lua
+++ b/Moose Development/Moose/Core/Point.lua
@@ -488,9 +488,9 @@ do -- COORDINATE
function COORDINATE:GetHeadingText( Settings )
local Heading = self:GetHeading()
if Heading then
- return string.format( " heading %3.2f °", Heading )
+ return string.format( " bearing %3d°", Heading )
else
- return " heading cannot be determined"
+ return " bearing unknown"
end
end
@@ -1072,7 +1072,7 @@ do -- COORDINATE
end
- if ModeA2A then
+ if ModeA2A == true then
return self:ToStringA2A( Controllable, Settings )
else
return self:ToStringA2G( Controllable, Settings )
diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua
index 84d0763dd..c7dda4192 100644
--- a/Moose Development/Moose/Core/Set.lua
+++ b/Moose Development/Moose/Core/Set.lua
@@ -1883,7 +1883,7 @@ end
-- @return #number Heading Heading in degrees and speed in mps in case of moving units.
function SET_UNIT:GetHeading()
- local AvgHeading = nil
+ local HeadingSet = nil
local MovingCount = 0
for UnitName, UnitData in pairs( self:GetSet() ) do
@@ -1894,15 +1894,20 @@ function SET_UNIT:GetHeading()
local Velocity = Coordinate:GetVelocity()
if Velocity ~= 0 then
local Heading = Coordinate:GetHeading()
- AvgHeading = AvgHeading and ( AvgHeading + Heading ) or Heading
- MovingCount = MovingCount + 1
+ if HeadingSet == nil then
+ HeadingSet = Heading
+ else
+ local HeadingDiff = ( HeadingSet - Heading + 180 + 360 ) % 360 - 180
+ HeadingDiff = math.abs( HeadingDiff )
+ if HeadingDiff > 5 then
+ HeadingSet = nil
+ break
+ end
+ end
end
end
- AvgHeading = AvgHeading and ( AvgHeading / MovingCount )
-
- self:F( { AvgHeading = AvgHeading } )
- return AvgHeading
+ return HeadingSet
end
diff --git a/Moose Development/Moose/Functional/Scoring.lua b/Moose Development/Moose/Functional/Scoring.lua
index 53ed278b1..40c434f33 100644
--- a/Moose Development/Moose/Functional/Scoring.lua
+++ b/Moose Development/Moose/Functional/Scoring.lua
@@ -608,9 +608,9 @@ 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() )
@@ -626,16 +626,16 @@ function SCORING:_AddPlayerFromUnit( UnitData )
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
- 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
@@ -668,7 +668,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,7 +704,7 @@ 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
@@ -732,9 +732,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 +902,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 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 +926,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 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 +947,8 @@ function SCORING:_EventOnHit( Event )
end
else -- A scenery object was hit.
MESSAGE
- :New( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit 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 +1008,10 @@ function SCORING:_EventOnHit( Event )
PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1
MESSAGE
- :New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
+ :NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit friendly target " ..
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
"Penalty: -" .. PlayerHit.Penalty .. " = " .. Player.Score - Player.Penalty,
- 2
+ MESSAGE.Type.Update
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
@@ -1021,10 +1021,10 @@ function SCORING:_EventOnHit( Event )
PlayerHit.Score = PlayerHit.Score + 1
PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
MESSAGE
- :New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " ..
+ :NewType( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit enemy target " ..
TargetUnitCategory .. " ( " .. TargetType .. " ) " ..
"Score: +" .. PlayerHit.Score .. " = " .. Player.Score - Player.Penalty,
- 2
+ MESSAGE.Type.Update
)
:ToAllIf( self:IfMessagesHit() and self:IfMessagesToAll() )
:ToCoalitionIf( Event.WeaponCoalition, self:IfMessagesHit() and self:IfMessagesToCoalition() )
@@ -1032,8 +1032,8 @@ function SCORING:_EventOnHit( Event )
end
else -- A scenery object was hit.
MESSAGE
- :New( self.DisplayMessagePrefix .. "Player '" .. Event.WeaponPlayerName .. "' hit 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 +1131,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 .. "' " ..
+ :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly player '" .. TargetPlayerName .. "' " ..
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
- 15
+ MESSAGE.Type.Information
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
else
MESSAGE
- :New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " ..
+ :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed friendly target " ..
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
"Penalty: -" .. TargetDestroy.Penalty .. " = " .. Player.Score - Player.Penalty,
- 15
+ MESSAGE.Type.Information
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
@@ -1165,19 +1165,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 .. "' " ..
+ :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy player '" .. TargetPlayerName .. "' " ..
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
- 15
+ MESSAGE.Type.Information
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
else
MESSAGE
- :New( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " ..
+ :NewType( self.DisplayMessagePrefix .. "Player '" .. PlayerName .. "' destroyed enemy " ..
TargetUnitCategory .. " ( " .. ThreatTypeTarget .. " ) " ..
"Score: +" .. TargetDestroy.Score .. " = " .. Player.Score - Player.Penalty,
- 15
+ MESSAGE.Type.Information
)
:ToAllIf( self:IfMessagesDestroy() and self:IfMessagesToAll() )
:ToCoalitionIf( InitCoalition, self:IfMessagesDestroy() and self:IfMessagesToCoalition() )
@@ -1191,9 +1191,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 +1210,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 +1232,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 +1522,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 +1579,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 +1628,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
diff --git a/Moose Development/Moose/Functional/Spawn.lua b/Moose Development/Moose/Functional/Spawn.lua
index dfa15037d..6a99bdc11 100644
--- a/Moose Development/Moose/Functional/Spawn.lua
+++ b/Moose Development/Moose/Functional/Spawn.lua
@@ -1109,8 +1109,18 @@ function SPAWN:SpawnAtAirbase( SpawnAirbase, Takeoff, TakeoffAltitude ) -- R2.2
SpawnTemplate.x = PointVec3.x
SpawnTemplate.y = PointVec3.z
+
+ 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, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 1 )
+ end
+ end
- return self:SpawnWithIndex( self.SpawnIndex )
+ return GroupSpawned
end
end
diff --git a/Moose Development/Moose/Tasking/Mission.lua b/Moose Development/Moose/Tasking/Mission.lua
index 57b52983e..86117230c 100644
--- a/Moose Development/Moose/Tasking/Mission.lua
+++ b/Moose Development/Moose/Tasking/Mission.lua
@@ -888,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.
diff --git a/Moose Development/Moose/Tasking/Task.lua b/Moose Development/Moose/Tasking/Task.lua
index 4d6108705..e6a791794 100644
--- a/Moose Development/Moose/Tasking/Task.lua
+++ b/Moose Development/Moose/Tasking/Task.lua
@@ -1589,8 +1589,9 @@ function TASK:ReportDetails( ReportGroup )
Report:Add( TaskInfoIDText .. TaskInfo.TaskInfoText )
elseif type(TaskInfo) == "table" then
if TaskInfoID == "Coordinates" then
+ local FromCoordinate = ReportGroup:GetUnit(1):GetCoordinate()
local ToCoordinate = TaskInfo.TaskInfoText -- Core.Point#COORDINATE
- Report:Add( TaskInfoIDText .. ToCoordinate:ToString() )
+ Report:Add( TaskInfoIDText .. ToCoordinate:ToString( ReportGroup:GetUnit(1), nil, self ) )
else
end
end
diff --git a/Moose Development/Moose/Tasking/Task_A2G.lua b/Moose Development/Moose/Tasking/Task_A2G.lua
index 5b00b1b0d..cc4a21797 100644
--- a/Moose Development/Moose/Tasking/Task_A2G.lua
+++ b/Moose Development/Moose/Tasking/Task_A2G.lua
@@ -366,7 +366,8 @@ do -- TASK_A2G_SEAD
end
function TASK_A2G_SEAD:ReportOrder( ReportGroup )
- local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
+ local Coordinate = self:GetInfo( "Coordinates" )
+ --local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
return Distance
@@ -515,7 +516,8 @@ do -- TASK_A2G_BAI
function TASK_A2G_BAI:ReportOrder( ReportGroup )
- local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
+ local Coordinate = self:GetInfo( "Coordinates" )
+ --local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
return Distance
@@ -630,9 +632,9 @@ do -- TASK_A2G_CAS
function TASK_A2G_CAS:UpdateTaskInfo()
- local TargetCoordinate = self.Detection and self.Detection:GetDetectedItemCoordinate( self.DetectedItemIndex ) or self.TargetSetUnit:GetFirst():GetCoordinate()
+ local TargetCoordinate = ( self.Detection and self.Detection:GetDetectedItemCoordinate( self.DetectedItemIndex ) ) or self.TargetSetUnit:GetFirst():GetCoordinate()
self:SetInfo( "Coordinates", TargetCoordinate, 0 )
-
+
local ThreatLevel, ThreatText
if self.Detection then
ThreatLevel, ThreatText = self.Detection:GetDetectedItemThreatLevel( self.DetectedItemIndex )
@@ -661,8 +663,10 @@ do -- TASK_A2G_CAS
end
- function TASK_A2G_CAS:ReportOrder( ReportGroup )
- local Coordinate = self.TaskInfo.Coordinates.TaskInfoText
+ --- @param #TASK_A2G_CAS self
+ function TASK_A2G_CAS:ReportOrder( ReportGroup )
+
+ local Coordinate = self:GetInfo( "Coordinates" )
local Distance = ReportGroup:GetCoordinate():Get2DDistance( Coordinate )
return Distance
diff --git a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua
index 8857bb4ce..7613d7cad 100644
--- a/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua
+++ b/Moose Development/Moose/Tasking/Task_A2G_Dispatcher.lua
@@ -372,6 +372,7 @@ do -- TASK_A2G_DISPATCHER
self.Tasks[TaskIndex] = Task
Task:SetTargetZone( DetectedZone )
Task:SetDispatcher( self )
+ Task:UpdateTaskInfo()
Mission:AddTask( Task )
TaskReport:Add( Task:GetName() )
diff --git a/Moose Development/Moose/Wrapper/Group.lua b/Moose Development/Moose/Wrapper/Group.lua
index 5b4bc4169..1089224be 100644
--- a/Moose Development/Moose/Wrapper/Group.lua
+++ b/Moose Development/Moose/Wrapper/Group.lua
@@ -1161,9 +1161,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
diff --git a/Moose Development/Moose/Wrapper/Positionable.lua b/Moose Development/Moose/Wrapper/Positionable.lua
index ec24b47ed..592508733 100644
--- a/Moose Development/Moose/Wrapper/Positionable.lua
+++ b/Moose Development/Moose/Wrapper/Positionable.lua
@@ -635,7 +635,7 @@ function POSITIONABLE:MessageToSetGroup( Message, Duration, MessageSetGroup, Nam
if DCSObject:isExist() then
MessageSetGroup:ForEachGroup(
function( MessageGroup )
- self:GetMessageType( Message, Duration, Name ):ToGroup( MessageGroup )
+ self:GetMessage( Message, Duration, Name ):ToGroup( MessageGroup )
end
)
end
diff --git a/Utils/DCS_ControlAPI.txt b/Utils/DCS_ControlAPI.txt
new file mode 100644
index 000000000..a0650d801
--- /dev/null
+++ b/Utils/DCS_ControlAPI.txt
@@ -0,0 +1,565 @@
+DCS Simulation Control User Scripts
+====================================
+
+The behaviour of the DCS can be altered using the *GameGUI.lua scripts.
+You define the hooks to the DCS events, and then do what you want using the provided API.
+===================================================================================================
+
+When loading, DCS searches for Saved Games\DCS\Scripts\*GameGUI.lua files,
+sorts them by name and then loads into the GUI Lua-state.
+Each user script is loaded into an isolated environment, so the only
+thing they share is the state of the simulator.
+
+Each script defines a set of callbacks to the DCS events and sets them with the call
+ DCS.setUserCallbacks(cb_table)
+For each callback type the hooks of all user scripts will be called in order of loading.
+
+For callbacks which are supposed to returning a value, currently there are 3 of them:
+ onPlayerTryConnect
+ onPlayerTrySendChat
+ onPlayerTryChangeSlot
+returning a value means breaking the hook call chain.
+Returning nothing (or nil) means continuing the hook chain, which ends with the default allow-all handlers.
+
+The example user script 'testGameGUI.lua':
+----------------------------------------------------------------------------------------------
+local test = {}
+
+function test.onPlayerTryConnect(ipaddr, name, ucid, playerID)
+ print('onPlayerTryConnect(%s, %s, %s, %d)', ipaddr, name, ucid, playerID)
+ -- if you want to gently intercept the call, allowing other user scripts to get it,
+ -- you better return nothing here
+ return true -- allow the player to connect
+end
+
+function test.onSimulationStart()
+ print('Current mission is '..DCS.getMissionName())
+end
+
+DCS.setUserCallbacks(test) -- here we set our callbacks
+----------------------------------------------------------------------------------------------
+
+
+The available API are documented below.
+The full list of the callbacks is at the end of this document.
+
+In addition, all standard lua 5.1 libraries are available as well, namely:
+base api, like print, etc,
+math.*
+table.*
+string.*
+io.*
+os.*
+debug.*
+
+===================================================================================================
+
+
+
+Lua File System (lfs) API
+-------------------------------
+lfs.currentdir() -> string
+ Returns the path of the DCS install folder
+
+lfs.writedir() -> string
+ Returns the path of the current 'Saved Games\DCS' folder.
+
+lfs.tempdir() -> string
+ Returns the pat of the DCS Temp folder (AppData\Local\Temp\DCS).
+
+lfs.mkdir()
+lfs.rmdir()
+lfs.attributes()
+lfs.dir()
+lfs.normpath()
+lfs.realpath()
+
+
+
+DCS Control API, table 'DCS.*'
+-------------------------------
+
+DCS.setPause(bool)
+ Pauses/resumes the simulation. Server-side only.
+
+DCS.getPause() -> bool
+ true if simulation is paused
+
+DCS.stopMission()
+ stops current mission
+
+DCS.exitProcess()
+ Exits the DCS process.
+
+DCS.isMultiplayer() -> bool
+ True when running in the multiplayer mode.
+
+DCS.isServer() -> bool
+ True when running as a server or in the single-player mode.
+
+DCS.getModelTime() -> number
+ returns current DCS simulation time in seconds.
+
+DCS.getRealTime() -> number
+ returns current DCS real time in seconds relative to the DCS start time.
+
+DCS.getMissionOptions() -> table
+ Returns the value of 'mission.options'
+
+DCS.getMissionDescription() -> string
+ translated mission.descriptionText string
+
+DCS.getAvailableCoalitions() -> table {
+ [coalition_id] = { name = "coalition name", }
+ ...
+}
+ Returns a list of coalitions which have available slots.
+
+DCS.getAvailableSlots(coalitionID) -> array of {unitId, type, role, callsign, groupName, country}
+ Returns the list of available slots.
+ NOTE: the returned unitID is actually a slotID, which for multi-seat units is 'unitID_seatID'
+
+DCS.getCurrentMission() -> table with the currently loaded mission
+ NOTE: to get valid mission.options use DCS.getMissionOptions()
+
+DCS.getMissionName() -> string
+ Returns the name of the current mission
+
+DCS.getMissionFilename() -> string
+ Returns the file name of the current mission (returns nil when acting as a multiplayer client).
+
+DCS.getMissionResult(string side) -> integer [0, 100]
+ Gets missin result for either 'red' or 'blue'
+
+DCS.getUnitProperty(missionId, propertyId) -> string
+ propertyId:
+ DCS.UNIT_RUNTIME_ID, // unique within runtime mission. int
+ DCS.UNIT_MISSION_ID, // unique within mission file. int>0
+ DCS.UNIT_NAME, // unit name, as assigned by mission designer.
+ DCS.UNIT_TYPE, // unit type (Ural, ZU-23, etc)
+ DCS.UNIT_CATEGORY,
+ DCS.UNIT_GROUP_MISSION_ID, // group ID, unique within mission file. int>0
+ DCS.UNIT_GROUPNAME, // group name, as assigned by mission designer.
+ DCS.UNIT_GROUPCATEGORY,
+ DCS.UNIT_CALLSIGN,
+ DCS.UNIT_HIDDEN,// ME hiding
+ DCS.UNIT_COALITION,// "blue", "red" or "unknown"
+ DCS.UNIT_COUNTRY_ID,
+ DCS.UNIT_TASK, //"unit.group.task"
+ DCS.UNIT_PLAYER_NAME, // valid for network "humanable" units
+ DCS.UNIT_ROLE,//"artillery_commander", "instructor", etc
+ DCS.UNIT_INVISIBLE_MAP_ICON,//ME invisible map icon
+
+DCS.getUnitType(missionId) -> typeId
+ a shortcut for DCS.getUnitProperty(missionId, DCS.UNIT_TYPE)
+
+DCS.getUnitTypeAttribute(typeId, attr) -> string
+ Returns a value from Database: Objects[typeId][attr],
+ for example DCS.getUnitTypeAttribute("Ural", "DisplayName")
+
+DCS.writeDebriefing(str)
+ Writes a custom string to the debriefing file
+
+DCS.setUserCallbacks(cb_table)
+ Hooks the callbacks using the handlers from the provided table.
+ See: "GameGUI scripts" section.
+
+
+
+Logging API 'log.*'
+------------------------
+Logging works as follows:
+a) each log message is accompanied with 2 attributes: a subsystem, and level.
+b) after each messages gets into a logger it passes (asynchronously) through
+ a series of output filters which decide where the message will be written to.
+
+Writing to log is done by:
+
+log.write(SUBSYSTEM_NAME, LOG_LEVEL, message, ...)
+ if there are any arguments after 'message',
+ the actual string is formed as string.format(message, ...)
+
+ SUBSYSTEM_NAME is a string
+ LOG_LEVEL is one of the values, listed below
+ see log.set_output()
+
+log.set_output(log_file_name_wo_ext, rule_subsystem_name, rule_level_mask, rule_output_mode)
+
+ the args:
+ log_file_name_wo_ext: resulting log will be written to $WRITE_DIR/Logs/
Contains the counter how many units are currently alive
-Don't repeat the group from Take-Off till Landing and back Take-Off by ReSpawning.
+By default, no InitLimit
+When the first Spawn executes, all the Groups need to be made visible before start.
+Flag that indicates if all the Groups of the SpawnGroup need to be visible when Spawned.