diff --git a/Moose Development/Moose/AIBalancer.lua b/Moose Development/Moose/AIBalancer.lua deleted file mode 100644 index 78e795f97..000000000 --- a/Moose Development/Moose/AIBalancer.lua +++ /dev/null @@ -1,283 +0,0 @@ ---- This module contains the AIBALANCER class. --- --- === --- --- 1) @{AIBalancer#AIBALANCER} class, extends @{Base#BASE} --- ======================================================= --- The @{AIBalancer#AIBALANCER} class controls the dynamic spawning of AI GROUPS depending on a SET_CLIENT. --- There will be as many AI GROUPS spawned as there at CLIENTS in SET_CLIENT not spawned. --- The AIBalancer uses the @{PatrolZone#PATROLZONE} class to make AI patrol an zone until the fuel treshold is reached. --- --- 1.1) AIBALANCER construction method: --- ------------------------------------ --- Create a new AIBALANCER object with the @{#AIBALANCER.New} method: --- --- * @{#AIBALANCER.New}: Creates a new AIBALANCER object. --- --- 1.2) AIBALANCER returns AI to Airbases: --- --------------------------------------- --- You can configure to have the AI to return to: --- --- * @{#AIBALANCER.ReturnToHomeAirbase}: Returns the AI to the home @{Airbase#AIRBASE}. --- * @{#AIBALANCER.ReturnToNearestAirbases}: Returns the AI to the nearest friendly @{Airbase#AIRBASE}. --- --- 1.3) AIBALANCER allows AI to patrol specific zones: --- --------------------------------------------------- --- Use @{AIBalancer#AIBALANCER.SetPatrolZone}() to specify a zone where the AI needs to patrol. --- --- === --- --- **API CHANGE HISTORY** --- ====================== --- --- The underlying change log documents the API changes. Please read this carefully. The following notation is used: --- --- * **Added** parts are expressed in bold type face. --- * _Removed_ parts are expressed in italic type face. --- --- Hereby the change log: --- --- 2016-08-17: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ) --- --- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! --- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. --- --- === --- --- AUTHORS and CONTRIBUTIONS --- ========================= --- --- ### Contributions: --- --- * **Dutch_Baron (James)**: Who you can search on the Eagle Dynamics Forums. --- Working together with James has resulted in the creation of the AIBALANCER class. --- James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) --- --- * **SNAFU**: --- Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. --- None of the script code has been used however within the new AIBALANCER moose class. --- --- ### Authors: --- --- * FlightControl: Framework Design & Programming --- --- @module AIBalancer - - - ---- AIBALANCER class --- @type AIBALANCER --- @field Set#SET_CLIENT SetClient --- @field Spawn#SPAWN SpawnAI --- @field #boolean ToNearestAirbase --- @field Set#SET_AIRBASE ReturnAirbaseSet --- @field DCSTypes#Distance ReturnTresholdRange --- @field #boolean ToHomeAirbase --- @field PatrolZone#PATROLZONE PatrolZone --- @extends Base#BASE -AIBALANCER = { - ClassName = "AIBALANCER", - PatrolZones = {}, - AIGroups = {}, -} - ---- Creates a new AIBALANCER object, building a set of units belonging to a coalitions, categories, countries, types or with defined prefix names. --- @param #AIBALANCER self --- @param SetClient A SET_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player). --- @param SpawnAI A SPAWN object that will spawn the AI units required, balancing the SetClient. --- @return #AIBALANCER self -function AIBALANCER:New( SetClient, SpawnAI ) - - -- Inherits from BASE - local self = BASE:Inherit( self, BASE:New() ) - - self.SetClient = SetClient - if type( SpawnAI ) == "table" then - if SpawnAI.ClassName and SpawnAI.ClassName == "SPAWN" then - self.SpawnAI = { SpawnAI } - else - local SpawnObjects = true - for SpawnObjectID, SpawnObject in pairs( SpawnAI ) do - if SpawnObject.ClassName and SpawnObject.ClassName == "SPAWN" then - self:E( SpawnObject.ClassName ) - else - self:E( "other object" ) - SpawnObjects = false - end - end - if SpawnObjects == true then - self.SpawnAI = SpawnAI - else - error( "No SPAWN object given in parameter SpawnAI, either as a single object or as a table of objects!" ) - end - end - end - - self.ToNearestAirbase = false - self.ReturnHomeAirbase = false - - self.AIMonitorSchedule = SCHEDULER:New( self, self._ClientAliveMonitorScheduler, {}, 1, 10, 0 ) - - return self -end - ---- Returns the AI to the nearest friendly @{Airbase#AIRBASE}. --- @param #AIBALANCER self --- @param DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. --- @param Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Set#SET_AIRBASE}s to evaluate where to return to. -function AIBALANCER:ReturnToNearestAirbases( ReturnTresholdRange, ReturnAirbaseSet ) - - self.ToNearestAirbase = true - self.ReturnTresholdRange = ReturnTresholdRange - self.ReturnAirbaseSet = ReturnAirbaseSet -end - ---- Returns the AI to the home @{Airbase#AIRBASE}. --- @param #AIBALANCER self --- @param DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. -function AIBALANCER:ReturnToHomeAirbase( ReturnTresholdRange ) - - self.ToHomeAirbase = true - self.ReturnTresholdRange = ReturnTresholdRange -end - ---- Let the AI patrol a @{Zone} with a given Speed range and Altitude range. --- @param #AIBALANCER self --- @param PatrolZone#PATROLZONE PatrolZone The @{PatrolZone} where the AI needs to patrol. --- @return PatrolZone#PATROLZONE self -function AIBALANCER:SetPatrolZone( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitude, PatrolMinSpeed, PatrolMaxSpeed ) - - self.PatrolZone = PATROLZONE:New( - self.SpawnAI, - PatrolZone, - PatrolFloorAltitude, - PatrolCeilingAltitude, - PatrolMinSpeed, - PatrolMaxSpeed - ) -end - ---- Get the @{PatrolZone} object assigned by the @{AIBalancer} object. --- @param #AIBALANCER self --- @return PatrolZone#PATROLZONE PatrolZone The @{PatrolZone} where the AI needs to patrol. -function AIBALANCER:GetPatrolZone() - - return self.PatrolZone -end - - - ---- @param #AIBALANCER self -function AIBALANCER:_ClientAliveMonitorScheduler() - - self.SetClient:ForEachClient( - --- @param Client#CLIENT Client - function( Client ) - local ClientAIAliveState = Client:GetState( self, 'AIAlive' ) - self:T( ClientAIAliveState ) - if Client:IsAlive() then - if ClientAIAliveState == true then - Client:SetState( self, 'AIAlive', false ) - - local AIGroup = self.AIGroups[Client.UnitName] -- Group#GROUP - --- local PatrolZone = Client:GetState( self, "PatrolZone" ) --- if PatrolZone then --- PatrolZone = nil --- Client:ClearState( self, "PatrolZone" ) --- end - - if self.ToNearestAirbase == false and self.ToHomeAirbase == false then - AIGroup:Destroy() - else - -- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group. - -- If there is a CLIENT, the AI stays engaged and will not return. - -- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected. - - local PlayerInRange = { Value = false } - local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange ) - - self:E( RangeZone ) - - _DATABASE:ForEachPlayer( - --- @param Unit#UNIT RangeTestUnit - function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange ) - self:E( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } ) - if RangeTestUnit:IsInZone( RangeZone ) == true then - self:E( "in zone" ) - if RangeTestUnit:GetCoalition() ~= AIGroup:GetCoalition() then - self:E( "in range" ) - PlayerInRange.Value = true - end - end - end, - - --- @param Zone#ZONE_RADIUS RangeZone - -- @param Group#GROUP AIGroup - function( RangeZone, AIGroup, PlayerInRange ) - local AIGroupTemplate = AIGroup:GetTemplate() - if PlayerInRange.Value == false then - if self.ToHomeAirbase == true then - local WayPointCount = #AIGroupTemplate.route.points - local SwitchWayPointCommand = AIGroup:CommandSwitchWayPoint( 1, WayPointCount, 1 ) - AIGroup:SetCommand( SwitchWayPointCommand ) - AIGroup:MessageToRed( "Returning to home base ...", 30 ) - else - -- Okay, we need to send this Group back to the nearest base of the Coalition of the AI. - --TODO: i need to rework the POINT_VEC2 thing. - local PointVec2 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y ) - local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 ) - self:T( ClosestAirbase.AirbaseName ) - AIGroup:MessageToRed( "Returning to " .. ClosestAirbase:GetName().. " ...", 30 ) - local RTBRoute = AIGroup:RouteReturnToAirbase( ClosestAirbase ) - AIGroupTemplate.route = RTBRoute - AIGroup:Respawn( AIGroupTemplate ) - end - end - end - , RangeZone, AIGroup, PlayerInRange - ) - - end - end - else - if not ClientAIAliveState or ClientAIAliveState == false then - Client:SetState( self, 'AIAlive', true ) - - - -- OK, spawn a new group from the SpawnAI objects provided. - local SpawnAICount = #self.SpawnAI - local SpawnAIIndex = math.random( 1, SpawnAICount ) - local AIGroup = self.SpawnAI[SpawnAIIndex]:Spawn() - AIGroup:E( "spawning new AIGroup" ) - --TODO: need to rework UnitName thing ... - self.AIGroups[Client.UnitName] = AIGroup - - --- Now test if the AIGroup needs to patrol a zone, otherwise let it follow its route... - if self.PatrolZone then - self.PatrolZones[#self.PatrolZones+1] = PATROLZONE:New( - self.PatrolZone.PatrolZone, - self.PatrolZone.PatrolFloorAltitude, - self.PatrolZone.PatrolCeilingAltitude, - self.PatrolZone.PatrolMinSpeed, - self.PatrolZone.PatrolMaxSpeed - ) - - if self.PatrolZone.PatrolManageFuel == true then - self.PatrolZones[#self.PatrolZones]:ManageFuel( self.PatrolZone.PatrolFuelTresholdPercentage, self.PatrolZone.PatrolOutOfFuelOrbitTime ) - end - self.PatrolZones[#self.PatrolZones]:SetGroup( AIGroup ) - - --self.PatrolZones[#self.PatrolZones+1] = PatrolZone - - --Client:SetState( self, "PatrolZone", PatrolZone ) - end - end - end - end - ) - return true -end - - - diff --git a/Moose Development/Moose/AISet_Balancer.lua b/Moose Development/Moose/AISet_Balancer.lua new file mode 100644 index 000000000..60d8ea1d8 --- /dev/null +++ b/Moose Development/Moose/AISet_Balancer.lua @@ -0,0 +1,253 @@ +--- This module contains the AISET_BALANCER class. +-- +-- === +-- +-- 1) @{AISet_Balancer#AISET_BALANCER} class, extends @{StateMachine#STATEMACHINE_SET} +-- =================================================================================== +-- The @{AISet_Balancer#AISET_BALANCER} class monitors and manages as many AI GROUPS as there are +-- CLIENTS in a SET_CLIENT collection not occupied by players. +-- The AI_BALANCER class manages internally a collection of AI_MANAGEMENT objects, which govern the behaviour +-- of the underlying AI GROUPS. +-- +-- The parent class @{StateMachine#STATEMACHINE_SET} manages the functionality to control the Finite State Machine (FSM) +-- and calls for each event the state transition functions providing the internal @{StateMachine#STATEMACHINE_SET.Set} object containing the +-- SET_GROUP and additional event parameters provided during the event. +-- +-- 1.1) AISET_BALANCER construction method +-- --------------------------------------- +-- Create a new AISET_BALANCER object with the @{#AISET_BALANCER.New} method: +-- +-- * @{#AISET_BALANCER.New}: Creates a new AISET_BALANCER object. +-- +-- 1.2) +-- ---- +-- * Add +-- * Remove +-- +-- 1.2) AISET_BALANCER returns AI to Airbases +-- ------------------------------------------ +-- You can configure to have the AI to return to: +-- +-- * @{#AISET_BALANCER.ReturnToHomeAirbase}: Returns the AI to the home @{Airbase#AIRBASE}. +-- * @{#AISET_BALANCER.ReturnToNearestAirbases}: Returns the AI to the nearest friendly @{Airbase#AIRBASE}. +-- -- +-- === +-- +-- **API CHANGE HISTORY** +-- ====================== +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2016-08-17: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ) +-- +-- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! +-- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. +-- +-- === +-- +-- AUTHORS and CONTRIBUTIONS +-- ========================= +-- +-- ### Contributions: +-- +-- * **Dutch_Baron (James)**: Who you can search on the Eagle Dynamics Forums. +-- Working together with James has resulted in the creation of the AISET_BALANCER class. +-- James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) +-- +-- * **SNAFU**: +-- Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. +-- None of the script code has been used however within the new AISET_BALANCER moose class. +-- +-- ### Authors: +-- +-- * FlightControl: Framework Design & Programming +-- +-- @module AISet_Balancer + + + +--- AISET_BALANCER class +-- @type AISET_BALANCER +-- @field Set#SET_CLIENT SetClient +-- @extends StateMachine#STATEMACHINE_SET +AISET_BALANCER = { + ClassName = "AISET_BALANCER", + PatrolZones = {}, + AIGroups = {}, +} + +--- Creates a new AI\_SET\_BALANCER object +-- @param #AISET_BALANCER self +-- @param Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player). +-- @param Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed. +-- @return #AISET_BALANCER +-- @usage +-- -- Define a new AISET_BALANCER Object. +function AISET_BALANCER:New( SetClient, SpawnAI ) + + local FSMT = { + initial = 'None', + events = { + { name = 'Start', from = '*', to = 'Monitoring' }, + { name = 'Monitor', from = '*', to = 'Monitoring' }, + { name = 'Spawn', from = '*', to = 'Spawning' }, + { name = 'Destroy', from = '*', to = 'Destroying' }, + { name = 'Return', from = '*', to = 'Returning' }, + { name = 'End', from = '*', to = 'End' }, + { name = 'Dead', from = '*', to = 'End' }, + }, + } + + -- Inherits from BASE + local self = BASE:Inherit( self, STATEMACHINE_SET:New( FSMT, SET_GROUP:New() ) ) + + self.SetClient = SetClient + self.SpawnAI = SpawnAI + self.ToNearestAirbase = false + self.ToHomeAirbase = false + + self:__Start( 1 ) + + return self +end + +--- Returns the AI to the nearest friendly @{Airbase#AIRBASE}. +-- @param #AISET_BALANCER self +-- @param DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. +-- @param Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Set#SET_AIRBASE}s to evaluate where to return to. +function AISET_BALANCER:ReturnToNearestAirbases( ReturnTresholdRange, ReturnAirbaseSet ) + + self.ToNearestAirbase = true + self.ReturnTresholdRange = ReturnTresholdRange + self.ReturnAirbaseSet = ReturnAirbaseSet +end + +--- Returns the AI to the home @{Airbase#AIRBASE}. +-- @param #AISET_BALANCER self +-- @param DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. +function AISET_BALANCER:ReturnToHomeAirbase( ReturnTresholdRange ) + + self.ToHomeAirbase = true + self.ReturnTresholdRange = ReturnTresholdRange +end + +--- @param #AISET_BALANCER self +-- @param Set#SET_GROUP SetGroup +-- @param #string ClientName +-- @param Group#GROUP AIGroup +function AISET_BALANCER:onenterSpawning( SetGroup, ClientName ) + + -- OK, Spawn a new group from the default SpawnAI object provided. + local AIGroup = self.SpawnAI:Spawn() + AIGroup:E( "Spawning new AIGroup" ) + --TODO: need to rework UnitName thing ... + + SetGroup:Add( ClientName, AIGroup ) +end + +--- @param #AISET_BALANCER self +-- @param Set#SET_GROUP SetGroup +-- @param Group#GROUP AIGroup +function AISET_BALANCER:onenterDestroying( SetGroup, AIGroup ) + + AIGroup:Destroy() +end + +--- @param #AISET_BALANCER self +-- @param Set#SET_GROUP SetGroup +-- @param Group#GROUP AIGroup +function AISET_BALANCER:onenterReturning( SetGroup, AIGroup ) + + local AIGroupTemplate = AIGroup:GetTemplate() + if self.ToHomeAirbase == true then + local WayPointCount = #AIGroupTemplate.route.points + local SwitchWayPointCommand = AIGroup:CommandSwitchWayPoint( 1, WayPointCount, 1 ) + AIGroup:SetCommand( SwitchWayPointCommand ) + AIGroup:MessageToRed( "Returning to home base ...", 30 ) + else + -- Okay, we need to send this Group back to the nearest base of the Coalition of the AI. + --TODO: i need to rework the POINT_VEC2 thing. + local PointVec2 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y ) + local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 ) + self:T( ClosestAirbase.AirbaseName ) + AIGroup:MessageToRed( "Returning to " .. ClosestAirbase:GetName().. " ...", 30 ) + local RTBRoute = AIGroup:RouteReturnToAirbase( ClosestAirbase ) + AIGroupTemplate.route = RTBRoute + AIGroup:Respawn( AIGroupTemplate ) + end + +end + + +--- @param #AISET_BALANCER self +function AISET_BALANCER:onenterMonitoring( SetGroup ) + + self.SetClient:ForEachClient( + --- @param Client#CLIENT Client + function( Client ) + self:E(Client.ClientName) + + local AIGroup = self.Set:Get( Client.UnitName ) -- Group#GROUP + if Client:IsAlive() then + + if AIGroup and AIGroup:IsAlive() == true then + + if self.ToNearestAirbase == false and self.ToHomeAirbase == false then + self:Destroy( AIGroup ) + else + -- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group. + -- If there is a CLIENT, the AI stays engaged and will not return. + -- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected. + + local PlayerInRange = { Value = false } + local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange ) + + self:E( RangeZone ) + + _DATABASE:ForEachPlayer( + --- @param Unit#UNIT RangeTestUnit + function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange ) + self:E( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } ) + if RangeTestUnit:IsInZone( RangeZone ) == true then + self:E( "in zone" ) + if RangeTestUnit:GetCoalition() ~= AIGroup:GetCoalition() then + self:E( "in range" ) + PlayerInRange.Value = true + end + end + end, + + --- @param Zone#ZONE_RADIUS RangeZone + -- @param Group#GROUP AIGroup + function( RangeZone, AIGroup, PlayerInRange ) + if PlayerInRange.Value == false then + self:Return( AIGroup ) + end + end + , RangeZone, AIGroup, PlayerInRange + ) + + end + self.Set:Remove( Client.UnitName ) + end + else + if not AIGroup or not AIGroup:IsAlive() == true then + self:E("client not alive") + self:Spawn( Client.UnitName ) + self:E("text after spawn") + end + end + return true + end + ) + + self:__Monitor( 10 ) +end + + + diff --git a/Moose Development/Moose/Base.lua b/Moose Development/Moose/Base.lua index b8559f421..e3b6ec8b9 100644 --- a/Moose Development/Moose/Base.lua +++ b/Moose Development/Moose/Base.lua @@ -350,7 +350,7 @@ function BASE:GetState( Object, StateName ) local ClassNameAndID = Object:GetClassNameAndID() if self.States[ClassNameAndID] then - local State = self.States[ClassNameAndID][StateName] + local State = self.States[ClassNameAndID][StateName] or false self:T2( { ClassNameAndID, StateName, State } ) return State end diff --git a/Moose Development/Moose/Moose.lua b/Moose Development/Moose/Moose.lua index bf750f05b..0f41db202 100644 --- a/Moose Development/Moose/Moose.lua +++ b/Moose Development/Moose/Moose.lua @@ -34,7 +34,6 @@ Include.File( "Movement" ) Include.File( "Sead" ) Include.File( "Escort" ) Include.File( "MissileTrainer" ) ---Include.File( "AIBalancer" ) Include.File( "AirbasePolice" ) Include.File( "Detection" ) @@ -54,7 +53,10 @@ Include.File( "Task" ) Include.File( "Task_SEAD" ) Include.File( "Task_A2G" ) ---- AI Handling Classes +--- AI Set Handling Classes +Include.File( "AISet_Balancer" ) + +--- AI Task Handling Classes Include.File( "AI_PatrolZone" ) -- The order of the declarations is important here. Don't touch it. diff --git a/Moose Development/Moose/Set.lua b/Moose Development/Moose/Set.lua index 2556694c5..013e938ca 100644 --- a/Moose Development/Moose/Set.lua +++ b/Moose Development/Moose/Set.lua @@ -349,6 +349,21 @@ function SET_BASE:Remove( ObjectName ) end +--- Gets a @{Base#BASE} object from the @{Set#SET_BASE} and derived classes, based on the Object Name. +-- @param #SET_BASE self +-- @param #string ObjectName +-- @return Base#BASE +function SET_BASE:Get( ObjectName ) + self:F( ObjectName ) + + local t = self.Set[ObjectName] + + self:T3( { ObjectName, t } ) + + return t + +end + --- Retrieves the amount of objects in the @{Set#SET_BASE} and derived classes. -- @param #SET_BASE self -- @return #number Count diff --git a/Moose Development/Moose/Spawn.lua b/Moose Development/Moose/Spawn.lua index 4b24ad913..8397e67de 100644 --- a/Moose Development/Moose/Spawn.lua +++ b/Moose Development/Moose/Spawn.lua @@ -1534,47 +1534,35 @@ function SPAWN:_SpawnCleanUpScheduler() local Stamp = self.SpawnCleanUpTimeStamps[SpawnUnitName] self:T( { SpawnUnitName, Stamp } ) - if Stamp.Moved then - if SpawnUnit:InAir() == false then - if SpawnUnit:GetVelocityKMH() < 1 then + if Stamp.Vec2 then + if SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1 then + local NewVec2 = SpawnUnit:GetVec2() + if Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y then -- If the plane is not moving, and is on the ground, assign it with a timestamp... - if not Stamp.Time then - Stamp.Time = timer.getTime() - else - if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then - self:T( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } ) - self:ReSpawn( SpawnCursor ) - Stamp.Moved = nil - Stamp.Time = nil - end - end + if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then + self:T( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } ) + self:ReSpawn( SpawnCursor ) + Stamp.Vec2 = nil + Stamp.Time = nil + end else - Stamp.Time = nil + Stamp.Time = timer.getTime() + Stamp.Vec2 = SpawnUnit:GetVec2() end else - Stamp.Moved = nil + Stamp.Vec2 = nil Stamp.Time = nil end else - if SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() > 1 then - Stamp.Moved = true - else - -- If the plane did not move and on the runway for about 3 minutes, clean it. - if SpawnUnit:IsAboveRunway() and SpawnUnit:GetVelocityKMH() < 1 then - if not Stamp.Time then - Stamp.Time = timer.getTime() - end - if Stamp.Time + 180 < timer.getTime() then - self:T( { "CleanUp Scheduler:", "ReSpawning inactive group:", SpawnGroup:GetName() } ) - self:ReSpawn( SpawnCursor ) - Stamp.Moved = nil - Stamp.Time = nil - end - else - Stamp.Moved = nil - Stamp.Time = nil + if SpawnUnit:InAir() == false then + Stamp.Vec2 = SpawnUnit:GetVec2() + if SpawnUnit:GetVelocityKMH() < 1 then + Stamp.Time = timer.getTime() end - end + else + Stamp.Time = nil + Stamp.Vec2 = nil + end end end diff --git a/Moose Development/Moose/StateMachine.lua b/Moose Development/Moose/StateMachine.lua index e6f3e6bd1..d658fa179 100644 --- a/Moose Development/Moose/StateMachine.lua +++ b/Moose Development/Moose/StateMachine.lua @@ -1,15 +1,15 @@ --- This module contains the STATEMACHINE class. --- This development is based on a state machine implementation made by Conroy Kyle. --- The state machine can be found here: https://github.com/kyleconroy/lua-state-machine --- --- I've taken the development and enhanced it to make the state machine hierarchical... +-- This development is based on a state machine implementation made by Conroy Kyle. +-- The state machine can be found here: https://github.com/kyleconroy/lua-state-machine +-- +-- I've taken the development and enhanced it to make the state machine hierarchical... -- It is a fantastic development, this module. --- +-- -- === --- +-- -- 1) @{Workflow#STATEMACHINE} class, extends @{Base#BASE} -- ============================================== --- +-- -- 1.1) Add or remove objects from the STATEMACHINE -- -------------------------------------------- -- @module StateMachine @@ -55,15 +55,15 @@ function STATEMACHINE:New( options ) self.events[name] = self.events[name] or { map = {} } self:_add_to_map(self.events[name].map, event) end - + for name, callback in pairs(options.callbacks or {}) do self[name] = callback end - + for name, sub in pairs( options.subs or {} ) do self:_submap( self.subs, sub, name ) end - + for name, endstate in pairs( options.endstates or {} ) do self.endstates[endstate] = endstate end @@ -105,7 +105,7 @@ function STATEMACHINE._handler( self, EventName, ... ) local can, to = self:can(EventName) self:T( { EventName, can, to } ) - + local ReturnValues = nil if can then @@ -113,14 +113,14 @@ function STATEMACHINE._handler( self, EventName, ... ) local params = { ..., EventName, from, to } if self:_call_handler(self["onbefore" .. EventName], params) == false - or self:_call_handler(self["onleave" .. from], params) == false then + or self:_call_handler(self["onleave" .. from], params) == false then return false end self.current = to - + local execute = true - + local subtable = self:_gosub( to, EventName ) for _, sub in pairs( subtable ) do self:F2( "calling sub: " .. sub.event ) @@ -129,7 +129,7 @@ function STATEMACHINE._handler( self, EventName, ... ) sub.fsm[sub.event]( sub.fsm ) execute = true end - + local fsmparent, event = self:_isendstate( to ) if fsmparent and event then self:F2( { "end state: ", fsmparent, event } ) @@ -143,20 +143,20 @@ function STATEMACHINE._handler( self, EventName, ... ) if execute then self:T3( { onenter = "onenter" .. to, callback = self["onenter" .. to] } ) self:_call_handler(self["onenter" .. to] or self["on" .. to], params) - + self:T3( { On = "OnBefore" .. to, callback = self["OnBefore" .. to] } ) if ( self:_call_handler(self["OnBefore" .. to], params ) ~= false ) then self:T3( { onafter = "onafter" .. EventName, callback = self["onafter" .. EventName] } ) self:_call_handler(self["onafter" .. EventName] or self["on" .. EventName], params) - + self:T3( { On = "OnAfter" .. to, callback = self["OnAfter" .. to] } ) ReturnValues = self:_call_handler(self["OnAfter" .. to], params ) end self:_call_handler(self["onstatechange"], params) end - + return ReturnValues end @@ -167,7 +167,7 @@ function STATEMACHINE:_delayed_transition( EventName ) self:E( { EventName = EventName } ) return function( self, DelaySeconds, ... ) self:T( "Delayed Event: " .. EventName ) - SCHEDULER:New( self, self._handler, { EventName, ... }, DelaySeconds ) + SCHEDULER:New( self, self._handler, { EventName, ... }, DelaySeconds ) end end @@ -305,7 +305,7 @@ function STATEMACHINE_TASK:New( Task, TaskUnit, options ) FsmTask["onAssigned"] = Task.OnAssigned FsmTask["onSuccess"] = Task.OnSuccess FsmTask["onFailed"] = Task.OnFailed - + FsmTask.Task = Task FsmTask.TaskUnit = TaskUnit @@ -335,7 +335,7 @@ function STATEMACHINE_CONTROLLABLE:New( FSMT, Controllable ) -- Inherits from BASE local self = BASE:Inherit( self, STATEMACHINE:New( FSMT ) ) -- StateMachine#STATEMACHINE_CONTROLLABLE - + if Controllable then self:SetControllable( Controllable ) end @@ -363,4 +363,55 @@ function STATEMACHINE_CONTROLLABLE:_call_handler( handler, params ) if handler then return handler( self, self.Controllable, unpack( params ) ) end -end \ No newline at end of file +end + +do -- STATEMACHINE_SET + +--- STATEMACHINE_SET class +-- @type STATEMACHINE_SET +-- @field Set#SET_BASE Set +-- @extends StateMachine#STATEMACHINE +STATEMACHINE_SET = { + ClassName = "STATEMACHINE_SET", +} + +--- Creates a new STATEMACHINE_SET object. +-- @param #STATEMACHINE_SET self +-- @param #table FSMT Finite State Machine Table +-- @param Set_SET_BASE FSMSet (optional) The Set object that the STATEMACHINE_SET governs. +-- @return #STATEMACHINE_SET +function STATEMACHINE_SET:New( FSMT, FSMSet ) + + -- Inherits from BASE + local self = BASE:Inherit( self, STATEMACHINE:New( FSMT ) ) -- StateMachine#STATEMACHINE_SET + + if FSMSet then + self:Set( FSMSet ) + end + + return self +end + +--- Sets the SET_BASE object that the STATEMACHINE_SET governs. +-- @param #STATEMACHINE_SET self +-- @param Set#SET_BASE FSMSet +-- @return #STATEMACHINE_SET +function STATEMACHINE_SET:Set( FSMSet ) + self:F( FSMSet ) + self.Set = FSMSet +end + +--- Gets the SET_BASE object that the STATEMACHINE_SET governs. +-- @param #STATEMACHINE_SET self +-- @return Set#SET_BASE +function STATEMACHINE_SET:Get() + return self.Controllable +end + +function STATEMACHINE_SET:_call_handler( handler, params ) + if handler then + return handler( self, self.Set, unpack( params ) ) + end +end + +end diff --git a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua index 79ae94e91..203bb88f5 100644 --- a/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua +++ b/Moose Mission Setup/Moose Mission Update/l10n/DEFAULT/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE STATIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20160823_0655' ) +env.info( 'Moose Generation Timestamp: 20160824_1433' ) local base = _G Include = {} @@ -3142,7 +3142,7 @@ function BASE:GetState( Object, StateName ) local ClassNameAndID = Object:GetClassNameAndID() if self.States[ClassNameAndID] then - local State = self.States[ClassNameAndID][StateName] + local State = self.States[ClassNameAndID][StateName] or false self:T2( { ClassNameAndID, StateName, State } ) return State end @@ -12462,6 +12462,21 @@ function SET_BASE:Remove( ObjectName ) end +--- Gets a @{Base#BASE} object from the @{Set#SET_BASE} and derived classes, based on the Object Name. +-- @param #SET_BASE self +-- @param #string ObjectName +-- @return Base#BASE +function SET_BASE:Get( ObjectName ) + self:F( ObjectName ) + + local t = self.Set[ObjectName] + + self:T3( { ObjectName, t } ) + + return t + +end + --- Retrieves the amount of objects in the @{Set#SET_BASE} and derived classes. -- @param #SET_BASE self -- @return #number Count @@ -15082,7 +15097,6 @@ Include.File( "Movement" ) Include.File( "Sead" ) Include.File( "Escort" ) Include.File( "MissileTrainer" ) ---Include.File( "AIBalancer" ) Include.File( "AirbasePolice" ) Include.File( "Detection" ) @@ -15102,7 +15116,10 @@ Include.File( "Task" ) Include.File( "Task_SEAD" ) Include.File( "Task_A2G" ) ---- AI Handling Classes +--- AI Set Handling Classes +Include.File( "AISet_Balancer" ) + +--- AI Task Handling Classes Include.File( "AI_PatrolZone" ) -- The order of the declarations is important here. Don't touch it. @@ -20088,47 +20105,35 @@ function SPAWN:_SpawnCleanUpScheduler() local Stamp = self.SpawnCleanUpTimeStamps[SpawnUnitName] self:T( { SpawnUnitName, Stamp } ) - if Stamp.Moved then - if SpawnUnit:InAir() == false then - if SpawnUnit:GetVelocityKMH() < 1 then + if Stamp.Vec2 then + if SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1 then + local NewVec2 = SpawnUnit:GetVec2() + if Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y then -- If the plane is not moving, and is on the ground, assign it with a timestamp... - if not Stamp.Time then - Stamp.Time = timer.getTime() - else - if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then - self:T( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } ) - self:ReSpawn( SpawnCursor ) - Stamp.Moved = nil - Stamp.Time = nil - end - end + if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then + self:T( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } ) + self:ReSpawn( SpawnCursor ) + Stamp.Vec2 = nil + Stamp.Time = nil + end else - Stamp.Time = nil + Stamp.Time = timer.getTime() + Stamp.Vec2 = SpawnUnit:GetVec2() end else - Stamp.Moved = nil + Stamp.Vec2 = nil Stamp.Time = nil end else - if SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() > 1 then - Stamp.Moved = true - else - -- If the plane did not move and on the runway for about 3 minutes, clean it. - if SpawnUnit:IsAboveRunway() and SpawnUnit:GetVelocityKMH() < 1 then - if not Stamp.Time then - Stamp.Time = timer.getTime() - end - if Stamp.Time + 180 < timer.getTime() then - self:T( { "CleanUp Scheduler:", "ReSpawning inactive group:", SpawnGroup:GetName() } ) - self:ReSpawn( SpawnCursor ) - Stamp.Moved = nil - Stamp.Time = nil - end - else - Stamp.Moved = nil - Stamp.Time = nil + if SpawnUnit:InAir() == false then + Stamp.Vec2 = SpawnUnit:GetVec2() + if SpawnUnit:GetVelocityKMH() < 1 then + Stamp.Time = timer.getTime() end - end + else + Stamp.Time = nil + Stamp.Vec2 = nil + end end end @@ -25066,17 +25071,17 @@ do -- DETECTION_DISPATCHER end end--- This module contains the STATEMACHINE class. --- This development is based on a state machine implementation made by Conroy Kyle. --- The state machine can be found here: https://github.com/kyleconroy/lua-state-machine --- --- I've taken the development and enhanced it to make the state machine hierarchical... +-- This development is based on a state machine implementation made by Conroy Kyle. +-- The state machine can be found here: https://github.com/kyleconroy/lua-state-machine +-- +-- I've taken the development and enhanced it to make the state machine hierarchical... -- It is a fantastic development, this module. --- +-- -- === --- +-- -- 1) @{Workflow#STATEMACHINE} class, extends @{Base#BASE} -- ============================================== --- +-- -- 1.1) Add or remove objects from the STATEMACHINE -- -------------------------------------------- -- @module StateMachine @@ -25122,15 +25127,15 @@ function STATEMACHINE:New( options ) self.events[name] = self.events[name] or { map = {} } self:_add_to_map(self.events[name].map, event) end - + for name, callback in pairs(options.callbacks or {}) do self[name] = callback end - + for name, sub in pairs( options.subs or {} ) do self:_submap( self.subs, sub, name ) end - + for name, endstate in pairs( options.endstates or {} ) do self.endstates[endstate] = endstate end @@ -25172,7 +25177,7 @@ function STATEMACHINE._handler( self, EventName, ... ) local can, to = self:can(EventName) self:T( { EventName, can, to } ) - + local ReturnValues = nil if can then @@ -25180,14 +25185,14 @@ function STATEMACHINE._handler( self, EventName, ... ) local params = { ..., EventName, from, to } if self:_call_handler(self["onbefore" .. EventName], params) == false - or self:_call_handler(self["onleave" .. from], params) == false then + or self:_call_handler(self["onleave" .. from], params) == false then return false end self.current = to - + local execute = true - + local subtable = self:_gosub( to, EventName ) for _, sub in pairs( subtable ) do self:F2( "calling sub: " .. sub.event ) @@ -25196,7 +25201,7 @@ function STATEMACHINE._handler( self, EventName, ... ) sub.fsm[sub.event]( sub.fsm ) execute = true end - + local fsmparent, event = self:_isendstate( to ) if fsmparent and event then self:F2( { "end state: ", fsmparent, event } ) @@ -25210,20 +25215,20 @@ function STATEMACHINE._handler( self, EventName, ... ) if execute then self:T3( { onenter = "onenter" .. to, callback = self["onenter" .. to] } ) self:_call_handler(self["onenter" .. to] or self["on" .. to], params) - + self:T3( { On = "OnBefore" .. to, callback = self["OnBefore" .. to] } ) if ( self:_call_handler(self["OnBefore" .. to], params ) ~= false ) then self:T3( { onafter = "onafter" .. EventName, callback = self["onafter" .. EventName] } ) self:_call_handler(self["onafter" .. EventName] or self["on" .. EventName], params) - + self:T3( { On = "OnAfter" .. to, callback = self["OnAfter" .. to] } ) ReturnValues = self:_call_handler(self["OnAfter" .. to], params ) end self:_call_handler(self["onstatechange"], params) end - + return ReturnValues end @@ -25234,7 +25239,7 @@ function STATEMACHINE:_delayed_transition( EventName ) self:E( { EventName = EventName } ) return function( self, DelaySeconds, ... ) self:T( "Delayed Event: " .. EventName ) - SCHEDULER:New( self, self._handler, { EventName, ... }, DelaySeconds ) + SCHEDULER:New( self, self._handler, { EventName, ... }, DelaySeconds ) end end @@ -25372,7 +25377,7 @@ function STATEMACHINE_TASK:New( Task, TaskUnit, options ) FsmTask["onAssigned"] = Task.OnAssigned FsmTask["onSuccess"] = Task.OnSuccess FsmTask["onFailed"] = Task.OnFailed - + FsmTask.Task = Task FsmTask.TaskUnit = TaskUnit @@ -25402,7 +25407,7 @@ function STATEMACHINE_CONTROLLABLE:New( FSMT, Controllable ) -- Inherits from BASE local self = BASE:Inherit( self, STATEMACHINE:New( FSMT ) ) -- StateMachine#STATEMACHINE_CONTROLLABLE - + if Controllable then self:SetControllable( Controllable ) end @@ -25430,7 +25435,59 @@ function STATEMACHINE_CONTROLLABLE:_call_handler( handler, params ) if handler then return handler( self, self.Controllable, unpack( params ) ) end -end--- @module Process +end + +do -- STATEMACHINE_SET + +--- STATEMACHINE_SET class +-- @type STATEMACHINE_SET +-- @field Set#SET_BASE Set +-- @extends StateMachine#STATEMACHINE +STATEMACHINE_SET = { + ClassName = "STATEMACHINE_SET", +} + +--- Creates a new STATEMACHINE_SET object. +-- @param #STATEMACHINE_SET self +-- @param #table FSMT Finite State Machine Table +-- @param Set_SET_BASE FSMSet (optional) The Set object that the STATEMACHINE_SET governs. +-- @return #STATEMACHINE_SET +function STATEMACHINE_SET:New( FSMT, FSMSet ) + + -- Inherits from BASE + local self = BASE:Inherit( self, STATEMACHINE:New( FSMT ) ) -- StateMachine#STATEMACHINE_SET + + if FSMSet then + self:Set( FSMSet ) + end + + return self +end + +--- Sets the SET_BASE object that the STATEMACHINE_SET governs. +-- @param #STATEMACHINE_SET self +-- @param Set#SET_BASE FSMSet +-- @return #STATEMACHINE_SET +function STATEMACHINE_SET:Set( FSMSet ) + self:F( FSMSet ) + self.Set = FSMSet +end + +--- Gets the SET_BASE object that the STATEMACHINE_SET governs. +-- @param #STATEMACHINE_SET self +-- @return Set#SET_BASE +function STATEMACHINE_SET:Get() + return self.Controllable +end + +function STATEMACHINE_SET:_call_handler( handler, params ) + if handler then + return handler( self, self.Set, unpack( params ) ) + end +end + +end +--- @module Process --- The PROCESS class -- @type PROCESS @@ -27437,6 +27494,259 @@ end +--- This module contains the AISET_BALANCER class. +-- +-- === +-- +-- 1) @{AISet_Balancer#AISET_BALANCER} class, extends @{StateMachine#STATEMACHINE_SET} +-- =================================================================================== +-- The @{AISet_Balancer#AISET_BALANCER} class monitors and manages as many AI GROUPS as there are +-- CLIENTS in a SET_CLIENT collection not occupied by players. +-- The AI_BALANCER class manages internally a collection of AI_MANAGEMENT objects, which govern the behaviour +-- of the underlying AI GROUPS. +-- +-- The parent class @{StateMachine#STATEMACHINE_SET} manages the functionality to control the Finite State Machine (FSM) +-- and calls for each event the state transition functions providing the internal @{StateMachine#STATEMACHINE_SET.Set} object containing the +-- SET_GROUP and additional event parameters provided during the event. +-- +-- 1.1) AISET_BALANCER construction method +-- --------------------------------------- +-- Create a new AISET_BALANCER object with the @{#AISET_BALANCER.New} method: +-- +-- * @{#AISET_BALANCER.New}: Creates a new AISET_BALANCER object. +-- +-- 1.2) +-- ---- +-- * Add +-- * Remove +-- +-- 1.2) AISET_BALANCER returns AI to Airbases +-- ------------------------------------------ +-- You can configure to have the AI to return to: +-- +-- * @{#AISET_BALANCER.ReturnToHomeAirbase}: Returns the AI to the home @{Airbase#AIRBASE}. +-- * @{#AISET_BALANCER.ReturnToNearestAirbases}: Returns the AI to the nearest friendly @{Airbase#AIRBASE}. +-- -- +-- === +-- +-- **API CHANGE HISTORY** +-- ====================== +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2016-08-17: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ) +-- +-- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! +-- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. +-- +-- === +-- +-- AUTHORS and CONTRIBUTIONS +-- ========================= +-- +-- ### Contributions: +-- +-- * **Dutch_Baron (James)**: Who you can search on the Eagle Dynamics Forums. +-- Working together with James has resulted in the creation of the AISET_BALANCER class. +-- James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) +-- +-- * **SNAFU**: +-- Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. +-- None of the script code has been used however within the new AISET_BALANCER moose class. +-- +-- ### Authors: +-- +-- * FlightControl: Framework Design & Programming +-- +-- @module AISet_Balancer + + + +--- AISET_BALANCER class +-- @type AISET_BALANCER +-- @field Set#SET_CLIENT SetClient +-- @extends StateMachine#STATEMACHINE_SET +AISET_BALANCER = { + ClassName = "AISET_BALANCER", + PatrolZones = {}, + AIGroups = {}, +} + +--- Creates a new AI\_SET\_BALANCER object +-- @param #AISET_BALANCER self +-- @param Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player). +-- @param Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed. +-- @return #AISET_BALANCER +-- @usage +-- -- Define a new AISET_BALANCER Object. +function AISET_BALANCER:New( SetClient, SpawnAI ) + + local FSMT = { + initial = 'None', + events = { + { name = 'Start', from = '*', to = 'Monitoring' }, + { name = 'Monitor', from = '*', to = 'Monitoring' }, + { name = 'Spawn', from = '*', to = 'Spawning' }, + { name = 'Destroy', from = '*', to = 'Destroying' }, + { name = 'Return', from = '*', to = 'Returning' }, + { name = 'End', from = '*', to = 'End' }, + { name = 'Dead', from = '*', to = 'End' }, + }, + } + + -- Inherits from BASE + local self = BASE:Inherit( self, STATEMACHINE_SET:New( FSMT, SET_GROUP:New() ) ) + + self.SetClient = SetClient + self.SpawnAI = SpawnAI + self.ToNearestAirbase = false + self.ToHomeAirbase = false + + self:__Start( 1 ) + + return self +end + +--- Returns the AI to the nearest friendly @{Airbase#AIRBASE}. +-- @param #AISET_BALANCER self +-- @param DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. +-- @param Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Set#SET_AIRBASE}s to evaluate where to return to. +function AISET_BALANCER:ReturnToNearestAirbases( ReturnTresholdRange, ReturnAirbaseSet ) + + self.ToNearestAirbase = true + self.ReturnTresholdRange = ReturnTresholdRange + self.ReturnAirbaseSet = ReturnAirbaseSet +end + +--- Returns the AI to the home @{Airbase#AIRBASE}. +-- @param #AISET_BALANCER self +-- @param DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. +function AISET_BALANCER:ReturnToHomeAirbase( ReturnTresholdRange ) + + self.ToHomeAirbase = true + self.ReturnTresholdRange = ReturnTresholdRange +end + +--- @param #AISET_BALANCER self +-- @param Set#SET_GROUP SetGroup +-- @param #string ClientName +-- @param Group#GROUP AIGroup +function AISET_BALANCER:onenterSpawning( SetGroup, ClientName ) + + -- OK, Spawn a new group from the default SpawnAI object provided. + local AIGroup = self.SpawnAI:Spawn() + AIGroup:E( "Spawning new AIGroup" ) + --TODO: need to rework UnitName thing ... + + SetGroup:Add( ClientName, AIGroup ) +end + +--- @param #AISET_BALANCER self +-- @param Set#SET_GROUP SetGroup +-- @param Group#GROUP AIGroup +function AISET_BALANCER:onenterDestroying( SetGroup, AIGroup ) + + AIGroup:Destroy() +end + +--- @param #AISET_BALANCER self +-- @param Set#SET_GROUP SetGroup +-- @param Group#GROUP AIGroup +function AISET_BALANCER:onenterReturning( SetGroup, AIGroup ) + + local AIGroupTemplate = AIGroup:GetTemplate() + if self.ToHomeAirbase == true then + local WayPointCount = #AIGroupTemplate.route.points + local SwitchWayPointCommand = AIGroup:CommandSwitchWayPoint( 1, WayPointCount, 1 ) + AIGroup:SetCommand( SwitchWayPointCommand ) + AIGroup:MessageToRed( "Returning to home base ...", 30 ) + else + -- Okay, we need to send this Group back to the nearest base of the Coalition of the AI. + --TODO: i need to rework the POINT_VEC2 thing. + local PointVec2 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y ) + local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 ) + self:T( ClosestAirbase.AirbaseName ) + AIGroup:MessageToRed( "Returning to " .. ClosestAirbase:GetName().. " ...", 30 ) + local RTBRoute = AIGroup:RouteReturnToAirbase( ClosestAirbase ) + AIGroupTemplate.route = RTBRoute + AIGroup:Respawn( AIGroupTemplate ) + end + +end + + +--- @param #AISET_BALANCER self +function AISET_BALANCER:onenterMonitoring( SetGroup ) + + self.SetClient:ForEachClient( + --- @param Client#CLIENT Client + function( Client ) + self:E(Client.ClientName) + + local AIGroup = self.Set:Get( Client.UnitName ) -- Group#GROUP + if Client:IsAlive() then + + if AIGroup and AIGroup:IsAlive() == true then + + if self.ToNearestAirbase == false and self.ToHomeAirbase == false then + self:Destroy( AIGroup ) + else + -- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group. + -- If there is a CLIENT, the AI stays engaged and will not return. + -- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected. + + local PlayerInRange = { Value = false } + local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange ) + + self:E( RangeZone ) + + _DATABASE:ForEachPlayer( + --- @param Unit#UNIT RangeTestUnit + function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange ) + self:E( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } ) + if RangeTestUnit:IsInZone( RangeZone ) == true then + self:E( "in zone" ) + if RangeTestUnit:GetCoalition() ~= AIGroup:GetCoalition() then + self:E( "in range" ) + PlayerInRange.Value = true + end + end + end, + + --- @param Zone#ZONE_RADIUS RangeZone + -- @param Group#GROUP AIGroup + function( RangeZone, AIGroup, PlayerInRange ) + if PlayerInRange.Value == false then + self:Return( AIGroup ) + end + end + , RangeZone, AIGroup, PlayerInRange + ) + + end + self.Set:Remove( Client.UnitName ) + end + else + if not AIGroup or not AIGroup:IsAlive() == true then + self:E("client not alive") + self:Spawn( Client.UnitName ) + self:E("text after spawn") + end + end + return true + end + ) + + self:__Monitor( 10 ) +end + + + --- This module contains the AI\_PATROLZONE class. -- -- === diff --git a/Moose Mission Setup/Moose.lua b/Moose Mission Setup/Moose.lua index 79ae94e91..203bb88f5 100644 --- a/Moose Mission Setup/Moose.lua +++ b/Moose Mission Setup/Moose.lua @@ -1,5 +1,5 @@ env.info( '*** MOOSE STATIC INCLUDE START *** ' ) -env.info( 'Moose Generation Timestamp: 20160823_0655' ) +env.info( 'Moose Generation Timestamp: 20160824_1433' ) local base = _G Include = {} @@ -3142,7 +3142,7 @@ function BASE:GetState( Object, StateName ) local ClassNameAndID = Object:GetClassNameAndID() if self.States[ClassNameAndID] then - local State = self.States[ClassNameAndID][StateName] + local State = self.States[ClassNameAndID][StateName] or false self:T2( { ClassNameAndID, StateName, State } ) return State end @@ -12462,6 +12462,21 @@ function SET_BASE:Remove( ObjectName ) end +--- Gets a @{Base#BASE} object from the @{Set#SET_BASE} and derived classes, based on the Object Name. +-- @param #SET_BASE self +-- @param #string ObjectName +-- @return Base#BASE +function SET_BASE:Get( ObjectName ) + self:F( ObjectName ) + + local t = self.Set[ObjectName] + + self:T3( { ObjectName, t } ) + + return t + +end + --- Retrieves the amount of objects in the @{Set#SET_BASE} and derived classes. -- @param #SET_BASE self -- @return #number Count @@ -15082,7 +15097,6 @@ Include.File( "Movement" ) Include.File( "Sead" ) Include.File( "Escort" ) Include.File( "MissileTrainer" ) ---Include.File( "AIBalancer" ) Include.File( "AirbasePolice" ) Include.File( "Detection" ) @@ -15102,7 +15116,10 @@ Include.File( "Task" ) Include.File( "Task_SEAD" ) Include.File( "Task_A2G" ) ---- AI Handling Classes +--- AI Set Handling Classes +Include.File( "AISet_Balancer" ) + +--- AI Task Handling Classes Include.File( "AI_PatrolZone" ) -- The order of the declarations is important here. Don't touch it. @@ -20088,47 +20105,35 @@ function SPAWN:_SpawnCleanUpScheduler() local Stamp = self.SpawnCleanUpTimeStamps[SpawnUnitName] self:T( { SpawnUnitName, Stamp } ) - if Stamp.Moved then - if SpawnUnit:InAir() == false then - if SpawnUnit:GetVelocityKMH() < 1 then + if Stamp.Vec2 then + if SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() < 1 then + local NewVec2 = SpawnUnit:GetVec2() + if Stamp.Vec2.x == NewVec2.x and Stamp.Vec2.y == NewVec2.y then -- If the plane is not moving, and is on the ground, assign it with a timestamp... - if not Stamp.Time then - Stamp.Time = timer.getTime() - else - if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then - self:T( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } ) - self:ReSpawn( SpawnCursor ) - Stamp.Moved = nil - Stamp.Time = nil - end - end + if Stamp.Time + self.SpawnCleanUpInterval < timer.getTime() then + self:T( { "CleanUp Scheduler:", "ReSpawning:", SpawnGroup:GetName() } ) + self:ReSpawn( SpawnCursor ) + Stamp.Vec2 = nil + Stamp.Time = nil + end else - Stamp.Time = nil + Stamp.Time = timer.getTime() + Stamp.Vec2 = SpawnUnit:GetVec2() end else - Stamp.Moved = nil + Stamp.Vec2 = nil Stamp.Time = nil end else - if SpawnUnit:InAir() == false and SpawnUnit:GetVelocityKMH() > 1 then - Stamp.Moved = true - else - -- If the plane did not move and on the runway for about 3 minutes, clean it. - if SpawnUnit:IsAboveRunway() and SpawnUnit:GetVelocityKMH() < 1 then - if not Stamp.Time then - Stamp.Time = timer.getTime() - end - if Stamp.Time + 180 < timer.getTime() then - self:T( { "CleanUp Scheduler:", "ReSpawning inactive group:", SpawnGroup:GetName() } ) - self:ReSpawn( SpawnCursor ) - Stamp.Moved = nil - Stamp.Time = nil - end - else - Stamp.Moved = nil - Stamp.Time = nil + if SpawnUnit:InAir() == false then + Stamp.Vec2 = SpawnUnit:GetVec2() + if SpawnUnit:GetVelocityKMH() < 1 then + Stamp.Time = timer.getTime() end - end + else + Stamp.Time = nil + Stamp.Vec2 = nil + end end end @@ -25066,17 +25071,17 @@ do -- DETECTION_DISPATCHER end end--- This module contains the STATEMACHINE class. --- This development is based on a state machine implementation made by Conroy Kyle. --- The state machine can be found here: https://github.com/kyleconroy/lua-state-machine --- --- I've taken the development and enhanced it to make the state machine hierarchical... +-- This development is based on a state machine implementation made by Conroy Kyle. +-- The state machine can be found here: https://github.com/kyleconroy/lua-state-machine +-- +-- I've taken the development and enhanced it to make the state machine hierarchical... -- It is a fantastic development, this module. --- +-- -- === --- +-- -- 1) @{Workflow#STATEMACHINE} class, extends @{Base#BASE} -- ============================================== --- +-- -- 1.1) Add or remove objects from the STATEMACHINE -- -------------------------------------------- -- @module StateMachine @@ -25122,15 +25127,15 @@ function STATEMACHINE:New( options ) self.events[name] = self.events[name] or { map = {} } self:_add_to_map(self.events[name].map, event) end - + for name, callback in pairs(options.callbacks or {}) do self[name] = callback end - + for name, sub in pairs( options.subs or {} ) do self:_submap( self.subs, sub, name ) end - + for name, endstate in pairs( options.endstates or {} ) do self.endstates[endstate] = endstate end @@ -25172,7 +25177,7 @@ function STATEMACHINE._handler( self, EventName, ... ) local can, to = self:can(EventName) self:T( { EventName, can, to } ) - + local ReturnValues = nil if can then @@ -25180,14 +25185,14 @@ function STATEMACHINE._handler( self, EventName, ... ) local params = { ..., EventName, from, to } if self:_call_handler(self["onbefore" .. EventName], params) == false - or self:_call_handler(self["onleave" .. from], params) == false then + or self:_call_handler(self["onleave" .. from], params) == false then return false end self.current = to - + local execute = true - + local subtable = self:_gosub( to, EventName ) for _, sub in pairs( subtable ) do self:F2( "calling sub: " .. sub.event ) @@ -25196,7 +25201,7 @@ function STATEMACHINE._handler( self, EventName, ... ) sub.fsm[sub.event]( sub.fsm ) execute = true end - + local fsmparent, event = self:_isendstate( to ) if fsmparent and event then self:F2( { "end state: ", fsmparent, event } ) @@ -25210,20 +25215,20 @@ function STATEMACHINE._handler( self, EventName, ... ) if execute then self:T3( { onenter = "onenter" .. to, callback = self["onenter" .. to] } ) self:_call_handler(self["onenter" .. to] or self["on" .. to], params) - + self:T3( { On = "OnBefore" .. to, callback = self["OnBefore" .. to] } ) if ( self:_call_handler(self["OnBefore" .. to], params ) ~= false ) then self:T3( { onafter = "onafter" .. EventName, callback = self["onafter" .. EventName] } ) self:_call_handler(self["onafter" .. EventName] or self["on" .. EventName], params) - + self:T3( { On = "OnAfter" .. to, callback = self["OnAfter" .. to] } ) ReturnValues = self:_call_handler(self["OnAfter" .. to], params ) end self:_call_handler(self["onstatechange"], params) end - + return ReturnValues end @@ -25234,7 +25239,7 @@ function STATEMACHINE:_delayed_transition( EventName ) self:E( { EventName = EventName } ) return function( self, DelaySeconds, ... ) self:T( "Delayed Event: " .. EventName ) - SCHEDULER:New( self, self._handler, { EventName, ... }, DelaySeconds ) + SCHEDULER:New( self, self._handler, { EventName, ... }, DelaySeconds ) end end @@ -25372,7 +25377,7 @@ function STATEMACHINE_TASK:New( Task, TaskUnit, options ) FsmTask["onAssigned"] = Task.OnAssigned FsmTask["onSuccess"] = Task.OnSuccess FsmTask["onFailed"] = Task.OnFailed - + FsmTask.Task = Task FsmTask.TaskUnit = TaskUnit @@ -25402,7 +25407,7 @@ function STATEMACHINE_CONTROLLABLE:New( FSMT, Controllable ) -- Inherits from BASE local self = BASE:Inherit( self, STATEMACHINE:New( FSMT ) ) -- StateMachine#STATEMACHINE_CONTROLLABLE - + if Controllable then self:SetControllable( Controllable ) end @@ -25430,7 +25435,59 @@ function STATEMACHINE_CONTROLLABLE:_call_handler( handler, params ) if handler then return handler( self, self.Controllable, unpack( params ) ) end -end--- @module Process +end + +do -- STATEMACHINE_SET + +--- STATEMACHINE_SET class +-- @type STATEMACHINE_SET +-- @field Set#SET_BASE Set +-- @extends StateMachine#STATEMACHINE +STATEMACHINE_SET = { + ClassName = "STATEMACHINE_SET", +} + +--- Creates a new STATEMACHINE_SET object. +-- @param #STATEMACHINE_SET self +-- @param #table FSMT Finite State Machine Table +-- @param Set_SET_BASE FSMSet (optional) The Set object that the STATEMACHINE_SET governs. +-- @return #STATEMACHINE_SET +function STATEMACHINE_SET:New( FSMT, FSMSet ) + + -- Inherits from BASE + local self = BASE:Inherit( self, STATEMACHINE:New( FSMT ) ) -- StateMachine#STATEMACHINE_SET + + if FSMSet then + self:Set( FSMSet ) + end + + return self +end + +--- Sets the SET_BASE object that the STATEMACHINE_SET governs. +-- @param #STATEMACHINE_SET self +-- @param Set#SET_BASE FSMSet +-- @return #STATEMACHINE_SET +function STATEMACHINE_SET:Set( FSMSet ) + self:F( FSMSet ) + self.Set = FSMSet +end + +--- Gets the SET_BASE object that the STATEMACHINE_SET governs. +-- @param #STATEMACHINE_SET self +-- @return Set#SET_BASE +function STATEMACHINE_SET:Get() + return self.Controllable +end + +function STATEMACHINE_SET:_call_handler( handler, params ) + if handler then + return handler( self, self.Set, unpack( params ) ) + end +end + +end +--- @module Process --- The PROCESS class -- @type PROCESS @@ -27437,6 +27494,259 @@ end +--- This module contains the AISET_BALANCER class. +-- +-- === +-- +-- 1) @{AISet_Balancer#AISET_BALANCER} class, extends @{StateMachine#STATEMACHINE_SET} +-- =================================================================================== +-- The @{AISet_Balancer#AISET_BALANCER} class monitors and manages as many AI GROUPS as there are +-- CLIENTS in a SET_CLIENT collection not occupied by players. +-- The AI_BALANCER class manages internally a collection of AI_MANAGEMENT objects, which govern the behaviour +-- of the underlying AI GROUPS. +-- +-- The parent class @{StateMachine#STATEMACHINE_SET} manages the functionality to control the Finite State Machine (FSM) +-- and calls for each event the state transition functions providing the internal @{StateMachine#STATEMACHINE_SET.Set} object containing the +-- SET_GROUP and additional event parameters provided during the event. +-- +-- 1.1) AISET_BALANCER construction method +-- --------------------------------------- +-- Create a new AISET_BALANCER object with the @{#AISET_BALANCER.New} method: +-- +-- * @{#AISET_BALANCER.New}: Creates a new AISET_BALANCER object. +-- +-- 1.2) +-- ---- +-- * Add +-- * Remove +-- +-- 1.2) AISET_BALANCER returns AI to Airbases +-- ------------------------------------------ +-- You can configure to have the AI to return to: +-- +-- * @{#AISET_BALANCER.ReturnToHomeAirbase}: Returns the AI to the home @{Airbase#AIRBASE}. +-- * @{#AISET_BALANCER.ReturnToNearestAirbases}: Returns the AI to the nearest friendly @{Airbase#AIRBASE}. +-- -- +-- === +-- +-- **API CHANGE HISTORY** +-- ====================== +-- +-- The underlying change log documents the API changes. Please read this carefully. The following notation is used: +-- +-- * **Added** parts are expressed in bold type face. +-- * _Removed_ parts are expressed in italic type face. +-- +-- Hereby the change log: +-- +-- 2016-08-17: SPAWN:**InitCleanUp**( SpawnCleanUpInterval ) replaces SPAWN:_CleanUp_( SpawnCleanUpInterval ) +-- +-- * Want to ensure that the methods starting with **Init** are the first called methods before any _Spawn_ method is called! +-- * This notation makes it now more clear which methods are initialization methods and which methods are Spawn enablement methods. +-- +-- === +-- +-- AUTHORS and CONTRIBUTIONS +-- ========================= +-- +-- ### Contributions: +-- +-- * **Dutch_Baron (James)**: Who you can search on the Eagle Dynamics Forums. +-- Working together with James has resulted in the creation of the AISET_BALANCER class. +-- James has shared his ideas on balancing AI with air units, and together we made a first design which you can use now :-) +-- +-- * **SNAFU**: +-- Had a couple of mails with the guys to validate, if the same concept in the GCI/CAP script could be reworked within MOOSE. +-- None of the script code has been used however within the new AISET_BALANCER moose class. +-- +-- ### Authors: +-- +-- * FlightControl: Framework Design & Programming +-- +-- @module AISet_Balancer + + + +--- AISET_BALANCER class +-- @type AISET_BALANCER +-- @field Set#SET_CLIENT SetClient +-- @extends StateMachine#STATEMACHINE_SET +AISET_BALANCER = { + ClassName = "AISET_BALANCER", + PatrolZones = {}, + AIGroups = {}, +} + +--- Creates a new AI\_SET\_BALANCER object +-- @param #AISET_BALANCER self +-- @param Set#SET_CLIENT SetClient A SET\_CLIENT object that will contain the CLIENT objects to be monitored if they are alive or not (joined by a player). +-- @param Spawn#SPAWN SpawnAI The default Spawn object to spawn new AI Groups when needed. +-- @return #AISET_BALANCER +-- @usage +-- -- Define a new AISET_BALANCER Object. +function AISET_BALANCER:New( SetClient, SpawnAI ) + + local FSMT = { + initial = 'None', + events = { + { name = 'Start', from = '*', to = 'Monitoring' }, + { name = 'Monitor', from = '*', to = 'Monitoring' }, + { name = 'Spawn', from = '*', to = 'Spawning' }, + { name = 'Destroy', from = '*', to = 'Destroying' }, + { name = 'Return', from = '*', to = 'Returning' }, + { name = 'End', from = '*', to = 'End' }, + { name = 'Dead', from = '*', to = 'End' }, + }, + } + + -- Inherits from BASE + local self = BASE:Inherit( self, STATEMACHINE_SET:New( FSMT, SET_GROUP:New() ) ) + + self.SetClient = SetClient + self.SpawnAI = SpawnAI + self.ToNearestAirbase = false + self.ToHomeAirbase = false + + self:__Start( 1 ) + + return self +end + +--- Returns the AI to the nearest friendly @{Airbase#AIRBASE}. +-- @param #AISET_BALANCER self +-- @param DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. +-- @param Set#SET_AIRBASE ReturnAirbaseSet The SET of @{Set#SET_AIRBASE}s to evaluate where to return to. +function AISET_BALANCER:ReturnToNearestAirbases( ReturnTresholdRange, ReturnAirbaseSet ) + + self.ToNearestAirbase = true + self.ReturnTresholdRange = ReturnTresholdRange + self.ReturnAirbaseSet = ReturnAirbaseSet +end + +--- Returns the AI to the home @{Airbase#AIRBASE}. +-- @param #AISET_BALANCER self +-- @param DCSTypes#Distance ReturnTresholdRange If there is an enemy @{Client#CLIENT} within the ReturnTresholdRange given in meters, the AI will not return to the nearest @{Airbase#AIRBASE}. +function AISET_BALANCER:ReturnToHomeAirbase( ReturnTresholdRange ) + + self.ToHomeAirbase = true + self.ReturnTresholdRange = ReturnTresholdRange +end + +--- @param #AISET_BALANCER self +-- @param Set#SET_GROUP SetGroup +-- @param #string ClientName +-- @param Group#GROUP AIGroup +function AISET_BALANCER:onenterSpawning( SetGroup, ClientName ) + + -- OK, Spawn a new group from the default SpawnAI object provided. + local AIGroup = self.SpawnAI:Spawn() + AIGroup:E( "Spawning new AIGroup" ) + --TODO: need to rework UnitName thing ... + + SetGroup:Add( ClientName, AIGroup ) +end + +--- @param #AISET_BALANCER self +-- @param Set#SET_GROUP SetGroup +-- @param Group#GROUP AIGroup +function AISET_BALANCER:onenterDestroying( SetGroup, AIGroup ) + + AIGroup:Destroy() +end + +--- @param #AISET_BALANCER self +-- @param Set#SET_GROUP SetGroup +-- @param Group#GROUP AIGroup +function AISET_BALANCER:onenterReturning( SetGroup, AIGroup ) + + local AIGroupTemplate = AIGroup:GetTemplate() + if self.ToHomeAirbase == true then + local WayPointCount = #AIGroupTemplate.route.points + local SwitchWayPointCommand = AIGroup:CommandSwitchWayPoint( 1, WayPointCount, 1 ) + AIGroup:SetCommand( SwitchWayPointCommand ) + AIGroup:MessageToRed( "Returning to home base ...", 30 ) + else + -- Okay, we need to send this Group back to the nearest base of the Coalition of the AI. + --TODO: i need to rework the POINT_VEC2 thing. + local PointVec2 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y ) + local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 ) + self:T( ClosestAirbase.AirbaseName ) + AIGroup:MessageToRed( "Returning to " .. ClosestAirbase:GetName().. " ...", 30 ) + local RTBRoute = AIGroup:RouteReturnToAirbase( ClosestAirbase ) + AIGroupTemplate.route = RTBRoute + AIGroup:Respawn( AIGroupTemplate ) + end + +end + + +--- @param #AISET_BALANCER self +function AISET_BALANCER:onenterMonitoring( SetGroup ) + + self.SetClient:ForEachClient( + --- @param Client#CLIENT Client + function( Client ) + self:E(Client.ClientName) + + local AIGroup = self.Set:Get( Client.UnitName ) -- Group#GROUP + if Client:IsAlive() then + + if AIGroup and AIGroup:IsAlive() == true then + + if self.ToNearestAirbase == false and self.ToHomeAirbase == false then + self:Destroy( AIGroup ) + else + -- We test if there is no other CLIENT within the self.ReturnTresholdRange of the first unit of the AI group. + -- If there is a CLIENT, the AI stays engaged and will not return. + -- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected. + + local PlayerInRange = { Value = false } + local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange ) + + self:E( RangeZone ) + + _DATABASE:ForEachPlayer( + --- @param Unit#UNIT RangeTestUnit + function( RangeTestUnit, RangeZone, AIGroup, PlayerInRange ) + self:E( { PlayerInRange, RangeTestUnit.UnitName, RangeZone.ZoneName } ) + if RangeTestUnit:IsInZone( RangeZone ) == true then + self:E( "in zone" ) + if RangeTestUnit:GetCoalition() ~= AIGroup:GetCoalition() then + self:E( "in range" ) + PlayerInRange.Value = true + end + end + end, + + --- @param Zone#ZONE_RADIUS RangeZone + -- @param Group#GROUP AIGroup + function( RangeZone, AIGroup, PlayerInRange ) + if PlayerInRange.Value == false then + self:Return( AIGroup ) + end + end + , RangeZone, AIGroup, PlayerInRange + ) + + end + self.Set:Remove( Client.UnitName ) + end + else + if not AIGroup or not AIGroup:IsAlive() == true then + self:E("client not alive") + self:Spawn( Client.UnitName ) + self:E("text after spawn") + end + end + return true + end + ) + + self:__Monitor( 10 ) +end + + + --- This module contains the AI\_PATROLZONE class. -- -- === diff --git a/Moose Mission Setup/Moose_Create.bat b/Moose Mission Setup/Moose_Create.bat index 09daa26a9..87c092f73 100644 --- a/Moose Mission Setup/Moose_Create.bat +++ b/Moose Mission Setup/Moose_Create.bat @@ -73,7 +73,6 @@ COPY /b Moose.lua + %1\Movement.lua Moose.lua COPY /b Moose.lua + %1\Sead.lua Moose.lua COPY /b Moose.lua + %1\Escort.lua Moose.lua COPY /b Moose.lua + %1\MissileTrainer.lua Moose.lua -rem COPY /b Moose.lua + %1\AIBalancer.lua Moose.lua COPY /b Moose.lua + %1\AirbasePolice.lua Moose.lua COPY /b Moose.lua + %1\Detection.lua Moose.lua @@ -93,7 +92,10 @@ COPY /b Moose.lua + %1\Task.lua Moose.lua COPY /b Moose.lua + %1\Task_SEAD.lua Moose.lua COPY /b Moose.lua + %1\Task_A2G.lua Moose.lua -rem AI Handling Classes +rem AI Set Handling Classes +COPY /b Moose.lua + %1\AISet_Balancer.lua Moose.lua + +rem AI Task Handling Classes COPY /b Moose.lua + %1\AI_PatrolZone.lua Moose.lua diff --git a/Moose Test Missions/MOOSE_Test_Template.miz b/Moose Test Missions/MOOSE_Test_Template.miz index 9caa369e6..40db2d928 100644 Binary files a/Moose Test Missions/MOOSE_Test_Template.miz and b/Moose Test Missions/MOOSE_Test_Template.miz differ diff --git a/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.lua b/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.lua deleted file mode 100644 index 4c200f163..000000000 --- a/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.lua +++ /dev/null @@ -1,45 +0,0 @@ - -local US_PlanesClientSet = SET_CLIENT:New():FilterCountries( "USA" ):FilterCategories( "plane" ):FilterStart() - -local US_PlanesSpawn1 = SPAWN:New( "AI US 1" ):InitCleanUp( 90 ) -local US_PlanesSpawn2 = SPAWN:New( "AI US 2" ):InitCleanUp( 90 ) -local US_AIBalancer = AIBALANCER:New( US_PlanesClientSet ) - -US_AIBalancer:OnNewAI( - function( AIGroup ) - AIGroup = US_PlanesSpawn1:Spawn() - - local AIPatrolZone = AI_PATROLZONE:New( 3000, 6000, 900, 1100 ) - AIPatrolZone:ManageFuel( 0.2, 180 ) - AIGroup:SetTask( AIPatrolZone ) - - AIPatrolZone:OnRTB( - function( AIGroup ) - AIGroup = US_PlanesSpawn1:Spawn() - end - ) - end -) - - - - - -local RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" ):FilterStart() -local RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 90 ) -local RU_AIBalancer = AIBALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn ) - -local RU_AirbasesSet = SET_AIRBASE:New():FilterCoalitions("red"):FilterStart() -RU_AirbasesSet:Flush() -RU_AIBalancer:ReturnToNearestAirbases( 10000, RU_AirbasesSet ) ---RU_AIBalancer:ReturnToHomeAirbase( 10000 ) - -local PatrolZoneGroup = GROUP:FindByName( "Patrol Zone Blue" ) -local PatrolZoneBlue = ZONE_POLYGON:New( "PatrolZone", PatrolZoneGroup ) -local PatrolZoneB = PATROLZONE:New( PatrolZoneBlue, 3000, 6000, 900, 1100 ):ManageFuel( 0.2, 180 ) -US_AIBalancer:SetPatrolZone( PatrolZoneB ) - -local PatrolZoneGroup = GROUP:FindByName( "Patrol Zone Red" ) -local PatrolZoneRed = ZONE_POLYGON:New( "PatrolZone", PatrolZoneGroup ) -local PatrolZoneR = PATROLZONE:New( PatrolZoneRed, 3000, 6000, 900, 1100 ):ManageFuel( 0.2, 180 ) -RU_AIBalancer:SetPatrolZone( PatrolZoneR ) diff --git a/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.miz b/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.miz deleted file mode 100644 index ebf4f9305..000000000 Binary files a/Moose Test Missions/Moose_Test_AIBALANCER/Moose_Test_AIBALANCER.miz and /dev/null differ diff --git a/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE-DB.miz b/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE-DB.miz index 102c87e99..3c8f266e5 100644 Binary files a/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE-DB.miz and b/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE-DB.miz differ diff --git a/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE.miz b/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE.miz index 69d49c20b..cfa65c17e 100644 Binary files a/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE.miz and b/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE.miz differ diff --git a/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE_CAUCASUS.miz b/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE_CAUCASUS.miz index 5107cff11..ca7941019 100644 Binary files a/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE_CAUCASUS.miz and b/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE_CAUCASUS.miz differ diff --git a/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE_NEVADA.miz b/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE_NEVADA.miz index 02ea9d38a..8b282ba28 100644 Binary files a/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE_NEVADA.miz and b/Moose Test Missions/Moose_Test_AIRBASEPOLICE/Moose_Test_AIRBASEPOLICE_NEVADA.miz differ diff --git a/Moose Test Missions/Moose_Test_AISET_BALANCER/Moose_Test_AISET_BALANCER.lua b/Moose Test Missions/Moose_Test_AISET_BALANCER/Moose_Test_AISET_BALANCER.lua new file mode 100644 index 000000000..e3a5249b3 --- /dev/null +++ b/Moose Test Missions/Moose_Test_AISET_BALANCER/Moose_Test_AISET_BALANCER.lua @@ -0,0 +1,24 @@ + +local US_PlanesClientSet = SET_CLIENT:New():FilterCountries( "USA" ):FilterCategories( "plane" ):FilterStart() + +local US_PlanesSpawn = SPAWN:New( "AI US" ):InitCleanUp( 20 ) +local US_AIBalancer = AISET_BALANCER:New( US_PlanesClientSet, US_PlanesSpawn ) + +local RU_PlanesClientSet = SET_CLIENT:New():FilterCountries( "RUSSIA" ):FilterCategories( "plane" ):FilterStart() +local RU_PlanesSpawn = SPAWN:New( "AI RU" ):InitCleanUp( 20 ) +local RU_AIBalancer = AISET_BALANCER:New( RU_PlanesClientSet, RU_PlanesSpawn ) + +local RU_AirbasesSet = SET_AIRBASE:New():FilterCoalitions("red"):FilterStart() +RU_AirbasesSet:Flush() +RU_AIBalancer:ReturnToNearestAirbases( 10000, RU_AirbasesSet ) +--RU_AIBalancer:ReturnToHomeAirbase( 10000 ) + +--local PatrolZoneGroup = GROUP:FindByName( "Patrol Zone Blue" ) +--local PatrolZoneBlue = ZONE_POLYGON:New( "PatrolZone", PatrolZoneGroup ) +--local PatrolZoneB = PATROLZONE:New( PatrolZoneBlue, 3000, 6000, 900, 1100 ):ManageFuel( 0.2, 180 ) +--US_AIBalancer:SetPatrolZone( PatrolZoneB ) +-- +--local PatrolZoneGroup = GROUP:FindByName( "Patrol Zone Red" ) +--local PatrolZoneRed = ZONE_POLYGON:New( "PatrolZone", PatrolZoneGroup ) +--local PatrolZoneR = PATROLZONE:New( PatrolZoneRed, 3000, 6000, 900, 1100 ):ManageFuel( 0.2, 180 ) +--RU_AIBalancer:SetPatrolZone( PatrolZoneR ) diff --git a/Moose Test Missions/Moose_Test_AISET_BALANCER/Moose_Test_AISET_BALANCER.miz b/Moose Test Missions/Moose_Test_AISET_BALANCER/Moose_Test_AISET_BALANCER.miz new file mode 100644 index 000000000..5e01ba50b Binary files /dev/null and b/Moose Test Missions/Moose_Test_AISET_BALANCER/Moose_Test_AISET_BALANCER.miz differ diff --git a/Moose Test Missions/Moose_Test_AI_PATROLZONE/Moose_Test_AI_PATROLZONE_Switching/Moose_Test_AI_PATROLZONE_Switching.miz b/Moose Test Missions/Moose_Test_AI_PATROLZONE/Moose_Test_AI_PATROLZONE_Switching/Moose_Test_AI_PATROLZONE_Switching.miz index 876d4028a..dc954dae3 100644 Binary files a/Moose Test Missions/Moose_Test_AI_PATROLZONE/Moose_Test_AI_PATROLZONE_Switching/Moose_Test_AI_PATROLZONE_Switching.miz and b/Moose Test Missions/Moose_Test_AI_PATROLZONE/Moose_Test_AI_PATROLZONE_Switching/Moose_Test_AI_PATROLZONE_Switching.miz differ diff --git a/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_with_Moose.miz b/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_with_Moose.miz index e95b3633e..aed301f72 100644 Binary files a/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_with_Moose.miz and b/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_with_Moose.miz differ diff --git a/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_without_Moose.miz b/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_without_Moose.miz index e235cb4db..9ca361d61 100644 Binary files a/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_without_Moose.miz and b/Moose Test Missions/Moose_Test_BASE/Moose_Test_AIRBLANCER_without_Moose.miz differ diff --git a/Moose Test Missions/Moose_Test_BASE/Moose_Test_BASE.miz b/Moose Test Missions/Moose_Test_BASE/Moose_Test_BASE.miz index 0b5b83543..3fa527eb9 100644 Binary files a/Moose Test Missions/Moose_Test_BASE/Moose_Test_BASE.miz and b/Moose Test Missions/Moose_Test_BASE/Moose_Test_BASE.miz differ diff --git a/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_PACKAGE_Board/MOOSE_Test_CARGO_PACKAGE_Board.miz b/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_PACKAGE_Board/MOOSE_Test_CARGO_PACKAGE_Board.miz index d8fecc959..6d610ac41 100644 Binary files a/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_PACKAGE_Board/MOOSE_Test_CARGO_PACKAGE_Board.miz and b/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_PACKAGE_Board/MOOSE_Test_CARGO_PACKAGE_Board.miz differ diff --git a/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_PACKAGE_UnBoard/MOOSE_Test_CARGO_PACKAGE_UnBoard.miz b/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_PACKAGE_UnBoard/MOOSE_Test_CARGO_PACKAGE_UnBoard.miz index 82ec64885..1f08a235b 100644 Binary files a/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_PACKAGE_UnBoard/MOOSE_Test_CARGO_PACKAGE_UnBoard.miz and b/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_PACKAGE_UnBoard/MOOSE_Test_CARGO_PACKAGE_UnBoard.miz differ diff --git a/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_Board/MOOSE_Test_CARGO_UNIT_Board.miz b/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_Board/MOOSE_Test_CARGO_UNIT_Board.miz index c04e057c1..c7ffb41dc 100644 Binary files a/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_Board/MOOSE_Test_CARGO_UNIT_Board.miz and b/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_Board/MOOSE_Test_CARGO_UNIT_Board.miz differ diff --git a/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_Transfer/MOOSE_Test_CARGO_UNIT_Transfer.miz b/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_Transfer/MOOSE_Test_CARGO_UNIT_Transfer.miz index 9358598f1..a4fe807ee 100644 Binary files a/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_Transfer/MOOSE_Test_CARGO_UNIT_Transfer.miz and b/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_Transfer/MOOSE_Test_CARGO_UNIT_Transfer.miz differ diff --git a/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_UnBoard/MOOSE_Test_CARGO_UNIT_UnBoard.miz b/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_UnBoard/MOOSE_Test_CARGO_UNIT_UnBoard.miz index b1c64f659..f1a338edd 100644 Binary files a/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_UnBoard/MOOSE_Test_CARGO_UNIT_UnBoard.miz and b/Moose Test Missions/Moose_Test_CARGO/Moose_Test_CARGO_UNIT_UnBoard/MOOSE_Test_CARGO_UNIT_UnBoard.miz differ diff --git a/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz b/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz index 526f21531..a4d8d1f75 100644 Binary files a/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz and b/Moose Test Missions/Moose_Test_CLEANUP/Moose_Test_CLEANUP.miz differ diff --git a/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.miz b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.miz index fbe480e4e..3a0670a02 100644 Binary files a/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.miz and b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION.miz differ diff --git a/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION_Laser.miz b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION_Laser.miz index 42ccc670b..3100b8b9f 100644 Binary files a/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION_Laser.miz and b/Moose Test Missions/Moose_Test_DETECTION/Moose_Test_DETECTION_Laser.miz differ diff --git a/Moose Test Missions/Moose_Test_DETECTION_DISPATCHER/Moose_Test_DETECTION_DISPATCHER.miz b/Moose Test Missions/Moose_Test_DETECTION_DISPATCHER/Moose_Test_DETECTION_DISPATCHER.miz index bc59e050d..117eb60f7 100644 Binary files a/Moose Test Missions/Moose_Test_DETECTION_DISPATCHER/Moose_Test_DETECTION_DISPATCHER.miz and b/Moose Test Missions/Moose_Test_DETECTION_DISPATCHER/Moose_Test_DETECTION_DISPATCHER.miz differ diff --git a/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz b/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz index 6a9030faa..80df35669 100644 Binary files a/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz and b/Moose Test Missions/Moose_Test_ESCORT/MOOSE_Test_ESCORT.miz differ diff --git a/Moose Test Missions/Moose_Test_FAC/Moose_Test_FAC.miz b/Moose Test Missions/Moose_Test_FAC/Moose_Test_FAC.miz index aeda38c51..1e6cc9e34 100644 Binary files a/Moose Test Missions/Moose_Test_FAC/Moose_Test_FAC.miz and b/Moose Test Missions/Moose_Test_FAC/Moose_Test_FAC.miz differ diff --git a/Moose Test Missions/Moose_Test_GROUP_SwitchWayPoint/MOOSE_Test_GROUP_SwitchWayPoint.miz b/Moose Test Missions/Moose_Test_GROUP_SwitchWayPoint/MOOSE_Test_GROUP_SwitchWayPoint.miz index 6564024d4..e5072273e 100644 Binary files a/Moose Test Missions/Moose_Test_GROUP_SwitchWayPoint/MOOSE_Test_GROUP_SwitchWayPoint.miz and b/Moose Test Missions/Moose_Test_GROUP_SwitchWayPoint/MOOSE_Test_GROUP_SwitchWayPoint.miz differ diff --git a/Moose Test Missions/Moose_Test_MENU_CLIENT/Moose_Test_MENU_CLIENT.miz b/Moose Test Missions/Moose_Test_MENU_CLIENT/Moose_Test_MENU_CLIENT.miz index 3820dccee..ee5c0a47e 100644 Binary files a/Moose Test Missions/Moose_Test_MENU_CLIENT/Moose_Test_MENU_CLIENT.miz and b/Moose Test Missions/Moose_Test_MENU_CLIENT/Moose_Test_MENU_CLIENT.miz differ diff --git a/Moose Test Missions/Moose_Test_MENU_COALITION/Moose_Test_MENU_COALITION.miz b/Moose Test Missions/Moose_Test_MENU_COALITION/Moose_Test_MENU_COALITION.miz index 0225b80af..1aa7ccd94 100644 Binary files a/Moose Test Missions/Moose_Test_MENU_COALITION/Moose_Test_MENU_COALITION.miz and b/Moose Test Missions/Moose_Test_MENU_COALITION/Moose_Test_MENU_COALITION.miz differ diff --git a/Moose Test Missions/Moose_Test_MENU_GROUP/Moose_Test_MENU_GROUP.miz b/Moose Test Missions/Moose_Test_MENU_GROUP/Moose_Test_MENU_GROUP.miz index 6a7cc03a8..1fb471c2d 100644 Binary files a/Moose Test Missions/Moose_Test_MENU_GROUP/Moose_Test_MENU_GROUP.miz and b/Moose Test Missions/Moose_Test_MENU_GROUP/Moose_Test_MENU_GROUP.miz differ diff --git a/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz b/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz index df6c03f7f..9cc2ea950 100644 Binary files a/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz and b/Moose Test Missions/Moose_Test_MISSILETRAINER/Moose_Test_MISSILETRAINER.miz differ diff --git a/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Nested/Moose_Test_SCHEDULER_Nested.miz b/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Nested/Moose_Test_SCHEDULER_Nested.miz index 89dcf2e26..9df2fddcc 100644 Binary files a/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Nested/Moose_Test_SCHEDULER_Nested.miz and b/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Nested/Moose_Test_SCHEDULER_Nested.miz differ diff --git a/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Repeated/Moose_Test_SCHEDULER_Repeated.miz b/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Repeated/Moose_Test_SCHEDULER_Repeated.miz index 854ff50a1..1b87691b9 100644 Binary files a/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Repeated/Moose_Test_SCHEDULER_Repeated.miz and b/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Repeated/Moose_Test_SCHEDULER_Repeated.miz differ diff --git a/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Simple/Moose_Test_SCHEDULER_Simple.miz b/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Simple/Moose_Test_SCHEDULER_Simple.miz index 2faba9580..d54c44b09 100644 Binary files a/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Simple/Moose_Test_SCHEDULER_Simple.miz and b/Moose Test Missions/Moose_Test_SCHEDULER/Moose_Test_SCHEDULER_Simple/Moose_Test_SCHEDULER_Simple.miz differ diff --git a/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz b/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz index afed80ccd..74f488d95 100644 Binary files a/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz and b/Moose Test Missions/Moose_Test_SEAD/MOOSE_Test_SEAD.miz differ diff --git a/Moose Test Missions/Moose_Test_SET_AIRBASE/Moose_Test_SET_AIRBASE.miz b/Moose Test Missions/Moose_Test_SET_AIRBASE/Moose_Test_SET_AIRBASE.miz index e7df66fd5..baeb3cc9b 100644 Binary files a/Moose Test Missions/Moose_Test_SET_AIRBASE/Moose_Test_SET_AIRBASE.miz and b/Moose Test Missions/Moose_Test_SET_AIRBASE/Moose_Test_SET_AIRBASE.miz differ diff --git a/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz b/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz index 6addc0b3a..8e2b73b9f 100644 Binary files a/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz and b/Moose Test Missions/Moose_Test_SET_CLIENT/Moose_Test_SET_CLIENT.miz differ diff --git a/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz b/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz index b25f6183d..d500805da 100644 Binary files a/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz and b/Moose Test Missions/Moose_Test_SET_GROUP/Moose_Test_SET_GROUP.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz b/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz index 10e1f1ccb..855088e81 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz and b/Moose Test Missions/Moose_Test_SPAWN/MOOSE_Test_SPAWN.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_CleanUp/MOOSE_Test_SPAWN_CleanUp.miz b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_CleanUp/MOOSE_Test_SPAWN_CleanUp.miz index 525c52328..92e47efd0 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_CleanUp/MOOSE_Test_SPAWN_CleanUp.miz and b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_CleanUp/MOOSE_Test_SPAWN_CleanUp.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitLimit/MOOSE_Test_SPAWN_InitLimit.miz b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitLimit/MOOSE_Test_SPAWN_InitLimit.miz index c42abf04e..ec7c1d0d0 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitLimit/MOOSE_Test_SPAWN_InitLimit.miz and b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitLimit/MOOSE_Test_SPAWN_InitLimit.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRandomizeTemplate/MOOSE_Test_SPAWN_InitRandomizeTemplate.miz b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRandomizeTemplate/MOOSE_Test_SPAWN_InitRandomizeTemplate.miz index c5fe17bd7..42e23c0fd 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRandomizeTemplate/MOOSE_Test_SPAWN_InitRandomizeTemplate.miz and b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRandomizeTemplate/MOOSE_Test_SPAWN_InitRandomizeTemplate.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRandomizeZones/Moose_Test_SPAWN_InitRandomizeZones.miz b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRandomizeZones/Moose_Test_SPAWN_InitRandomizeZones.miz index 5588c8e49..41009f2b4 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRandomizeZones/Moose_Test_SPAWN_InitRandomizeZones.miz and b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRandomizeZones/Moose_Test_SPAWN_InitRandomizeZones.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRepeat/MOOSE_Test_SPAWN_InitRepeat.miz b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRepeat/MOOSE_Test_SPAWN_InitRepeat.miz index f29deadef..ce5df95d8 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRepeat/MOOSE_Test_SPAWN_InitRepeat.miz and b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_InitRepeat/MOOSE_Test_SPAWN_InitRepeat.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromStatic/Moose_Test_SPAWN_SpawnFromStatic.miz b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromStatic/Moose_Test_SPAWN_SpawnFromStatic.miz index 68be06b67..34e84f30e 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromStatic/Moose_Test_SPAWN_SpawnFromStatic.miz and b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromStatic/Moose_Test_SPAWN_SpawnFromStatic.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromUnit/Moose_Test_SPAWN_SpawnFromUnit.miz b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromUnit/Moose_Test_SPAWN_SpawnFromUnit.miz index 76e3f505a..edbd4748c 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromUnit/Moose_Test_SPAWN_SpawnFromUnit.miz and b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromUnit/Moose_Test_SPAWN_SpawnFromUnit.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromVec2/Moose_Test_SPAWN_SpawnFromVec2.miz b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromVec2/Moose_Test_SPAWN_SpawnFromVec2.miz index 95439e2a6..11230ebda 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromVec2/Moose_Test_SPAWN_SpawnFromVec2.miz and b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromVec2/Moose_Test_SPAWN_SpawnFromVec2.miz differ diff --git a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromVec3/Moose_Test_SPAWN_SpawnFromVec3.miz b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromVec3/Moose_Test_SPAWN_SpawnFromVec3.miz index 0d9ad87ec..2577af44b 100644 Binary files a/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromVec3/Moose_Test_SPAWN_SpawnFromVec3.miz and b/Moose Test Missions/Moose_Test_SPAWN/Moose_Test_SPAWN_SpawnFromVec3/Moose_Test_SPAWN_SpawnFromVec3.miz differ diff --git a/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz b/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz index ead57742a..4615f370a 100644 Binary files a/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz and b/Moose Test Missions/Moose_Test_TASK_Pickup_and_Deploy/MOOSE_Test_TASK_Pickup_and_Deploy.miz differ diff --git a/Moose Test Missions/Moose_Test_TASK_SEAD/Moose_Test_TASK_SEAD.miz b/Moose Test Missions/Moose_Test_TASK_SEAD/Moose_Test_TASK_SEAD.miz index b49877475..3736d9917 100644 Binary files a/Moose Test Missions/Moose_Test_TASK_SEAD/Moose_Test_TASK_SEAD.miz and b/Moose Test Missions/Moose_Test_TASK_SEAD/Moose_Test_TASK_SEAD.miz differ diff --git a/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz b/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz index b1f4dd836..998b14072 100644 Binary files a/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz and b/Moose Test Missions/Moose_Test_WRAPPER/Moose_Test_WRAPPER.miz differ diff --git a/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz b/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz index 635aaa7d3..c19c46660 100644 Binary files a/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz and b/Moose Test Missions/Moose_Test_ZONE/Moose_Test_ZONE.miz differ diff --git a/Moose Test Missions/Moose_Test_ZONE_GROUP/Moose_Test_ZONE_GROUP.miz b/Moose Test Missions/Moose_Test_ZONE_GROUP/Moose_Test_ZONE_GROUP.miz index 7733657d1..61588f826 100644 Binary files a/Moose Test Missions/Moose_Test_ZONE_GROUP/Moose_Test_ZONE_GROUP.miz and b/Moose Test Missions/Moose_Test_ZONE_GROUP/Moose_Test_ZONE_GROUP.miz differ diff --git a/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz b/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz index d453498e2..4933b36d2 100644 Binary files a/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz and b/Moose Test Missions/Moose_Test_ZONE_POLYGON/Moose_Test_ZONE_POLYGON.miz differ diff --git a/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz b/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz index 85f54a981..112535948 100644 Binary files a/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz and b/Moose Test Missions/Moose_Test_ZONE_RADIUS/Moose_Test_ZONE_RADIUS.miz differ diff --git a/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz b/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz index d2f5c0c5c..ffa8a3601 100644 Binary files a/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz and b/Moose Test Missions/Moose_Test_ZONE_UNIT/Moose_Test_ZONE_UNIT.miz differ