mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
- Bugfix when enemy plane has crashed, AttackerDetection is not existing anymore.
Implemented an important fix. Refuel airplanes also when they are engaging targets and the fuel treshold has been reached. - Inherit ZONE_BASE from FSM instead of BASE. Opens a range of possibilities. - Remove from ZONE_GOAL the Zone field, and make it inherit from ZONE_BASE instead of FSM! - Rework the new inheritance tree in the code. (Remove .Zone fields). - Implement the determination of attack and defense zones. - Reworked the TaskInfo to include Type and ShowKey. - Flash A2G Tasking Details. Added menu option.
This commit is contained in:
commit
c0771c0096
@ -278,6 +278,8 @@ function AI_A2A_CAP:New( AICap, PatrolZone, PatrolFloorAltitude, PatrolCeilingAl
|
||||
-- @param #AI_A2A_CAP self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
self:AddTransition( { "Patrolling", "Engaging" }, "Refuel", "Refuelling" )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@ -279,6 +279,8 @@ function AI_A2A_GCI:New( AIIntercept, EngageMinSpeed, EngageMaxSpeed )
|
||||
-- @param #AI_A2A_GCI self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
self:AddTransition( { "Patrolling", "Engaging" }, "Refuel", "Refuelling" )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@ -62,12 +62,14 @@ end
|
||||
-- @param #string To The To State string.
|
||||
function AI_A2G_BAI:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit )
|
||||
|
||||
self:F( { DefenderGroup, From, Event, To, AttackSetUnit} )
|
||||
self:I( { DefenderGroup, From, Event, To, AttackSetUnit} )
|
||||
|
||||
local DefenderGroupName = DefenderGroup:GetName()
|
||||
|
||||
local AttackCount = AttackSetUnit:Count()
|
||||
|
||||
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
|
||||
|
||||
if AttackCount > 0 then
|
||||
|
||||
if DefenderGroup:IsAlive() then
|
||||
@ -151,3 +153,14 @@ function AI_A2G_BAI:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit
|
||||
self:__RTB( self.TaskDelay )
|
||||
end
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIEngage
|
||||
function AI_A2G_BAI.Resume( AIEngage, Fsm )
|
||||
|
||||
AIEngage:F( { "AI_A2G_BAI.Resume:", AIEngage:GetName() } )
|
||||
if AIEngage:IsAlive() then
|
||||
Fsm:__Reset( Fsm.TaskDelay )
|
||||
Fsm:__EngageRoute( Fsm.TaskDelay, Fsm.AttackSetUnit )
|
||||
end
|
||||
|
||||
end
|
||||
@ -66,6 +66,8 @@ function AI_A2G_CAS:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit
|
||||
|
||||
local DefenderGroupName = DefenderGroup:GetName()
|
||||
|
||||
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
|
||||
|
||||
local AttackCount = AttackSetUnit:Count()
|
||||
|
||||
if AttackCount > 0 then
|
||||
@ -148,3 +150,13 @@ function AI_A2G_CAS:onafterEngage( DefenderGroup, From, Event, To, AttackSetUnit
|
||||
end
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIEngage
|
||||
function AI_A2G_CAS.Resume( AIEngage, Fsm )
|
||||
|
||||
AIEngage:F( { "AI_A2G_CAS.Resume:", AIEngage:GetName() } )
|
||||
if AIEngage:IsAlive() then
|
||||
Fsm:__Reset( Fsm.TaskDelay )
|
||||
Fsm:__EngageRoute( Fsm.TaskDelay, Fsm.AttackSetUnit )
|
||||
end
|
||||
|
||||
end
|
||||
@ -4043,6 +4043,107 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
return ShortestDistance
|
||||
end
|
||||
|
||||
--- Shows the tactical display.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
function AI_A2G_DISPATCHER:ShowTacticalDisplay( Detection )
|
||||
|
||||
local AreaMsg = {}
|
||||
local TaskMsg = {}
|
||||
local ChangeMsg = {}
|
||||
|
||||
local TaskReport = REPORT:New()
|
||||
|
||||
local DefenseTotal = 0
|
||||
|
||||
local Report = REPORT:New( "\nTactical Overview" )
|
||||
|
||||
local DefenderGroupCount = 0
|
||||
local DefendersTotal = 0
|
||||
|
||||
-- Now that all obsolete tasks are removed, loop through the detected targets.
|
||||
--for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do
|
||||
for DetectedItemID, DetectedItem in UTILS.spairs( Detection:GetDetectedItems(), function( t, a, b ) return self:Order(t[a]) < self:Order(t[b]) end ) do
|
||||
|
||||
if not self.Detection:IsDetectedItemLocked( DetectedItem ) == true then
|
||||
local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem
|
||||
local DetectedSet = DetectedItem.Set -- Core.Set#SET_UNIT
|
||||
local DetectedCount = DetectedSet:Count()
|
||||
local DetectedZone = DetectedItem.Zone
|
||||
|
||||
self:F( { "Target ID", DetectedItem.ItemID } )
|
||||
|
||||
self:F( { DefenseLimit = self.DefenseLimit, DefenseTotal = DefenseTotal } )
|
||||
DetectedSet:Flush( self )
|
||||
|
||||
local DetectedID = DetectedItem.ID
|
||||
local DetectionIndex = DetectedItem.Index
|
||||
local DetectedItemChanged = DetectedItem.Changed
|
||||
|
||||
-- Show tactical situation
|
||||
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
|
||||
Report:Add( string.format( " - %1s%s ( %4s ): ( #%d - %4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) )
|
||||
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
||||
local Defender = Defender -- Wrapper.Group#GROUP
|
||||
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
||||
if Defender:IsAlive() then
|
||||
DefenderGroupCount = DefenderGroupCount + 1
|
||||
local Fuel = Defender:GetFuelMin() * 100
|
||||
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
|
||||
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
|
||||
Defender:GetName(),
|
||||
DefenderTask.Type,
|
||||
DefenderTask.Fsm:GetState(),
|
||||
Defender:GetSize(),
|
||||
Fuel,
|
||||
Damage,
|
||||
Defender:HasTask() == true and "Executing" or "Idle" ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Report:Add( "\n - No Targets:")
|
||||
local TaskCount = 0
|
||||
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
||||
TaskCount = TaskCount + 1
|
||||
local Defender = Defender -- Wrapper.Group#GROUP
|
||||
if not DefenderTask.Target then
|
||||
if Defender:IsAlive() then
|
||||
local DefenderHasTask = Defender:HasTask()
|
||||
local Fuel = Defender:GetFuelMin() * 100
|
||||
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
|
||||
DefenderGroupCount = DefenderGroupCount + 1
|
||||
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
|
||||
Defender:GetName(),
|
||||
DefenderTask.Type,
|
||||
DefenderTask.Fsm:GetState(),
|
||||
Defender:GetSize(),
|
||||
Fuel,
|
||||
Damage,
|
||||
Defender:HasTask() == true and "Executing" or "Idle" ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
Report:Add( string.format( "\n - %d Tasks - %d Defender Groups", TaskCount, DefenderGroupCount ) )
|
||||
|
||||
Report:Add( string.format( "\n - %d Queued Aircraft Launches", #self.DefenseQueue ) )
|
||||
for DefenseQueueID, DefenseQueueItem in pairs( self.DefenseQueue ) do
|
||||
local DefenseQueueItem = DefenseQueueItem -- #AI_A2G_DISPATCHER.DefenseQueueItem
|
||||
Report:Add( string.format( " - %s - %s", DefenseQueueItem.SquadronName, DefenseQueueItem.DefenderSquadron.TakeoffTime, DefenseQueueItem.DefenderSquadron.TakeoffInterval) )
|
||||
|
||||
end
|
||||
|
||||
Report:Add( string.format( "\n - Squadron Resources: ", #self.DefenseQueue ) )
|
||||
for DefenderSquadronName, DefenderSquadron in pairs( self.DefenderSquadrons ) do
|
||||
Report:Add( string.format( " - %s - %d", DefenderSquadronName, DefenderSquadron.ResourceCount and DefenderSquadron.ResourceCount or "n/a" ) )
|
||||
end
|
||||
|
||||
self:F( Report:Text( "\n" ) )
|
||||
trigger.action.outText( Report:Text( "\n" ), 25 )
|
||||
|
||||
end
|
||||
|
||||
--- Assigns A2G AI Tasks in relation to the detected items.
|
||||
-- @param #AI_A2G_DISPATCHER self
|
||||
@ -4191,7 +4292,7 @@ do -- AI_A2G_DISPATCHER
|
||||
|
||||
for DefenseQueueID, DefenseQueueItem in pairs( self.DefenseQueue ) do
|
||||
local DefenseQueueItem = DefenseQueueItem -- #AI_A2G_DISPATCHER.DefenseQueueItem
|
||||
if DefenseQueueItem.AttackerDetection.Index == DetectedItem.Index then
|
||||
if DefenseQueueItem.AttackerDetection and DefenseQueueItem.AttackerDetection.Index and DefenseQueueItem.AttackerDetection.Index == DetectedItem.Index then
|
||||
DefenseTotal = DefenseTotal + 1
|
||||
end
|
||||
end
|
||||
|
||||
@ -304,6 +304,8 @@ function AI_A2G_ENGAGE:New( AIGroup, EngageMinSpeed, EngageMaxSpeed, EngageFloor
|
||||
-- @param #AI_A2G_ENGAGE self
|
||||
-- @param #number Delay The delay in seconds.
|
||||
|
||||
self:AddTransition( { "Patrolling", "Engaging" }, "Refuel", "Refuelling" )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@ -389,17 +391,6 @@ function AI_A2G_ENGAGE:onafterAbort( AIGroup, From, Event, To )
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_A2G_ENGAGE self
|
||||
-- @param Wrapper.Group#GROUP DefenderGroup The GroupGroup managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
-- @param #string Event The Event string.
|
||||
-- @param #string To The To State string.
|
||||
function AI_A2G_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, AttackSetUnit )
|
||||
|
||||
self:F( { DefenderGroup, From, Event, To, AttackSetUnit} )
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_A2G_ENGAGE self
|
||||
-- @param Wrapper.Group#GROUP AIGroup The Group Object managed by the FSM.
|
||||
-- @param #string From The From State string.
|
||||
@ -446,6 +437,8 @@ function AI_A2G_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
||||
|
||||
local DefenderGroupName = DefenderGroup:GetName()
|
||||
|
||||
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
|
||||
|
||||
local AttackCount = AttackSetUnit:Count()
|
||||
|
||||
if AttackCount > 0 then
|
||||
@ -517,4 +510,5 @@ function AI_A2G_ENGAGE:onafterEngageRoute( DefenderGroup, From, Event, To, Attac
|
||||
self:Return()
|
||||
self:__RTB( self.TaskDelay )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -316,8 +316,8 @@ function AI_A2G_PATROL.Resume( AIPatrol, Fsm )
|
||||
|
||||
AIPatrol:F( { "AI_A2G_PATROL.Resume:", AIPatrol:GetName() } )
|
||||
if AIPatrol:IsAlive() then
|
||||
Fsm:__Reset( self.TaskDelay )
|
||||
Fsm:__PatrolRoute( self.TaskDelay )
|
||||
Fsm:__Reset( Fsm.TaskDelay )
|
||||
Fsm:__PatrolRoute( Fsm.TaskDelay )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -117,6 +117,8 @@ function AI_A2G_SEAD:onafterEngage( DefenderGroup, From, Event, To, AttackSetUni
|
||||
|
||||
local DefenderGroupName = DefenderGroup:GetName()
|
||||
|
||||
self.AttackSetUnit = AttackSetUnit -- Kept in memory in case of resume from refuel in air!
|
||||
|
||||
local AttackCount = AttackSetUnit:Count()
|
||||
|
||||
if AttackCount > 0 then
|
||||
@ -206,3 +208,13 @@ function AI_A2G_SEAD:onafterEngage( DefenderGroup, From, Event, To, AttackSetUni
|
||||
end
|
||||
end
|
||||
|
||||
--- @param Wrapper.Group#GROUP AIEngage
|
||||
function AI_A2G_SEAD.Resume( AIEngage, Fsm )
|
||||
|
||||
AIEngage:F( { "AI_A2G_SEAD.Resume:", AIEngage:GetName() } )
|
||||
if AIEngage:IsAlive() then
|
||||
Fsm:__Reset( Fsm.TaskDelay )
|
||||
Fsm:__EngageRoute( Fsm.TaskDelay, Fsm.AttackSetUnit )
|
||||
end
|
||||
|
||||
end
|
||||
@ -461,7 +461,7 @@ function AI_AIR:onafterStatus()
|
||||
-- end
|
||||
|
||||
|
||||
if not self:Is( "Fuel" ) and not self:Is( "Home" ) then
|
||||
if not self:Is( "Fuel" ) and not self:Is( "Home" ) and not self:is( "Refuelling" )then
|
||||
|
||||
local Fuel = self.Controllable:GetFuelMin()
|
||||
|
||||
@ -680,12 +680,14 @@ end
|
||||
function AI_AIR: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
|
||||
|
||||
self:E( "Group " .. self.Controllable:GetName() .. " ... Refuelling! ( " .. self:GetState() .. "), at tanker " .. self.TankerName )
|
||||
|
||||
local RefuelRoute = {}
|
||||
|
||||
--- Calculate the target route point.
|
||||
|
||||
@ -81,6 +81,7 @@ DATABASE = {
|
||||
HITS = {},
|
||||
DESTROYS = {},
|
||||
ZONES = {},
|
||||
ZONES_GOAL = {},
|
||||
}
|
||||
|
||||
local _DATABASECoalition =
|
||||
@ -338,6 +339,39 @@ do -- Zones
|
||||
|
||||
end -- zone
|
||||
|
||||
do -- Zone_Goal
|
||||
|
||||
--- Finds a @{Zone} based on the zone name.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
-- @return Core.Zone#ZONE_BASE The found ZONE.
|
||||
function DATABASE:FindZoneGoal( ZoneName )
|
||||
|
||||
local ZoneFound = self.ZONES_GOAL[ZoneName]
|
||||
return ZoneFound
|
||||
end
|
||||
|
||||
--- Adds a @{Zone} based on the zone name in the DATABASE.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
-- @param Core.Zone#ZONE_BASE Zone The zone.
|
||||
function DATABASE:AddZoneGoal( ZoneName, Zone )
|
||||
|
||||
if not self.ZONES_GOAL[ZoneName] then
|
||||
self.ZONES_GOAL[ZoneName] = Zone
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Deletes a @{Zone} from the DATABASE based on the zone name.
|
||||
-- @param #DATABASE self
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
function DATABASE:DeleteZoneGoal( ZoneName )
|
||||
|
||||
self.ZONES_GOAL[ZoneName] = nil
|
||||
end
|
||||
|
||||
end -- Zone_Goal
|
||||
do -- cargo
|
||||
|
||||
--- Adds a Cargo based on the Cargo Name in the DATABASE.
|
||||
|
||||
@ -189,7 +189,9 @@ world.event.S_EVENT_NEW_CARGO = world.event.S_EVENT_MAX + 1000
|
||||
world.event.S_EVENT_DELETE_CARGO = world.event.S_EVENT_MAX + 1001
|
||||
world.event.S_EVENT_NEW_ZONE = world.event.S_EVENT_MAX + 1002
|
||||
world.event.S_EVENT_DELETE_ZONE = world.event.S_EVENT_MAX + 1003
|
||||
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1004
|
||||
world.event.S_EVENT_NEW_ZONE_GOAL = world.event.S_EVENT_MAX + 1004
|
||||
world.event.S_EVENT_DELETE_ZONE_GOAL = world.event.S_EVENT_MAX + 1005
|
||||
world.event.S_EVENT_REMOVE_UNIT = world.event.S_EVENT_MAX + 1006
|
||||
|
||||
|
||||
--- The different types of events supported by MOOSE.
|
||||
@ -226,6 +228,8 @@ EVENTS = {
|
||||
DeleteCargo = world.event.S_EVENT_DELETE_CARGO,
|
||||
NewZone = world.event.S_EVENT_NEW_ZONE,
|
||||
DeleteZone = world.event.S_EVENT_DELETE_ZONE,
|
||||
NewZoneGoal = world.event.S_EVENT_NEW_ZONE_GOAL,
|
||||
DeleteZoneGoal = world.event.S_EVENT_DELETE_ZONE_GOAL,
|
||||
RemoveUnit = world.event.S_EVENT_REMOVE_UNIT,
|
||||
}
|
||||
|
||||
@ -462,6 +466,16 @@ local _EVENTMETA = {
|
||||
Event = "OnEventDeleteZone",
|
||||
Text = "S_EVENT_DELETE_ZONE"
|
||||
},
|
||||
[EVENTS.NewZoneGoal] = {
|
||||
Order = 1,
|
||||
Event = "OnEventNewZoneGoal",
|
||||
Text = "S_EVENT_NEW_ZONE_GOAL"
|
||||
},
|
||||
[EVENTS.DeleteZoneGoal] = {
|
||||
Order = 1,
|
||||
Event = "OnEventDeleteZoneGoal",
|
||||
Text = "S_EVENT_DELETE_ZONE_GOAL"
|
||||
},
|
||||
[EVENTS.RemoveUnit] = {
|
||||
Order = -1,
|
||||
Event = "OnEventRemoveUnit",
|
||||
@ -800,6 +814,38 @@ do -- Event Creation
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
--- Creation of a New ZoneGoal Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Core.Functional#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||
function EVENT:CreateEventNewZoneGoal( ZoneGoal )
|
||||
self:F( { ZoneGoal } )
|
||||
|
||||
local Event = {
|
||||
id = EVENTS.NewZoneGoal,
|
||||
time = timer.getTime(),
|
||||
ZoneGoal = ZoneGoal,
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
|
||||
--- Creation of a ZoneGoal Deletion Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Core.ZoneGoal#ZONE_GOAL ZoneGoal The ZoneGoal created.
|
||||
function EVENT:CreateEventDeleteZoneGoal( ZoneGoal )
|
||||
self:F( { ZoneGoal } )
|
||||
|
||||
local Event = {
|
||||
id = EVENTS.DeleteZoneGoal,
|
||||
time = timer.getTime(),
|
||||
ZoneGoal = ZoneGoal,
|
||||
}
|
||||
|
||||
world.onEvent( Event )
|
||||
end
|
||||
|
||||
|
||||
--- Creation of a S_EVENT_PLAYER_ENTER_UNIT Event.
|
||||
-- @param #EVENT self
|
||||
-- @param Wrapper.Unit#UNIT PlayerUnit.
|
||||
|
||||
@ -5497,4 +5497,324 @@ do -- SET_ZONE
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
do -- SET_ZONE_GOAL
|
||||
|
||||
--- @type SET_ZONE_GOAL
|
||||
-- @extends Core.Set#SET_BASE
|
||||
|
||||
--- Mission designers can use the @{Core.Set#SET_ZONE_GOAL} class to build sets of zones of various types.
|
||||
--
|
||||
-- ## SET_ZONE_GOAL constructor
|
||||
--
|
||||
-- Create a new SET_ZONE_GOAL object with the @{#SET_ZONE_GOAL.New} method:
|
||||
--
|
||||
-- * @{#SET_ZONE_GOAL.New}: Creates a new SET_ZONE_GOAL object.
|
||||
--
|
||||
-- ## Add or Remove ZONEs from SET_ZONE_GOAL
|
||||
--
|
||||
-- ZONEs can be added and removed using the @{Core.Set#SET_ZONE_GOAL.AddZonesByName} and @{Core.Set#SET_ZONE_GOAL.RemoveZonesByName} respectively.
|
||||
-- These methods take a single ZONE name or an array of ZONE names to be added or removed from SET_ZONE_GOAL.
|
||||
--
|
||||
-- ## SET_ZONE_GOAL filter criteria
|
||||
--
|
||||
-- You can set filter criteria to build the collection of zones in SET_ZONE_GOAL.
|
||||
-- Filter criteria are defined by:
|
||||
--
|
||||
-- * @{#SET_ZONE_GOAL.FilterPrefixes}: Builds the SET_ZONE_GOAL with the zones having a certain text pattern of prefix.
|
||||
--
|
||||
-- Once the filter criteria have been set for the SET_ZONE_GOAL, you can start filtering using:
|
||||
--
|
||||
-- * @{#SET_ZONE_GOAL.FilterStart}: Starts the filtering of the zones within the SET_ZONE_GOAL.
|
||||
--
|
||||
-- ## SET_ZONE_GOAL iterators
|
||||
--
|
||||
-- Once the filters have been defined and the SET_ZONE_GOAL has been built, you can iterate the SET_ZONE_GOAL with the available iterator methods.
|
||||
-- The iterator methods will walk the SET_ZONE_GOAL set, and call for each airbase within the set a function that you provide.
|
||||
-- The following iterator methods are currently available within the SET_ZONE_GOAL:
|
||||
--
|
||||
-- * @{#SET_ZONE_GOAL.ForEachZone}: Calls a function for each zone it finds within the SET_ZONE_GOAL.
|
||||
--
|
||||
-- ===
|
||||
-- @field #SET_ZONE_GOAL SET_ZONE_GOAL
|
||||
SET_ZONE_GOAL = {
|
||||
ClassName = "SET_ZONE_GOAL",
|
||||
Zones = {},
|
||||
Filter = {
|
||||
Prefixes = nil,
|
||||
},
|
||||
FilterMeta = {
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
--- Creates a new SET_ZONE_GOAL object, building a set of zones.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
-- @usage
|
||||
-- -- Define a new SET_ZONE_GOAL Object. The DatabaseSet will contain a reference to all Zones.
|
||||
-- DatabaseSet = SET_ZONE_GOAL:New()
|
||||
function SET_ZONE_GOAL:New()
|
||||
-- Inherits from BASE
|
||||
local self = BASE:Inherit( self, SET_BASE:New( _DATABASE.ZONES_GOAL ) )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add ZONEs to SET_ZONE_GOAL.
|
||||
-- @param Core.Set#SET_ZONE_GOAL self
|
||||
-- @param Core.Zone#ZONE_BASE Zone A ZONE_BASE object.
|
||||
-- @return self
|
||||
function SET_ZONE_GOAL:AddZone( Zone )
|
||||
|
||||
self:Add( Zone:GetName(), Zone )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Remove ZONEs from SET_ZONE_GOAL.
|
||||
-- @param Core.Set#SET_ZONE_GOAL self
|
||||
-- @param Core.Zone#ZONE_BASE RemoveZoneNames A single name or an array of ZONE_BASE names.
|
||||
-- @return self
|
||||
function SET_ZONE_GOAL:RemoveZonesByName( RemoveZoneNames )
|
||||
|
||||
local RemoveZoneNamesArray = ( type( RemoveZoneNames ) == "table" ) and RemoveZoneNames or { RemoveZoneNames }
|
||||
|
||||
for RemoveZoneID, RemoveZoneName in pairs( RemoveZoneNamesArray ) do
|
||||
self:Remove( RemoveZoneName )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Finds a Zone based on the Zone Name.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param #string ZoneName
|
||||
-- @return Core.Zone#ZONE_BASE The found Zone.
|
||||
function SET_ZONE_GOAL:FindZone( ZoneName )
|
||||
|
||||
local ZoneFound = self.Set[ZoneName]
|
||||
return ZoneFound
|
||||
end
|
||||
|
||||
|
||||
--- Get a random zone from the set.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @return Core.Zone#ZONE_BASE The random Zone.
|
||||
-- @return #nil if no zone in the collection.
|
||||
function SET_ZONE_GOAL:GetRandomZone()
|
||||
|
||||
if self:Count() ~= 0 then
|
||||
|
||||
local Index = self.Index
|
||||
local ZoneFound = nil -- Core.Zone#ZONE_BASE
|
||||
|
||||
-- Loop until a zone has been found.
|
||||
-- The :GetZoneMaybe() call will evaluate the probability for the zone to be selected.
|
||||
-- If the zone is not selected, then nil is returned by :GetZoneMaybe() and the loop continues!
|
||||
while not ZoneFound do
|
||||
local ZoneRandom = math.random( 1, #Index )
|
||||
ZoneFound = self.Set[Index[ZoneRandom]]:GetZoneMaybe()
|
||||
end
|
||||
|
||||
return ZoneFound
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--- Set a zone probability.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param #string ZoneName The name of the zone.
|
||||
function SET_ZONE_GOAL:SetZoneProbability( ZoneName, ZoneProbability )
|
||||
local Zone = self:FindZone( ZoneName )
|
||||
Zone:SetZoneProbability( ZoneProbability )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Builds a set of zones of defined zone prefixes.
|
||||
-- All the zones starting with the given prefixes will be included within the set.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param #string Prefixes The prefix of which the zone name starts with.
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
function SET_ZONE_GOAL:FilterPrefixes( Prefixes )
|
||||
if not self.Filter.Prefixes then
|
||||
self.Filter.Prefixes = {}
|
||||
end
|
||||
if type( Prefixes ) ~= "table" then
|
||||
Prefixes = { Prefixes }
|
||||
end
|
||||
for PrefixID, Prefix in pairs( Prefixes ) do
|
||||
self.Filter.Prefixes[Prefix] = Prefix
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Starts the filtering.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
function SET_ZONE_GOAL:FilterStart()
|
||||
|
||||
if _DATABASE then
|
||||
|
||||
-- We initialize the first set.
|
||||
for ObjectName, Object in pairs( self.Database ) do
|
||||
if self:IsIncludeObject( Object ) then
|
||||
self:Add( ObjectName, Object )
|
||||
else
|
||||
self:RemoveZonesByName( ObjectName )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:HandleEvent( EVENTS.NewZoneGoal )
|
||||
self:HandleEvent( EVENTS.DeleteZoneGoal )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Stops the filtering for the defined collection.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
function SET_ZONE_GOAL:FilterStop()
|
||||
|
||||
self:UnHandleEvent( EVENTS.NewZoneGoal )
|
||||
self:UnHandleEvent( EVENTS.DeleteZoneGoal )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Handles the Database to check on an event (birth) that the Object was added in the Database.
|
||||
-- This is required, because sometimes the _DATABASE birth event gets called later than the SET_BASE birth event!
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
-- @return #string The name of the AIRBASE
|
||||
-- @return #table The AIRBASE
|
||||
function SET_ZONE_GOAL:AddInDatabase( Event )
|
||||
self:F3( { Event } )
|
||||
|
||||
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
|
||||
end
|
||||
|
||||
--- Handles the Database to check on any event that Object exists in the Database.
|
||||
-- This is required, because sometimes the _DATABASE event gets called later than the SET_BASE event or vise versa!
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param Core.Event#EVENTDATA Event
|
||||
-- @return #string The name of the AIRBASE
|
||||
-- @return #table The AIRBASE
|
||||
function SET_ZONE_GOAL:FindInDatabase( Event )
|
||||
self:F3( { Event } )
|
||||
|
||||
return Event.IniDCSUnitName, self.Database[Event.IniDCSUnitName]
|
||||
end
|
||||
|
||||
--- Iterate the SET_ZONE_GOAL and call an interator function for each ZONE, providing the ZONE and optional parameters.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param #function IteratorFunction The function that will be called when there is an alive ZONE in the SET_ZONE_GOAL. The function needs to accept a AIRBASE parameter.
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
function SET_ZONE_GOAL:ForEachZone( IteratorFunction, ... )
|
||||
self:F2( arg )
|
||||
|
||||
self:ForEach( IteratorFunction, arg, self:GetSet() )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param Core.Zone#ZONE_BASE MZone
|
||||
-- @return #SET_ZONE_GOAL self
|
||||
function SET_ZONE_GOAL:IsIncludeObject( MZone )
|
||||
self:F2( MZone )
|
||||
|
||||
local MZoneInclude = true
|
||||
|
||||
if MZone then
|
||||
local MZoneName = MZone:GetName()
|
||||
|
||||
if self.Filter.Prefixes then
|
||||
local MZonePrefix = false
|
||||
for ZonePrefixId, ZonePrefix in pairs( self.Filter.Prefixes ) do
|
||||
self:T3( { "Prefix:", string.find( MZoneName, ZonePrefix, 1 ), ZonePrefix } )
|
||||
if string.find( MZoneName, ZonePrefix, 1 ) then
|
||||
MZonePrefix = true
|
||||
end
|
||||
end
|
||||
self:T( { "Evaluated Prefix", MZonePrefix } )
|
||||
MZoneInclude = MZoneInclude and MZonePrefix
|
||||
end
|
||||
end
|
||||
|
||||
self:T2( MZoneInclude )
|
||||
return MZoneInclude
|
||||
end
|
||||
|
||||
--- Handles the OnEventNewZone event for the Set.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function SET_ZONE_GOAL:OnEventNewZoneGoal( EventData )
|
||||
|
||||
self:I( { "New Zone Capture Coalition", EventData } )
|
||||
self:I( { "Zone Capture Coalition", EventData.ZoneGoal } )
|
||||
|
||||
if EventData.ZoneGoal then
|
||||
if EventData.ZoneGoal and self:IsIncludeObject( EventData.ZoneGoal ) then
|
||||
self:I( { "Adding Zone Capture Coalition", EventData.ZoneGoal.ZoneName, EventData.ZoneGoal } )
|
||||
self:Add( EventData.ZoneGoal.ZoneName , EventData.ZoneGoal )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Handles the OnDead or OnCrash event for alive units set.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function SET_ZONE_GOAL:OnEventDeleteZoneGoal( EventData ) --R2.1
|
||||
self:F3( { EventData } )
|
||||
|
||||
if EventData.ZoneGoal then
|
||||
local Zone = _DATABASE:FindZone( EventData.ZoneGoal.ZoneName )
|
||||
if Zone and Zone.ZoneName then
|
||||
|
||||
-- When cargo was deleted, it may probably be because of an S_EVENT_DEAD.
|
||||
-- However, in the loading logic, an S_EVENT_DEAD is also generated after a Destroy() call.
|
||||
-- And this is a problem because it will remove all entries from the SET_ZONE_GOALs.
|
||||
-- To prevent this from happening, the Zone object has a flag NoDestroy.
|
||||
-- When true, the SET_ZONE_GOAL won't Remove the Zone object from the set.
|
||||
-- This flag is switched off after the event handlers have been called in the EVENT class.
|
||||
self:F( { ZoneNoDestroy=Zone.NoDestroy } )
|
||||
if Zone.NoDestroy then
|
||||
else
|
||||
self:Remove( Zone.ZoneName )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Validate if a coordinate is in one of the zones in the set.
|
||||
-- Returns the ZONE object where the coordiante is located.
|
||||
-- If zones overlap, the first zone that validates the test is returned.
|
||||
-- @param #SET_ZONE_GOAL self
|
||||
-- @param Core.Point#COORDINATE Coordinate The coordinate to be searched.
|
||||
-- @return Core.Zone#ZONE_BASE The zone that validates the coordinate location.
|
||||
-- @return #nil No zone has been found.
|
||||
function SET_ZONE_GOAL:IsCoordinateInZone( Coordinate )
|
||||
|
||||
for _, Zone in pairs( self:GetSet() ) do
|
||||
local Zone = Zone -- Core.Zone#ZONE_BASE
|
||||
if Zone:IsCoordinateInZone( Coordinate ) then
|
||||
return Zone
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -120,7 +120,7 @@ ZONE_BASE = {
|
||||
-- @param #string ZoneName Name of the zone.
|
||||
-- @return #ZONE_BASE self
|
||||
function ZONE_BASE:New( ZoneName )
|
||||
local self = BASE:Inherit( self, BASE:New() )
|
||||
local self = BASE:Inherit( self, FSM:New() )
|
||||
self:F( ZoneName )
|
||||
|
||||
self.ZoneName = ZoneName
|
||||
|
||||
@ -549,6 +549,9 @@ do -- ZONE_CAPTURE_COALITION
|
||||
-- If it is, then we must move the zone to attack state.
|
||||
self:HandleEvent( EVENTS.Hit, self.OnEventHit )
|
||||
|
||||
-- ZoneGoal objects are added to the _DATABASE.ZONES_GOAL and SET_ZONE_GOAL sets.
|
||||
_EVENTDISPATCHER:CreateEventNewZoneGoal( self )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@ -566,7 +569,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsGuarded()
|
||||
|
||||
local IsGuarded = self.Zone:IsAllInZoneOfCoalition( self.Coalition )
|
||||
local IsGuarded = self:IsAllInZoneOfCoalition( self.Coalition )
|
||||
self:F( { IsGuarded = IsGuarded } )
|
||||
return IsGuarded
|
||||
end
|
||||
@ -574,7 +577,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsEmpty()
|
||||
|
||||
local IsEmpty = self.Zone:IsNoneInZone()
|
||||
local IsEmpty = self:IsNoneInZone()
|
||||
self:F( { IsEmpty = IsEmpty } )
|
||||
return IsEmpty
|
||||
end
|
||||
@ -582,7 +585,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsCaptured()
|
||||
|
||||
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
local IsCaptured = self:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
self:F( { IsCaptured = IsCaptured } )
|
||||
return IsCaptured
|
||||
end
|
||||
@ -590,7 +593,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsAttacked()
|
||||
|
||||
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
local IsAttacked = self:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
self:F( { IsAttacked = IsAttacked } )
|
||||
return IsAttacked
|
||||
end
|
||||
@ -601,7 +604,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
-- @param #ZONE_CAPTURE_COALITION self
|
||||
function ZONE_CAPTURE_COALITION:Mark()
|
||||
|
||||
local Coord = self.Zone:GetCoordinate()
|
||||
local Coord = self:GetCoordinate()
|
||||
local ZoneName = self:GetZoneName()
|
||||
local State = self:GetState()
|
||||
|
||||
@ -640,7 +643,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
--self:GetParent( self ):onenterCaptured()
|
||||
|
||||
local NewCoalition = self.Zone:GetScannedCoalition()
|
||||
local NewCoalition = self:GetScannedCoalition()
|
||||
self:F( { NewCoalition = NewCoalition } )
|
||||
self:SetCoalition( NewCoalition )
|
||||
|
||||
@ -680,7 +683,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsCaptured()
|
||||
|
||||
local IsCaptured = self.Zone:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
local IsCaptured = self:IsAllInZoneOfOtherCoalition( self.Coalition )
|
||||
self:F( { IsCaptured = IsCaptured } )
|
||||
return IsCaptured
|
||||
end
|
||||
@ -688,7 +691,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
|
||||
function ZONE_CAPTURE_COALITION:IsAttacked()
|
||||
|
||||
local IsAttacked = self.Zone:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
local IsAttacked = self:IsSomeInZoneOfCoalition( self.Coalition )
|
||||
self:F( { IsAttacked = IsAttacked } )
|
||||
return IsAttacked
|
||||
end
|
||||
@ -803,7 +806,7 @@ do -- ZONE_CAPTURE_COALITION
|
||||
local UnitHit = EventData.TgtUnit
|
||||
|
||||
if UnitHit then
|
||||
if UnitHit:IsInZone( self.Zone ) then
|
||||
if UnitHit:IsInZone( self ) then
|
||||
self:Attack()
|
||||
end
|
||||
end
|
||||
|
||||
@ -44,14 +44,13 @@ do -- Zone
|
||||
|
||||
--- ZONE_GOAL Constructor.
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param Core.Zone#ZONE_BASE Zone A @{Zone} object with the goal to be achieved.
|
||||
-- @param Core.Zone#ZONE_RADIUS Zone A @{Zone} object with the goal to be achieved.
|
||||
-- @return #ZONE_GOAL
|
||||
function ZONE_GOAL:New( Zone )
|
||||
|
||||
local self = BASE:Inherit( self, FSM:New() ) -- #ZONE_GOAL
|
||||
local self = BASE:Inherit( self, ZONE_RADIUS:New( Zone:GetName(), Zone:GetVec2(), Zone:GetRadius() ) ) -- #ZONE_GOAL
|
||||
self:F( { Zone = Zone } )
|
||||
|
||||
self.Zone = Zone -- Core.Zone#ZONE_BASE
|
||||
self.Goal = GOAL:New()
|
||||
|
||||
self.SmokeTime = nil
|
||||
@ -67,6 +66,7 @@ do -- Zone
|
||||
-- @param Wrapper.Unit#UNIT DestroyedUnit The destroyed unit.
|
||||
-- @param #string PlayerName The name of the player.
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@ -74,7 +74,7 @@ do -- Zone
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @return Core.Zone#ZONE_BASE
|
||||
function ZONE_GOAL:GetZone()
|
||||
return self.Zone
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ do -- Zone
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @return #string
|
||||
function ZONE_GOAL:GetZoneName()
|
||||
return self.Zone:GetName()
|
||||
return self:GetName()
|
||||
end
|
||||
|
||||
|
||||
@ -101,7 +101,7 @@ do -- Zone
|
||||
-- @param #ZONE_GOAL self
|
||||
-- @param #SMOKECOLOR.Color FlareColor
|
||||
function ZONE_GOAL:Flare( FlareColor )
|
||||
self.Zone:FlareZone( FlareColor, math.random( 1, 360 ) )
|
||||
self:FlareZone( FlareColor, math.random( 1, 360 ) )
|
||||
end
|
||||
|
||||
|
||||
@ -130,7 +130,7 @@ do -- Zone
|
||||
|
||||
if self.SmokeTime == nil or self.SmokeTime + 300 <= CurrentTime then
|
||||
if self.SmokeColor then
|
||||
self.Zone:GetCoordinate():Smoke( self.SmokeColor )
|
||||
self:GetCoordinate():Smoke( self.SmokeColor )
|
||||
--self.SmokeColor = nil
|
||||
self.SmokeTime = CurrentTime
|
||||
end
|
||||
@ -147,11 +147,9 @@ do -- Zone
|
||||
|
||||
local Vec3 = EventData.IniDCSUnit:getPosition().p
|
||||
self:F( { Vec3 = Vec3 } )
|
||||
local ZoneGoal = self:GetZone()
|
||||
self:F({ZoneGoal})
|
||||
|
||||
if EventData.IniDCSUnit then
|
||||
if ZoneGoal:IsVec3InZone(Vec3) then
|
||||
if self:IsVec3InZone(Vec3) then
|
||||
local PlayerHits = _DATABASE.HITS[EventData.IniUnitName]
|
||||
if PlayerHits then
|
||||
for PlayerName, PlayerHit in pairs( PlayerHits.Players or {} ) do
|
||||
|
||||
@ -104,7 +104,7 @@ do -- ZoneGoal
|
||||
local State = self:GetState()
|
||||
self:F( { State = self:GetState() } )
|
||||
|
||||
self.Zone:Scan( { Object.Category.UNIT, Object.Category.STATIC } )
|
||||
self:Scan( { Object.Category.UNIT, Object.Category.STATIC } )
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -180,7 +180,7 @@ COMMANDCENTER = {
|
||||
COMMANDCENTER.AutoAssignMethods = {
|
||||
["Random"] = 1,
|
||||
["Distance"] = 2,
|
||||
["Priority"] = 3
|
||||
["Priority"] = 3,
|
||||
}
|
||||
|
||||
--- The constructor takes an IDENTIFIABLE as the HQ command center.
|
||||
|
||||
@ -1111,6 +1111,11 @@ function TASK:SetAssignedMenuForGroup( TaskGroup, MenuTime )
|
||||
end
|
||||
local MarkMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Mark Task Location on Map" ), TaskControl, self.MenuMarkToGroup, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
|
||||
local TaskTypeMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Report Task Details" ), TaskControl, self.MenuTaskStatus, self, TaskGroup ):SetTime( MenuTime ):SetTag( "Tasking" )
|
||||
if not self.FlashTaskStatus then
|
||||
local TaskFlashStatusMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Flash Task Details" ), TaskControl, self.MenuFlashTaskStatus, self, TaskGroup, true ):SetTime( MenuTime ):SetTag( "Tasking" )
|
||||
else
|
||||
local TaskFlashStatusMenu = MENU_GROUP_COMMAND:New( TaskGroup, string.format( "Stop Flash Task Details" ), TaskControl, self.MenuFlashTaskStatus, self, TaskGroup, nil ):SetTime( MenuTime ):SetTag( "Tasking" )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1234,6 +1239,24 @@ function TASK:MenuTaskStatus( TaskGroup )
|
||||
|
||||
end
|
||||
|
||||
--- Report the task status.
|
||||
-- @param #TASK self
|
||||
function TASK:MenuFlashTaskStatus( TaskGroup, Flash )
|
||||
|
||||
self.FlashTaskStatus = Flash
|
||||
|
||||
if self.FlashTaskStatus then
|
||||
self.FlashTaskScheduler, self.FlashTaskScheduleID = SCHEDULER:New( self, self.MenuTaskStatus, { TaskGroup }, 0, 60 )
|
||||
else
|
||||
if self.FlashTaskScheduler then
|
||||
self.FlashTaskScheduler:Stop( self.FlashTaskScheduleID )
|
||||
self.FlashTaskScheduler = nil
|
||||
self.FlashTaskScheduleID = nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Report the task status.
|
||||
-- @param #TASK self
|
||||
function TASK:MenuTaskAbort( TaskGroup )
|
||||
|
||||
@ -52,16 +52,16 @@ end
|
||||
|
||||
--- Add taskinfo.
|
||||
-- @param #TASKINFO self
|
||||
-- @param #string The info key.
|
||||
-- @param #string Key The info key.
|
||||
-- @param Data The data of the info.
|
||||
-- @param #number Order The display order, which is a number from 0 to 100.
|
||||
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||
-- @return #TASKINFO self
|
||||
function TASKINFO:AddInfo( Key, Data, Order, Detail, Keep )
|
||||
self.VolatileInfo:Add( Key, { Data = Data, Order = Order, Detail = Detail } )
|
||||
function TASKINFO:AddInfo( Key, Data, Order, Detail, Keep, ShowKey, Type )
|
||||
self.VolatileInfo:Add( Key, { Data = Data, Order = Order, Detail = Detail, ShowKey = ShowKey, Type = Type } )
|
||||
if Keep == true then
|
||||
self.PersistentInfo:Add( Key, { Data = Data, Order = Order, Detail = Detail } )
|
||||
self.PersistentInfo:Add( Key, { Data = Data, Order = Order, Detail = Detail, ShowKey = ShowKey, Type = Type } )
|
||||
end
|
||||
return self
|
||||
end
|
||||
@ -124,8 +124,8 @@ end
|
||||
-- @param #TASKINFO.Detail Detail The detail Level.
|
||||
-- @param #boolean Keep (optional) If true, this would indicate that the planned taskinfo would be persistent when the task is completed, so that the original planned task info is used at the completed reports.
|
||||
-- @return #TASKINFO self
|
||||
function TASKINFO:AddCoordinate( Coordinate, Order, Detail, Keep )
|
||||
self:AddInfo( "Coordinate", Coordinate, Order, Detail, Keep )
|
||||
function TASKINFO:AddCoordinate( Coordinate, Order, Detail, Keep, ShowKey, Name )
|
||||
self:AddInfo( Name or "Coordinate", Coordinate, Order, Detail, Keep, ShowKey, "Coordinate" )
|
||||
return self
|
||||
end
|
||||
|
||||
@ -133,8 +133,8 @@ end
|
||||
--- Get the Coordinate.
|
||||
-- @param #TASKINFO self
|
||||
-- @return Core.Point#COORDINATE Coordinate
|
||||
function TASKINFO:GetCoordinate()
|
||||
return self:GetData( "Coordinate" )
|
||||
function TASKINFO:GetCoordinate( Name )
|
||||
return self:GetData( Name or "Coordinate" )
|
||||
end
|
||||
|
||||
|
||||
@ -308,10 +308,11 @@ function TASKINFO:Report( Report, Detail, ReportGroup, Task )
|
||||
|
||||
if Data.Detail:find( Detail ) then
|
||||
local Text = ""
|
||||
local ShowKey = ( Data.ShowKey == nil or Data.ShowKey == true )
|
||||
if Key == "TaskName" then
|
||||
Key = nil
|
||||
Text = Data.Data
|
||||
elseif Key == "Coordinate" then
|
||||
elseif Data.Type and Data.Type == "Coordinate" then
|
||||
local Coordinate = Data.Data -- Core.Point#COORDINATE
|
||||
Text = Coordinate:ToString( ReportGroup:GetUnit(1), nil, Task )
|
||||
elseif Key == "Threat" then
|
||||
@ -357,7 +358,7 @@ function TASKINFO:Report( Report, Detail, ReportGroup, Task )
|
||||
end
|
||||
|
||||
if Text ~= "" then
|
||||
LineReport:Add( ( Key and ( Key .. ":" ) or "" ) .. Text )
|
||||
LineReport:Add( ( ( Key and ShowKey == true ) and ( Key .. ": " ) or "" ) .. Text )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -194,6 +194,45 @@ do -- TASK_CAPTURE_DISPATCHER
|
||||
end
|
||||
|
||||
|
||||
--- Link a task capture dispatcher from the other coalition to understand its plan for defenses.
|
||||
-- This is used for the tactical overview, so the players also know the zones attacked by the other coalition!
|
||||
-- @param #TASK_CAPTURE_DISPATCHER self
|
||||
-- @param #TASK_CAPTURE_DISPATCHER DefenseTaskCaptureDispatcher
|
||||
function TASK_CAPTURE_DISPATCHER:SetDefenseTaskCaptureDispatcher( DefenseTaskCaptureDispatcher )
|
||||
|
||||
self.DefenseTaskCaptureDispatcher = DefenseTaskCaptureDispatcher
|
||||
end
|
||||
|
||||
|
||||
--- Get the linked task capture dispatcher from the other coalition to understand its plan for defenses.
|
||||
-- This is used for the tactical overview, so the players also know the zones attacked by the other coalition!
|
||||
-- @param #TASK_CAPTURE_DISPATCHER self
|
||||
-- @return #TASK_CAPTURE_DISPATCHER
|
||||
function TASK_CAPTURE_DISPATCHER:GetDefenseTaskCaptureDispatcher()
|
||||
|
||||
return self.DefenseTaskCaptureDispatcher
|
||||
end
|
||||
|
||||
|
||||
--- Link an AI A2G dispatcher from the other coalition to understand its plan for defenses.
|
||||
-- This is used for the tactical overview, so the players also know the zones attacked by the other AI A2G dispatcher!
|
||||
-- @param #TASK_CAPTURE_DISPATCHER self
|
||||
-- @param AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER DefenseAIA2GDispatcher
|
||||
function TASK_CAPTURE_DISPATCHER:SetDefenseAIA2GDispatcher( DefenseAIA2GDispatcher )
|
||||
|
||||
self.DefenseAIA2GDispatcher = DefenseAIA2GDispatcher
|
||||
end
|
||||
|
||||
|
||||
--- Get the linked AI A2G dispatcher from the other coalition to understand its plan for defenses.
|
||||
-- This is used for the tactical overview, so the players also know the zones attacked by the AI A2G dispatcher!
|
||||
-- @param #TASK_CAPTURE_DISPATCHER self
|
||||
-- @return AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER
|
||||
function TASK_CAPTURE_DISPATCHER:GetDefenseAIA2GDispatcher()
|
||||
|
||||
return self.DefenseAIA2GDispatcher
|
||||
end
|
||||
|
||||
|
||||
--- Add a capture zone task.
|
||||
-- @param #TASK_CAPTURE_DISPATCHER self
|
||||
@ -274,6 +313,9 @@ do -- TASK_CAPTURE_DISPATCHER
|
||||
CaptureZone.Task.TaskPrefix = CaptureZone.TaskPrefix -- We keep the TaskPrefix for further reference!
|
||||
Mission:AddTask( CaptureZone.Task )
|
||||
TaskReport:Add( TaskName )
|
||||
|
||||
-- Link the Task Dispatcher to the capture zone task, because it is used on the UpdateTaskInfo.
|
||||
CaptureZone.Task:SetDispatcher( self )
|
||||
CaptureZone.Task:UpdateTaskInfo()
|
||||
|
||||
function CaptureZone.Task.OnEnterAssigned( Task, From, Event, To )
|
||||
@ -281,6 +323,7 @@ do -- TASK_CAPTURE_DISPATCHER
|
||||
self.AI_A2G_Dispatcher:Unlock( Task.TaskZoneName ) -- This will unlock the zone to be defended by AI.
|
||||
end
|
||||
CaptureZone.Task:UpdateTaskInfo()
|
||||
CaptureZone.Task.ZoneGoal.Attacked = true
|
||||
end
|
||||
|
||||
function CaptureZone.Task.OnEnterSuccess( Task, From, Event, To )
|
||||
@ -289,6 +332,7 @@ do -- TASK_CAPTURE_DISPATCHER
|
||||
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
|
||||
end
|
||||
CaptureZone.Task:UpdateTaskInfo()
|
||||
CaptureZone.Task.ZoneGoal.Attacked = false
|
||||
end
|
||||
|
||||
function CaptureZone.Task.OnEnterCancelled( Task, From, Event, To )
|
||||
@ -297,6 +341,7 @@ do -- TASK_CAPTURE_DISPATCHER
|
||||
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
|
||||
end
|
||||
CaptureZone.Task:UpdateTaskInfo()
|
||||
CaptureZone.Task.ZoneGoal.Attacked = false
|
||||
end
|
||||
|
||||
function CaptureZone.Task.OnEnterFailed( Task, From, Event, To )
|
||||
@ -305,6 +350,7 @@ do -- TASK_CAPTURE_DISPATCHER
|
||||
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
|
||||
end
|
||||
CaptureZone.Task:UpdateTaskInfo()
|
||||
CaptureZone.Task.ZoneGoal.Attacked = false
|
||||
end
|
||||
|
||||
function CaptureZone.Task.OnEnterAborted( Task, From, Event, To )
|
||||
@ -313,6 +359,7 @@ do -- TASK_CAPTURE_DISPATCHER
|
||||
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
|
||||
end
|
||||
CaptureZone.Task:UpdateTaskInfo()
|
||||
CaptureZone.Task.ZoneGoal.Attacked = false
|
||||
end
|
||||
|
||||
-- Now broadcast the onafterCargoPickedUp event to the Task Cargo Dispatcher.
|
||||
@ -322,6 +369,7 @@ do -- TASK_CAPTURE_DISPATCHER
|
||||
self.AI_A2G_Dispatcher:Lock( Task.TaskZoneName ) -- This will lock the zone from being defended by AI.
|
||||
end
|
||||
CaptureZone.Task:UpdateTaskInfo()
|
||||
CaptureZone.Task.ZoneGoal.Attacked = false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -228,11 +228,44 @@ do -- TASK_CAPTURE_ZONE
|
||||
local ZoneCoordinate = self.ZoneGoal:GetZone():GetCoordinate()
|
||||
self.TaskInfo:AddTaskName( 0, "MSOD", Persist )
|
||||
self.TaskInfo:AddCoordinate( ZoneCoordinate, 1, "SOD", Persist )
|
||||
self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD", Persist )
|
||||
self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD", Persist )
|
||||
local SetUnit = self.ZoneGoal.Zone:GetScannedSetUnit()
|
||||
-- self.TaskInfo:AddText( "Zone Name", self.ZoneGoal:GetZoneName(), 10, "MOD", Persist )
|
||||
-- self.TaskInfo:AddText( "Zone Coalition", self.ZoneGoal:GetCoalitionName(), 11, "MOD", Persist )
|
||||
local SetUnit = self.ZoneGoal:GetScannedSetUnit()
|
||||
local ThreatLevel, ThreatText = SetUnit:CalculateThreatLevelA2G()
|
||||
local ThreatCount = SetUnit:Count()
|
||||
self.TaskInfo:AddThreat( ThreatText, ThreatLevel, 20, "MOD", Persist )
|
||||
self.TaskInfo:AddInfo( "Remaining Units", ThreatCount, 21, "MOD", Persist, true)
|
||||
|
||||
if self.Dispatcher then
|
||||
local DefenseTaskCaptureDispatcher = self.Dispatcher:GetDefenseTaskCaptureDispatcher() -- Tasking.Task_Capture_Dispatcher#TASK_CAPTURE_DISPATCHER
|
||||
|
||||
if DefenseTaskCaptureDispatcher then
|
||||
-- Loop through all zones of the Defenses, and check which zone has an assigned task!
|
||||
for TaskName, CaptureZone in pairs( DefenseTaskCaptureDispatcher.Zones or {} ) do
|
||||
local Task = CaptureZone.Task -- Tasking.Task_Capture_Zone#TASK_CAPTURE_ZONE
|
||||
if Task then
|
||||
self.TaskInfo:AddInfo( "Defense Player Zone", Task.ZoneGoal:GetName(), 30, "MOD", Persist )
|
||||
self.TaskInfo:AddCoordinate( Task.ZoneGoal:GetZone():GetCoordinate(), 31, "MOD", Persist, false, "Defense Player Coordinate" )
|
||||
end
|
||||
end
|
||||
end
|
||||
local DefenseAIA2GDispatcher = self.Dispatcher:GetDefenseAIA2GDispatcher() -- AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER
|
||||
|
||||
if DefenseAIA2GDispatcher then
|
||||
-- Loop through all zones of the Defenses, and check which zone has an assigned task!
|
||||
for Defender, Task in pairs( DefenseAIA2GDispatcher:GetDefenderTasks() or {} ) do
|
||||
local DetectedItem = DefenseAIA2GDispatcher:GetDefenderTaskTarget( Defender )
|
||||
if DetectedItem then
|
||||
local DetectedZone = DefenseAIA2GDispatcher.Detection:GetDetectedItemZone( DetectedItem )
|
||||
if DetectedZone then
|
||||
self.TaskInfo:AddInfo( "Defense AI Zone", DetectedZone:GetName(), 40, "MOD", Persist )
|
||||
self.TaskInfo:AddCoordinate( DetectedZone:GetCoordinate(), 41, "MOD", Persist, false, "Defense AI Coordinate" )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -274,7 +307,7 @@ do -- TASK_CAPTURE_ZONE
|
||||
-- @param #number AutoAssignMethod The method to be applied to the task.
|
||||
-- @param Tasking.CommandCenter#COMMANDCENTER CommandCenter The command center.
|
||||
-- @param Wrapper.Group#GROUP TaskGroup The player group.
|
||||
function TASK_CAPTURE_ZONE:GetAutoAssignPriority( AutoAssignMethod, CommandCenter, TaskGroup )
|
||||
function TASK_CAPTURE_ZONE:GetAutoAssignPriority( AutoAssignMethod, CommandCenter, TaskGroup, AutoAssignReference )
|
||||
|
||||
if AutoAssignMethod == COMMANDCENTER.AutoAssignMethods.Random then
|
||||
return math.random( 1, 9 )
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user