This commit is contained in:
FlightControl 2017-06-07 12:56:43 +02:00
parent d120875fa9
commit ef95cfb1f5
8 changed files with 132 additions and 22 deletions

View File

@ -71,7 +71,7 @@ function AI_A2A:New( AIGroup )
self:SetControllable( AIGroup )
self:ManageFuel( .2, 60 )
self:ManageDamage( 1 )
self:ManageDamage( 0.4 )
self:SetStartState( "Stopped" )

View File

@ -26,7 +26,7 @@
--
-- @module AI_A2A_Cap
BASE:TraceClass("AI_A2A_CAP")
--BASE:TraceClass("AI_A2A_CAP")
--- @type AI_A2A_CAP
-- @extends AI.AI_A2A_Patrol#AI_A2A_PATROL

View File

@ -269,7 +269,7 @@ do -- AI_A2A_DISPATCHER
---
-- @param #AI_A2A_DISPATCHER self
function AI_A2A_DISPATCHER:ClearDefenderTask( AIGroup )
if AIGroup:IsAlive() then
if AIGroup:IsAlive() and self.DefenderTasks[AIGroup] then
local Target = self.DefenderTasks[AIGroup].Target
local Message = "Clearing (" .. self.DefenderTasks[AIGroup].Type .. ") "
Message = Message .. AIGroup:GetName()
@ -342,8 +342,22 @@ do -- AI_A2A_DISPATCHER
DefenderSquadron.Resources = Resources
self:SetSquadronOverhead( SquadronName, 1 )
return self
end
--- Get an item from the Squadron table.
-- @param #AI_A2A_DISPATCHER self
-- @return #table
function AI_A2A_DISPATCHER:GetSquadron( SquadronName )
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
if not DefenderSquadron then
error( "Unknown Squadron:" .. SquadronName )
end
return DefenderSquadron
end
---
@ -361,7 +375,7 @@ do -- AI_A2A_DISPATCHER
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
self.DefenderSquadrons[SquadronName].Cap = self.DefenderSquadrons[SquadronName].Cap or {}
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
local DefenderSquadron = self:GetSquadron( SquadronName )
local Cap = self.DefenderSquadrons[SquadronName].Cap
Cap.Name = SquadronName
@ -386,7 +400,7 @@ do -- AI_A2A_DISPATCHER
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
self.DefenderSquadrons[SquadronName].Cap = self.DefenderSquadrons[SquadronName].Cap or {}
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
local DefenderSquadron = self:GetSquadron( SquadronName )
local Cap = self.DefenderSquadrons[SquadronName].Cap
if Cap then
@ -415,7 +429,7 @@ do -- AI_A2A_DISPATCHER
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
self.DefenderSquadrons[SquadronName].Cap = self.DefenderSquadrons[SquadronName].Cap or {}
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
local DefenderSquadron = self:GetSquadron( SquadronName )
local Cap = self.DefenderSquadrons[SquadronName].Cap
if Cap then
@ -434,7 +448,7 @@ do -- AI_A2A_DISPATCHER
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
self.DefenderSquadrons[SquadronName].Cap = self.DefenderSquadrons[SquadronName].Cap or {}
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
local DefenderSquadron = self:GetSquadron( SquadronName )
local Cap = DefenderSquadron.Cap
if Cap then
@ -501,8 +515,9 @@ do -- AI_A2A_DISPATCHER
--
-- @return #AI_A2A_DISPATCHER
function AI_A2A_DISPATCHER:SetSquadronOverhead( SquadronName, Overhead )
self.Overhead = Overhead
local DefenderSquadron = self:GetSquadron( SquadronName )
DefenderSquadron.Overhead = Overhead
return self
end
@ -520,7 +535,8 @@ do -- AI_A2A_DISPATCHER
-- @return #AI_A2A_DISPATCHER
function AI_A2A_DISPATCHER:SetSquadronGrouping( SquadronName, Grouping )
self.Grouping = Grouping
local DefenderSquadron = self:GetSquadron( SquadronName )
DefenderSquadron.Grouping = Grouping
return self
end
@ -602,13 +618,15 @@ do -- AI_A2A_DISPATCHER
local AIFriendlies = self:GetAIFriendliesNearBy( DetectedItem )
for AIName, AIFriendly in pairs( AIFriendlies or {} ) do
for FriendlyDistance, AIFriendly in UTILS.spairs( AIFriendlies or {} ) do
-- We only allow to ENGAGE targets as long as the Units on both sides are balanced.
if DetectedCount > DefenderCount then
local Friendly = AIFriendly:GetGroup() -- Wrapper.Group#GROUP
if Friendly and Friendly:IsAlive() then
-- Ok, so we have a friendly near the potential target.
-- Now we need to check if the AIGroup has a Task.
self:F( { FriendlyName = Friendly:GetName() } )
self:F( { FriendlyDistance = FriendlyDistance } )
local DefenderTask = self:GetDefenderTask( Friendly )
if DefenderTask then
-- The Task should be CAP or INTERCEPT
@ -641,13 +659,14 @@ do -- AI_A2A_DISPATCHER
self.DefenderSquadrons[SquadronName] = self.DefenderSquadrons[SquadronName] or {}
self.DefenderSquadrons[SquadronName].Cap = self.DefenderSquadrons[SquadronName].Cap or {}
local DefenderSquadron = self.DefenderSquadrons[SquadronName]
local DefenderSquadron = self:GetSquadron( SquadronName )
local Cap = DefenderSquadron.Cap
if Cap then
if self:CanCAP( SquadronName ) then
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ]
Spawn:InitGrouping( DefenderSquadron.Grouping )
local AIGroup = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase )
self:F( { AIGroup = AIGroup:GetName() } )
@ -682,6 +701,13 @@ do -- AI_A2A_DISPATCHER
Fsm:__Engage( 1, Target.Set ) -- Engage on the TargetSetUnit
self:SetDefenderTaskTarget( AIGroup, Target )
function Fsm:onafterRTB()
self:F({"CAP RTB"})
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
local AIGroup = self:GetControllable()
Dispatcher:ClearDefenderTask( AIGroup )
end
end
end
end
@ -706,7 +732,8 @@ do -- AI_A2A_DISPATCHER
DefendersCount = DefendersCount + AIGroup:GetSize()
end
while( DefendersCount < DefendersMissing ) do
DefendersCount = DefendersMissing
while( DefendersCount > 0 ) do
for SquadronName, DefenderSquadron in pairs( self.DefenderSquadrons or {} ) do
for InterceptID, Intercept in pairs( DefenderSquadron.Intercept or {} ) do
@ -724,16 +751,24 @@ do -- AI_A2A_DISPATCHER
if ClosestDefenderSquadronName then
local DefenderSquadron = self.DefenderSquadrons[ClosestDefenderSquadronName]
local DefenderSquadron = self:GetSquadron( ClosestDefenderSquadronName )
local DefenderOverhead = DefenderSquadron.Overhead
local DefenderGrouping = DefenderSquadron.Grouping
local DefendersNeeded = math.ceil( DefendersCount * DefenderOverhead )
local Intercept = self.DefenderSquadrons[ClosestDefenderSquadronName].Intercept
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ]
if DefenderGrouping then
Spawn:InitGrouping( ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded )
else
Spawn:InitGrouping()
end
local AIGroup = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase )
self:F( { AIGroup = AIGroup:GetName() } )
if AIGroup then
DefendersCount = DefendersCount + AIGroup:GetSize()
DefendersCount = DefendersCount - AIGroup:GetSize()
local Fsm = AI_A2A_INTERCEPT:New( AIGroup, Intercept.MinSpeed, Intercept.MaxSpeed )
Fsm:SetDispatcher( self )
@ -744,7 +779,7 @@ do -- AI_A2A_DISPATCHER
self:SetDefenderTask( AIGroup, "INTERCEPT", Fsm, Target )
function Fsm:onafterRTB()
self:F({"RTB"})
self:F({"INTERCEPT RTB"})
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
local AIGroup = self:GetControllable()
Dispatcher:ClearDefenderTask( AIGroup )
@ -795,7 +830,7 @@ do -- AI_A2A_DISPATCHER
-- First, count the active AIGroups Units, targetting the DetectedSet
local DefenderCount = self:CountDefendersEngaged( Target )
local DefendersMissing = math.ceil( ( AttackerCount - DefenderCount ) * self.Overhead )
local DefendersMissing = AttackerCount - DefenderCount
local Friendlies = self:CountDefendersToBeEngaged( Target, DefenderCount )
@ -865,7 +900,7 @@ do -- AI_A2A_DISPATCHER
local Defender = Defender -- Wrapper.Group#GROUP
local Message = string.format( "%s, %s", Defender:GetName(), DefenderTask.Type )
if DefenderTask.Target then
Message = Message .. " => " .. DefenderTask.Target.Index
Message = Message .. " => " .. DefenderTask.Target.Index .. " : " .. DefenderTask.Target.Set:GetObjectNames()
end
self:F( { Tactical = Message } )
end

