From ef95cfb1f5f28b8317bc36f971309be2741aac1c Mon Sep 17 00:00:00 2001 From: FlightControl Date: Wed, 7 Jun 2017 12:56:43 +0200 Subject: [PATCH] Progress --- Moose Development/Moose/AI/AI_A2A.lua | 2 +- Moose Development/Moose/AI/AI_A2A_Cap.lua | 2 +- .../Moose/AI/AI_A2A_Dispatcher.lua | 67 ++++++++++++++----- .../Moose/AI/AI_A2A_Intercept.lua | 2 +- Moose Development/Moose/Core/Set.lua | 14 ++++ .../Moose/Functional/Detection.lua | 5 +- Moose Development/Moose/Functional/Spawn.lua | 38 ++++++++++- Moose Development/Moose/Utilities/Utils.lua | 24 +++++++ 8 files changed, 132 insertions(+), 22 deletions(-) diff --git a/Moose Development/Moose/AI/AI_A2A.lua b/Moose Development/Moose/AI/AI_A2A.lua index 041e04556..8b75eb57f 100644 --- a/Moose Development/Moose/AI/AI_A2A.lua +++ b/Moose Development/Moose/AI/AI_A2A.lua @@ -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" ) diff --git a/Moose Development/Moose/AI/AI_A2A_Cap.lua b/Moose Development/Moose/AI/AI_A2A_Cap.lua index 22ac96127..8037254b6 100644 --- a/Moose Development/Moose/AI/AI_A2A_Cap.lua +++ b/Moose Development/Moose/AI/AI_A2A_Cap.lua @@ -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 diff --git a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua index 9a63a3193..d0960e2fb 100644 --- a/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua +++ b/Moose Development/Moose/AI/AI_A2A_Dispatcher.lua @@ -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 diff --git a/Moose Development/Moose/AI/AI_A2A_Intercept.lua b/Moose Development/Moose/AI/AI_A2A_Intercept.lua index b24f93e18..e7c858ddf 100644 --- a/Moose Development/Moose/AI/AI_A2A_Intercept.lua +++ b/Moose Development/Moose/AI/AI_A2A_Intercept.lua @@ -21,7 +21,7 @@ -- @module AI_A2A_Intercept -BASE:TraceClass("AI_A2A_INTERCEPT") +--BASE:TraceClass("AI_A2A_INTERCEPT") --- @type AI_A2A_INTERCEPT diff --git a/Moose Development/Moose/Core/Set.lua b/Moose Development/Moose/Core/Set.lua index 241a793db..28a5d53be 100644 --- a/Moose Development/Moose/Core/Set.lua +++ b/Moose Development/Moose/Core/Set.lua @@ -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. diff --git a/Moose Development/Moose/Functional/Detection.lua b/Moose Development/Moose/Functional/Detection.lua index f009fcc07..bf4f43191 100644 --- a/Moose Development/Moose/Functional/Detection.lua +++ b/Moose Development/Moose/Functional/Detection.lua @@ -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 diff --git a/Moose Development/Moose/Functional/Spawn.lua b/Moose Development/Moose/Functional/Spawn.lua index 77a6c48c0..c99e82d6e 100644 --- a/Moose Development/Moose/Functional/Spawn.lua +++ b/Moose Development/Moose/Functional/Spawn.lua @@ -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 ) diff --git a/Moose Development/Moose/Utilities/Utils.lua b/Moose Development/Moose/Utilities/Utils.lua index 0416e9d9f..cce57959b 100644 --- a/Moose Development/Moose/Utilities/Utils.lua +++ b/Moose Development/Moose/Utilities/Utils.lua @@ -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