mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
- Added a new UTILS.kpairs iterator, which will base the iteration on a different key, which can be determined before the iteration starts. eg. the key should be a sort in ascending order on the distance of the information in the set, and it should return the distance + item in the set for each element in the set.
- Resolved for TASK_CAPTURE_ZONES the whole logic of determining correctly the player and AI defense zones, as to be displayed in the information panel, this was a very difficult exercise for me.
This commit is contained in:
parent
372dd704d2
commit
e0075cc9ac
@ -4024,6 +4024,29 @@ do -- AI_A2G_DISPATCHER
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Determine the distance as the keys of reference of the detected items.
|
||||||
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
|
function AI_A2G_DISPATCHER:Keys( DetectedItem )
|
||||||
|
|
||||||
|
self:F( { DetectedItem = DetectedItem } )
|
||||||
|
|
||||||
|
local AttackCoordinate = self.Detection:GetDetectedItemCoordinate( DetectedItem )
|
||||||
|
|
||||||
|
local ShortestDistance = 999999999
|
||||||
|
|
||||||
|
for DefenseCoordinateName, DefenseCoordinate in pairs( self.DefenseCoordinates ) do
|
||||||
|
local DefenseCoordinate = DefenseCoordinate -- Core.Point#COORDINATE
|
||||||
|
|
||||||
|
local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate )
|
||||||
|
|
||||||
|
if EvaluateDistance <= ShortestDistance then
|
||||||
|
ShortestDistance = EvaluateDistance
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return ShortestDistance
|
||||||
|
end
|
||||||
|
|
||||||
--- Assigns A2G AI Tasks in relation to the detected items.
|
--- Assigns A2G AI Tasks in relation to the detected items.
|
||||||
-- @param #AI_A2G_DISPATCHER self
|
-- @param #AI_A2G_DISPATCHER self
|
||||||
function AI_A2G_DISPATCHER:Order( DetectedItem )
|
function AI_A2G_DISPATCHER:Order( DetectedItem )
|
||||||
@ -4082,7 +4105,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
|
|
||||||
-- Show tactical situation
|
-- Show tactical situation
|
||||||
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
|
local ThreatLevel = DetectedItem.Set:CalculateThreatLevelA2G()
|
||||||
Report:Add( string.format( " - %1s%s ( %4s ): ( #%d - %4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) )
|
Report:Add( string.format( " - %1s%s ( %04s ): ( #%02d - %-4s ) %s" , ( DetectedItem.IsDetected == true ) and "!" or " ", DetectedItem.ItemID, DetectedItem.Index, DetectedItem.Set:Count(), DetectedItem.Type or " --- ", string.rep( "■", ThreatLevel ) ) )
|
||||||
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
|
||||||
local Defender = Defender -- Wrapper.Group#GROUP
|
local Defender = Defender -- Wrapper.Group#GROUP
|
||||||
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
|
||||||
@ -4203,7 +4226,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
|
|
||||||
-- Now that all obsolete tasks are removed, loop through the detected targets.
|
-- Now that all obsolete tasks are removed, loop through the detected targets.
|
||||||
--for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do
|
--for DetectedItemID, DetectedItem in pairs( Detection:GetDetectedItems() ) do
|
||||||
for DetectedItemID, DetectedItem in UTILS.spairs( Detection:GetDetectedItems(), function( t, a, b ) return self:Order(t[a]) < self:Order(t[b]) end ) do
|
for DetectedDistance, DetectedItem in UTILS.kpairs( Detection:GetDetectedItems(), function( t ) return self:Keys( t ) end, function( t, a, b ) return self:Order(t[a]) < self:Order(t[b]) end ) do
|
||||||
|
|
||||||
if not self.Detection:IsDetectedItemLocked( DetectedItem ) == true then
|
if not self.Detection:IsDetectedItemLocked( DetectedItem ) == true then
|
||||||
local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem
|
local DetectedItem = DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem
|
||||||
@ -4226,43 +4249,42 @@ do -- AI_A2G_DISPATCHER
|
|||||||
-- This calculation is based on the distance between the defense point and the attackers, and the defensiveness parameter.
|
-- This calculation is based on the distance between the defense point and the attackers, and the defensiveness parameter.
|
||||||
-- The attackers closest to the defense coordinates will be handled first, or course!
|
-- The attackers closest to the defense coordinates will be handled first, or course!
|
||||||
|
|
||||||
local EngageCoordinate = nil
|
local EngageDefenses = nil
|
||||||
|
|
||||||
for DefenseCoordinateName, DefenseCoordinate in pairs( self.DefenseCoordinates ) do
|
self:F( { DetectedDistance = DetectedDistance, DefenseRadius = self.DefenseRadius } )
|
||||||
local DefenseCoordinate = DefenseCoordinate -- Core.Point#COORDINATE
|
if DetectedDistance <= self.DefenseRadius then
|
||||||
|
|
||||||
local EvaluateDistance = AttackCoordinate:Get2DDistance( DefenseCoordinate )
|
self:F( { DetectedApproach = self._DefenseApproach } )
|
||||||
|
if self._DefenseApproach == AI_A2G_DISPATCHER.DefenseApproach.Distance then
|
||||||
|
EngageDefenses = true
|
||||||
|
self:F( { EngageDefenses = EngageDefenses } )
|
||||||
|
end
|
||||||
|
|
||||||
if EvaluateDistance <= self.DefenseRadius then
|
if self._DefenseApproach == AI_A2G_DISPATCHER.DefenseApproach.Random then
|
||||||
|
local DistanceProbability = ( self.DefenseRadius / DetectedDistance * self.DefenseReactivity )
|
||||||
local DistanceProbability = ( self.DefenseRadius / EvaluateDistance * self.DefenseReactivity )
|
|
||||||
local DefenseProbability = math.random()
|
local DefenseProbability = math.random()
|
||||||
|
|
||||||
self:F( { DistanceProbability = DistanceProbability, DefenseProbability = DefenseProbability } )
|
self:F( { DistanceProbability = DistanceProbability, DefenseProbability = DefenseProbability } )
|
||||||
|
|
||||||
if self._DefenseApproach == AI_A2G_DISPATCHER.DefenseApproach.Random then
|
if DefenseProbability <= DistanceProbability / ( 300 / 30 ) then
|
||||||
|
EngageDefenses = true
|
||||||
if DefenseProbability <= DistanceProbability / ( 300 / 30 ) then
|
|
||||||
EngageCoordinate = DefenseCoordinate
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if self._DefenseApproach == AI_A2G_DISPATCHER.DefenseApproach.Distance then
|
|
||||||
EngageCoordinate = DefenseCoordinate
|
|
||||||
break
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:F( { EngageDefenses = EngageDefenses, DefenseLimit = self.DefenseLimit, DefenseTotal = DefenseTotal } )
|
||||||
|
|
||||||
-- There needs to be an EngageCoordinate.
|
-- There needs to be an EngageCoordinate.
|
||||||
-- If self.DefenseLimit is set (thus limit the amount of defenses to one zone), then only start a new defense if the maximum has not been reached.
|
-- If self.DefenseLimit is set (thus limit the amount of defenses to one zone), then only start a new defense if the maximum has not been reached.
|
||||||
-- If self.DefenseLimit has not been set, there is an unlimited amount of zones to be defended.
|
-- If self.DefenseLimit has not been set, there is an unlimited amount of zones to be defended.
|
||||||
if ( EngageCoordinate and ( self.DefenseLimit and DefenseTotal < self.DefenseLimit ) or not self.DefenseLimit ) then
|
if ( EngageDefenses and ( self.DefenseLimit and DefenseTotal < self.DefenseLimit ) or not self.DefenseLimit ) then
|
||||||
do
|
do
|
||||||
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_SEAD( DetectedItem ) -- Returns a SET_UNIT with the SEAD targets to be engaged...
|
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_SEAD( DetectedItem ) -- Returns a SET_UNIT with the SEAD targets to be engaged...
|
||||||
if DefendersMissing > 0 then
|
if DefendersMissing > 0 then
|
||||||
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
|
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
|
||||||
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "SEAD", EngageCoordinate )
|
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "SEAD" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -4270,7 +4292,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_CAS( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
|
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_CAS( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
|
||||||
if DefendersMissing > 0 then
|
if DefendersMissing > 0 then
|
||||||
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
|
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
|
||||||
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "CAS", EngageCoordinate )
|
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "CAS" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -4278,7 +4300,7 @@ do -- AI_A2G_DISPATCHER
|
|||||||
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_BAI( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
|
local DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies = self:Evaluate_BAI( DetectedItem ) -- Returns a SET_UNIT with the CAS targets to be engaged...
|
||||||
if DefendersMissing > 0 then
|
if DefendersMissing > 0 then
|
||||||
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
|
self:F( { DefendersTotal = DefendersTotal, DefendersEngaged = DefendersEngaged, DefendersMissing = DefendersMissing } )
|
||||||
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "BAI", EngageCoordinate )
|
self:Defend( DetectedItem, DefendersTotal, DefendersEngaged, DefendersMissing, Friendlies, "BAI" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -200,7 +200,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
|||||||
|
|
||||||
self:SetAutoAssignTasks( false )
|
self:SetAutoAssignTasks( false )
|
||||||
self:SetAutoAcceptTasks( true )
|
self:SetAutoAcceptTasks( true )
|
||||||
self:SetAutoAssignMethod( COMMANDCENTER.AutoAssignMethods.Random )
|
self:SetAutoAssignMethod( COMMANDCENTER.AutoAssignMethods.Distance )
|
||||||
self:SetFlashStatus( false )
|
self:SetFlashStatus( false )
|
||||||
|
|
||||||
self:HandleEvent( EVENTS.Birth,
|
self:HandleEvent( EVENTS.Birth,
|
||||||
@ -210,7 +210,7 @@ function COMMANDCENTER:New( CommandCenterPositionable, CommandCenterName )
|
|||||||
if EventData.IniObjectCategory == 1 then
|
if EventData.IniObjectCategory == 1 then
|
||||||
local EventGroup = GROUP:Find( EventData.IniDCSGroup )
|
local EventGroup = GROUP:Find( EventData.IniDCSGroup )
|
||||||
--self:E( { CommandCenter = self:GetName(), EventGroup = EventGroup:GetName(), HasGroup = self:HasGroup( EventGroup ), EventData = EventData } )
|
--self:E( { CommandCenter = self:GetName(), EventGroup = EventGroup:GetName(), HasGroup = self:HasGroup( EventGroup ), EventData = EventData } )
|
||||||
if EventGroup and self:HasGroup( EventGroup ) then
|
if EventGroup and EventGroup:IsAlive() and self:HasGroup( EventGroup ) then
|
||||||
local CommandCenterMenu = MENU_GROUP:New( EventGroup, self:GetText() )
|
local CommandCenterMenu = MENU_GROUP:New( EventGroup, self:GetText() )
|
||||||
local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", CommandCenterMenu )
|
local MenuReporting = MENU_GROUP:New( EventGroup, "Missions Reports", CommandCenterMenu )
|
||||||
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportSummary, self, EventGroup )
|
local MenuMissionsSummary = MENU_GROUP_COMMAND:New( EventGroup, "Missions Status Report", MenuReporting, self.ReportSummary, self, EventGroup )
|
||||||
|
|||||||
@ -1232,12 +1232,16 @@ end
|
|||||||
|
|
||||||
--- Report the task status.
|
--- Report the task status.
|
||||||
-- @param #TASK self
|
-- @param #TASK self
|
||||||
|
-- @param Wrapper.Group#GROUP TaskGroup
|
||||||
function TASK:MenuTaskStatus( TaskGroup )
|
function TASK:MenuTaskStatus( TaskGroup )
|
||||||
|
|
||||||
local ReportText = self:ReportDetails( TaskGroup )
|
if TaskGroup:IsAlive() then
|
||||||
|
|
||||||
self:T( ReportText )
|
local ReportText = self:ReportDetails( TaskGroup )
|
||||||
self:GetMission():GetCommandCenter():MessageTypeToGroup( ReportText, TaskGroup, MESSAGE.Type.Detailed )
|
|
||||||
|
self:T( ReportText )
|
||||||
|
self:GetMission():GetCommandCenter():MessageTypeToGroup( ReportText, TaskGroup, MESSAGE.Type.Detailed )
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -240,10 +240,13 @@ do -- TASK_CAPTURE_ZONE
|
|||||||
local DefenseTaskCaptureDispatcher = self.Dispatcher:GetDefenseTaskCaptureDispatcher() -- Tasking.Task_Capture_Dispatcher#TASK_CAPTURE_DISPATCHER
|
local DefenseTaskCaptureDispatcher = self.Dispatcher:GetDefenseTaskCaptureDispatcher() -- Tasking.Task_Capture_Dispatcher#TASK_CAPTURE_DISPATCHER
|
||||||
|
|
||||||
if DefenseTaskCaptureDispatcher then
|
if DefenseTaskCaptureDispatcher then
|
||||||
-- Loop through all zones of the Defenses, and check which zone has an assigned task!
|
-- Loop through all zones of the player Defenses, and check which zone has an assigned task!
|
||||||
|
-- The Zones collection contains a Task. This Task is checked if it is assigned.
|
||||||
|
-- If Assigned, then this task will be the task that is the closest to the defense zone.
|
||||||
for TaskName, CaptureZone in pairs( DefenseTaskCaptureDispatcher.Zones or {} ) do
|
for TaskName, CaptureZone in pairs( DefenseTaskCaptureDispatcher.Zones or {} ) do
|
||||||
local Task = CaptureZone.Task -- Tasking.Task_Capture_Zone#TASK_CAPTURE_ZONE
|
local Task = CaptureZone.Task -- Tasking.Task_Capture_Zone#TASK_CAPTURE_ZONE
|
||||||
if Task then
|
if Task and Task:IsStateAssigned() then -- We also check assigned.
|
||||||
|
-- Now we register the defense player zone information to the task report.
|
||||||
self.TaskInfo:AddInfo( "Defense Player Zone", Task.ZoneGoal:GetName(), 30, "MOD", Persist )
|
self.TaskInfo:AddInfo( "Defense Player Zone", Task.ZoneGoal:GetName(), 30, "MOD", Persist )
|
||||||
self.TaskInfo:AddCoordinate( Task.ZoneGoal:GetZone():GetCoordinate(), 31, "MOD", Persist, false, "Defense Player Coordinate" )
|
self.TaskInfo:AddCoordinate( Task.ZoneGoal:GetZone():GetCoordinate(), 31, "MOD", Persist, false, "Defense Player Coordinate" )
|
||||||
end
|
end
|
||||||
@ -252,7 +255,7 @@ do -- TASK_CAPTURE_ZONE
|
|||||||
local DefenseAIA2GDispatcher = self.Dispatcher:GetDefenseAIA2GDispatcher() -- AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER
|
local DefenseAIA2GDispatcher = self.Dispatcher:GetDefenseAIA2GDispatcher() -- AI.AI_A2G_Dispatcher#AI_A2G_DISPATCHER
|
||||||
|
|
||||||
if DefenseAIA2GDispatcher then
|
if DefenseAIA2GDispatcher then
|
||||||
-- Loop through all zones of the Defenses, and check which zone has an assigned task!
|
-- Loop through all the tasks of the AI Defenses, and check which zone is involved in the defenses and is active!
|
||||||
for Defender, Task in pairs( DefenseAIA2GDispatcher:GetDefenderTasks() or {} ) do
|
for Defender, Task in pairs( DefenseAIA2GDispatcher:GetDefenderTasks() or {} ) do
|
||||||
local DetectedItem = DefenseAIA2GDispatcher:GetDefenderTaskTarget( Defender )
|
local DetectedItem = DefenseAIA2GDispatcher:GetDefenderTaskTarget( Defender )
|
||||||
if DetectedItem then
|
if DetectedItem then
|
||||||
|
|||||||
@ -519,6 +519,32 @@ function UTILS.spairs( t, order )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Here is a customized version of pairs, which I called kpairs because it iterates over the table in a sorted order, based on a function that will determine the keys as reference first.
|
||||||
|
function UTILS.kpairs( t, getkey, order )
|
||||||
|
-- collect the keys
|
||||||
|
local keys = {}
|
||||||
|
local keyso = {}
|
||||||
|
for k, o in pairs(t) do keys[#keys+1] = k keyso[#keyso+1] = getkey( o ) end
|
||||||
|
|
||||||
|
-- if order function given, sort by it by passing the table and keys a, b,
|
||||||
|
-- otherwise just sort the keys
|
||||||
|
if order then
|
||||||
|
table.sort(keys, function(a,b) return order(t, a, b) end)
|
||||||
|
else
|
||||||
|
table.sort(keys)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- return the iterator function
|
||||||
|
local i = 0
|
||||||
|
return function()
|
||||||
|
i = i + 1
|
||||||
|
if keys[i] then
|
||||||
|
return keyso[i], t[keys[i]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Here is a customized version of pairs, which I called rpairs because it iterates over the table in a random order.
|
-- Here is a customized version of pairs, which I called rpairs because it iterates over the table in a random order.
|
||||||
function UTILS.rpairs( t )
|
function UTILS.rpairs( t )
|
||||||
-- collect the keys
|
-- collect the keys
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user