View File

@ -21,7 +21,7 @@
-- @module AI_A2A_Intercept
BASE:TraceClass("AI_A2A_INTERCEPT")
--BASE:TraceClass("AI_A2A_INTERCEPT")
--- @type AI_A2A_INTERCEPT

View File

@ -598,6 +598,20 @@ function SET_BASE:IsIncludeObject( Object )
return true
end
--- Gets a string with all the object names.
-- @param #SET_BASE self
-- @return #string A string with the names of the objects.
function SET_BASE:GetObjectNames()
self:F3()
local ObjectNames = ""
for ObjectName, Object in pairs( self.Set ) do
ObjectNames = ObjectNames .. ObjectName .. ", "
end
return ObjectNames
end
--- Flushes the current SET_BASE contents in the log ... (for debugging reasons).
-- @param #SET_BASE self
-- @return #string A string with the names of the objects.

View File

@ -1167,6 +1167,7 @@ do -- DETECTION_BASE
local DetectedItem = ReportGroupData.DetectedItem -- Functional.Detection#DETECTION_BASE.DetectedItem
local DetectedSet = ReportGroupData.DetectedItem.Set
local DetectedUnit = DetectedSet:GetFirst() -- Wrapper.Unit#UNIT
local CenterCoord = DetectedUnit:GetCoordinate()
local ReportSetGroup = ReportGroupData.ReportSetGroup
local EnemyCoalition = DetectedUnit:GetCoalition()
@ -1181,7 +1182,9 @@ do -- DETECTION_BASE
if FoundUnitCoalition ~= EnemyCoalition and FoundUnitInReportSetGroup == false then
DetectedItem.FriendliesNearBy = DetectedItem.FriendliesNearBy or {}
DetectedItem.FriendliesNearBy[FoundUnitName] = UNIT:Find( FoundDCSUnit )
local FriendlyUnit = UNIT:Find( FoundDCSUnit )
local Distance = CenterCoord:Get2DDistance( FriendlyUnit:GetCoordinate() )
DetectedItem.FriendliesNearBy[Distance] = FriendlyUnit
return true
end

View File

@ -37,6 +37,7 @@
--
-- @module Spawn
--BASE:TraceClass("SPAWN")
--- SPAWN Class
@ -299,6 +300,7 @@ function SPAWN:New( SpawnTemplatePrefix )
self.SpawnUnControlled = false
self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name.
self.DelayOnOff = false -- No intial delay when spawning the first group.
self.Grouping = nil -- No grouping
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
else
@ -343,6 +345,7 @@ function SPAWN:NewWithAlias( SpawnTemplatePrefix, SpawnAliasPrefix )
self.SpawnUnControlled = false
self.SpawnInitKeepUnitNames = false -- Overwrite unit names by default with group name.
self.DelayOnOff = false -- No intial delay when spawning the first group.
self.Grouping = nil
self.SpawnGroups = {} -- Array containing the descriptions of each Group to be Spawned.
else
@ -509,6 +512,20 @@ function SPAWN:InitRandomizeTemplate( SpawnTemplatePrefixTable )
return self
end
--- When spawning a new group, make the grouping of the units according the InitGrouping setting.
-- @param #SPAWN self
-- @param #number Grouping Indicates the maximum amount of units in the group.
-- @return #SPAWN
function SPAWN:InitGrouping( Grouping ) -- R2.2
self:F( { self.SpawnTemplatePrefix, Grouping } )
self.SpawnGrouping = Grouping
return self
end
--TODO: Add example.
--- This method provides the functionality to randomize the spawning of the Groups at a given list of zones of different types.
-- @param #SPAWN self
@ -966,7 +983,7 @@ end
-- @param #number SpawnIndex (optional) The index which group to spawn within the given zone.
-- @return Wrapper.Group#GROUP that was spawned.
-- @return #nil Nothing was spawned.
function SPAWN:SpawnAtAirbase( Airbase, SpawnIndex )
function SPAWN:SpawnAtAirbase( Airbase, SpawnIndex ) -- R2.2
self:F( { self.SpawnTemplatePrefix, Airbase, SpawnIndex } )
local PointVec3 = Airbase:GetPointVec3()
@ -1445,7 +1462,7 @@ end
-- @param #string SpawnTemplatePrefix
-- @param #number SpawnIndex
-- @return #SPAWN self
function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex )
function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex ) --R2.2
self:F( { self.SpawnTemplatePrefix, self.SpawnAliasPrefix } )
local SpawnTemplate = self:_GetTemplate( SpawnTemplatePrefix )
@ -1460,6 +1477,23 @@ function SPAWN:_Prepare( SpawnTemplatePrefix, SpawnIndex )
SpawnTemplate.visible = false
end
if self.SpawnGrouping then
local UnitAmount = #SpawnTemplate.units
self:F( { UnitAmount = UnitAmount, SpawnGrouping = self.SpawnGrouping } )
if UnitAmount > self.SpawnGrouping then
for UnitID = self.SpawnGrouping + 1, UnitAmount do
SpawnTemplate.units[UnitID] = nil
end
else
if UnitAmount < self.SpawnGrouping then
for UnitID = UnitAmount + 1, self.SpawnGrouping do
SpawnTemplate.units[UnitID] = UTILS.DeepCopy( SpawnTemplate.units[1] )
SpawnTemplate.units[UnitID].unitId = nil
end
end
end
end
if self.SpawnInitKeepUnitNames == false then
for UnitID = 1, #SpawnTemplate.units do
SpawnTemplate.units[UnitID].name = string.format( SpawnTemplate.name .. '-%02d', UnitID )

View File

@ -303,3 +303,27 @@ function UTILS.DoString( s )
return false, err
end
end
-- Here is a customized version of pairs, which I called spairs because it iterates over the table in a sorted order.
function UTILS.spairs( t, order )
-- collect the keys
local keys = {}
for k in pairs(t) do keys[#keys+1] = k 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 keys[i], t[keys[i]]
end
end
end