mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-19 13:46:08 +00:00
xx
This commit is contained in:
@@ -68,7 +68,7 @@ ARMYGROUP = {
|
|||||||
|
|
||||||
--- Army Group version.
|
--- Army Group version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
ARMYGROUP.version="1.0.3"
|
ARMYGROUP.version="1.0.4"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-- TODO list
|
-- TODO list
|
||||||
@@ -2332,6 +2332,213 @@ function ARMYGROUP:onafterUnsuppressed(From, Event, To)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- HuntingPatrol.lua
|
||||||
|
--
|
||||||
|
-- Adds simple "hunting patrol" behavior on top of ARMYGROUP:
|
||||||
|
--
|
||||||
|
-- * Group patrols normally using its existing waypoints
|
||||||
|
-- * While combat-ready, periodically scans a zone for enemies
|
||||||
|
-- * When an enemy is found, lock it and call EngageTarget()
|
||||||
|
-- * Stay on that target until it dies
|
||||||
|
-- * When target is dead, Disengage() and let ARMYGROUP resume patrol
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Module table
|
||||||
|
ARMYGROUP.HuntingPatrol = {}
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- ARMYGROUP extension state
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- We store a few extra fields on ARMYGROUP:
|
||||||
|
-- hp_zone : ZONE object to hunt inside
|
||||||
|
-- hp_speed : speed in knots when engaging
|
||||||
|
-- hp_formation : formation string when engaging
|
||||||
|
-- hp_target : currently locked UNIT (or nil)
|
||||||
|
-- hp_timer : TIMER object for periodic updates
|
||||||
|
-- hp_interval : scan interval in seconds
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
--- Enable hunting patrol behavior for this ARMYGROUP.
|
||||||
|
-- @param #ARMYGROUP self
|
||||||
|
-- @param Core.Zone#ZONE_BASE Zone The zone to hunt inside.
|
||||||
|
-- @param #number Speed Speed in knots when engaging.
|
||||||
|
-- @param #string Formation Formation used during engagement (optional).
|
||||||
|
-- @param #number Interval Scan interval in seconds (optional, default 5).
|
||||||
|
-- @return #ARMYGROUP self
|
||||||
|
function ARMYGROUP:EnableHuntingPatrol(Zone, Speed, Formation, Interval)
|
||||||
|
|
||||||
|
self.hp_zone = Zone
|
||||||
|
self.hp_speed = tonumber(Speed) or 20
|
||||||
|
self.hp_formation = Formation or nil
|
||||||
|
|
||||||
|
-- Force numeric, safe interval
|
||||||
|
local intervalNum = tonumber(Interval)
|
||||||
|
if not intervalNum or intervalNum <= 0 then
|
||||||
|
intervalNum = 5
|
||||||
|
end
|
||||||
|
self.hp_interval = intervalNum
|
||||||
|
|
||||||
|
self.hp_target = nil
|
||||||
|
|
||||||
|
if self.hp_timer then
|
||||||
|
self.hp_timer:Stop()
|
||||||
|
self.hp_timer = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
self.hp_timer = TIMER:New(self._HuntingPatrolUpdate, self):Start(1, self.hp_interval)
|
||||||
|
|
||||||
|
self:T(self.lid .. "HuntingPatrol: enabled. Interval=" .. tostring(self.hp_interval))
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Disable hunting patrol behavior.
|
||||||
|
-- @param #ARMYGROUP self
|
||||||
|
-- @return #ARMYGROUP self
|
||||||
|
function ARMYGROUP:DisableHuntingPatrol()
|
||||||
|
if self.hp_timer then
|
||||||
|
self.hp_timer:Stop()
|
||||||
|
self.hp_timer = nil
|
||||||
|
end
|
||||||
|
if self.HuntingEnemySet then
|
||||||
|
self.HuntingEnemySet:FilterStop()
|
||||||
|
self.HuntingEnemySet = nil
|
||||||
|
end
|
||||||
|
self.hp_target = nil
|
||||||
|
self:T(self.lid .. "HuntingPatrol: disabled.")
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- Internal: periodic update
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- This is called by the TIMER created in EnableHuntingPatrol().
|
||||||
|
-- It:
|
||||||
|
--
|
||||||
|
-- - checks if group is alive & combat-ready
|
||||||
|
-- - if a target is locked, checks if it is still alive
|
||||||
|
-- - if no target, scans the zone for enemies and locks one
|
||||||
|
-- - uses ARMYGROUP:EngageTarget() / Disengage()
|
||||||
|
--
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- @param #ARMYGROUP self
|
||||||
|
-- @return #ARMYGROUP self
|
||||||
|
function ARMYGROUP:_HuntingPatrolUpdate()
|
||||||
|
|
||||||
|
-- If group is dead, stop.
|
||||||
|
if not self:IsAlive() then
|
||||||
|
self:DisableHuntingPatrol()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Only run during PATROLZONE missions
|
||||||
|
local mission = self:GetMissionCurrent()
|
||||||
|
if not mission or mission.type ~= AUFTRAG.Type.PATROLZONE then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Only act when combat-ready
|
||||||
|
if not self:IsCombatReady() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If we have a locked target, keep or drop it
|
||||||
|
if self.hp_target then
|
||||||
|
if not self.hp_target:IsAlive() then
|
||||||
|
self.hp_target = nil
|
||||||
|
self:Disengage()
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- No target → scan for new enemies
|
||||||
|
local enemy = self:_HuntingPatrolFindEnemyInZone(self.hp_zone)
|
||||||
|
if enemy then
|
||||||
|
self.hp_target = enemy
|
||||||
|
self:EngageTarget(enemy, self.hp_speed, self.hp_formation)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- Internal: find one enemy ground unit inside a zone
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- Very simple: build a SET_UNIT, filter by coalition and zone,
|
||||||
|
-- and pick the closest unit to this ARMYGROUP.
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- @param #ARMYGROUP self
|
||||||
|
-- @param Core.Zone#ZONE Zone The zont to look at
|
||||||
|
-- @return Wrapper.Unit#UNIT Enemy The nearest enemy UNIT in zone
|
||||||
|
function ARMYGROUP:_HuntingPatrolFindEnemyInZone(Zone)
|
||||||
|
|
||||||
|
if not Zone then return nil end
|
||||||
|
|
||||||
|
-- Determine our coalition.
|
||||||
|
local myCoalition = self:GetCoalition()
|
||||||
|
|
||||||
|
if not self.HuntingEnemySet then
|
||||||
|
|
||||||
|
self.HuntingEnemySet = SET_UNIT:New()
|
||||||
|
:FilterActive(true)
|
||||||
|
:FilterCategories("ground")
|
||||||
|
:FilterStart()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local enemies = {}
|
||||||
|
|
||||||
|
self.HuntingEnemySet:ForEachUnitCompletelyInZone(Zone, function(unit)
|
||||||
|
if unit:GetCoalition() ~= myCoalition and unit:IsAlive() then
|
||||||
|
table.insert(enemies, unit)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if #enemies == 0 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Pick the closest enemy.
|
||||||
|
local myCoord = self:GetCoordinate()
|
||||||
|
|
||||||
|
table.sort(enemies, function(a, b)
|
||||||
|
return myCoord:Get2DDistance(a:GetCoordinate()) <
|
||||||
|
myCoord:Get2DDistance(b:GetCoordinate())
|
||||||
|
end)
|
||||||
|
|
||||||
|
return enemies[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- Optional helper: convenience wrapper for your campaign code
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- Example usage in your ArmyManagement:
|
||||||
|
--
|
||||||
|
-- local group = GROUP:FindByName("MyDefenseGroup")
|
||||||
|
-- local army = ARMYGROUP:New(group)
|
||||||
|
-- army:SetPatrolAdInfinitum(true)
|
||||||
|
-- army:EnableHuntingPatrol(myZone, 20, "Off Road", 5)
|
||||||
|
--
|
||||||
|
-- ARMYGROUP will:
|
||||||
|
--
|
||||||
|
-- * patrol its waypoints forever
|
||||||
|
-- * periodically scan myZone
|
||||||
|
-- * when an enemy appears, EngageTarget()
|
||||||
|
-- * when target dies, Disengage() and resume patrol
|
||||||
|
--
|
||||||
|
----------------------------------------------------------------
|
||||||
|
-- @param Wrapper.Group#GROUP group The GROUP object to be made into an ARMYGROUP and send hunting.
|
||||||
|
-- @param Core.Zone#ZONE zone The zone object where to search for enemies.
|
||||||
|
-- @param #number speed Speed in knots when engaging.
|
||||||
|
-- @param #string formation Formation used during engagement (optional).
|
||||||
|
-- @param #number interval Scan interval in seconds (optional, default 5).
|
||||||
|
-- @return #ARMYGROUP ArmyGroup The new ArmyGroup.
|
||||||
|
function ARMYGROUP.EnableHuntingPatrolForGroup(group, zone, speed, formation, interval)
|
||||||
|
local army = ARMYGROUP:New(group)
|
||||||
|
army:SetPatrolAdInfinitum(true)
|
||||||
|
army:EnableHuntingPatrol(zone, speed, formation, interval)
|
||||||
|
return army
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
--
|
--
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
-- Date: September 2023
|
-- Date: September 2023
|
||||||
-- Last Update: Jan 2026
|
-- Last Update: Mar 2026
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
--
|
--
|
||||||
--- **Ops** - Easy GCI & CAP Manager
|
--- **Ops** - Easy GCI & CAP Manager
|
||||||
@@ -286,7 +286,7 @@ EASYGCICAP = {
|
|||||||
|
|
||||||
--- EASYGCICAP class version.
|
--- EASYGCICAP class version.
|
||||||
-- @field #string version
|
-- @field #string version
|
||||||
EASYGCICAP.version="0.1.34"
|
EASYGCICAP.version="0.1.35"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
--
|
--
|
||||||
@@ -355,6 +355,7 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
|||||||
-- From State --> Event --> To State
|
-- From State --> Event --> To State
|
||||||
self:SetStartState("Stopped")
|
self:SetStartState("Stopped")
|
||||||
self:AddTransition("Stopped", "Start", "Running")
|
self:AddTransition("Stopped", "Start", "Running")
|
||||||
|
self:AddTransition("Stopped", "Restart", "Running")
|
||||||
self:AddTransition("Running", "Stop", "Stopped")
|
self:AddTransition("Running", "Stop", "Stopped")
|
||||||
self:AddTransition("*", "Status", "*")
|
self:AddTransition("*", "Status", "*")
|
||||||
|
|
||||||
@@ -392,6 +393,20 @@ function EASYGCICAP:New(Alias, AirbaseName, Coalition, EWRName)
|
|||||||
-- @param #string Event Event.
|
-- @param #string Event Event.
|
||||||
-- @param #string To To state.
|
-- @param #string To To state.
|
||||||
|
|
||||||
|
--- On Before "Restart" event. Use `myinstance:Restart()` in case you Stopped the instance before and want to restart it now.
|
||||||
|
-- @function [parent=#EASYGCICAP] OnBeforeRestart
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
|
||||||
|
--- On After "Restart" event. Use `myinstance:Restart()` in case you Stopped the instance before and want to restart it now.
|
||||||
|
-- @function [parent=#EASYGCICAP] OnAfterRestart
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @param #string From From state.
|
||||||
|
-- @param #string Event Event.
|
||||||
|
-- @param #string To To state.
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1798,8 +1813,31 @@ end
|
|||||||
function EASYGCICAP:onafterStop(From,Event,To)
|
function EASYGCICAP:onafterStop(From,Event,To)
|
||||||
self:T({From,Event,To})
|
self:T({From,Event,To})
|
||||||
self.Intel:Stop()
|
self.Intel:Stop()
|
||||||
|
-- self.wings[Airbasename] = { CAP_Wing, AIRBASE:FindByName(Airbasename):GetZone(), Airbasename }
|
||||||
for _,_wing in pairs(self.wings or {}) do
|
for _,_wing in pairs(self.wings or {}) do
|
||||||
_wing:Stop()
|
for _,_aw in pairs(_wing) do
|
||||||
|
_wing[1]:Stop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
--- (Internal) FSM Function onafterRestart
|
||||||
|
-- @param #EASYGCICAP self
|
||||||
|
-- @param #string From
|
||||||
|
-- @param #string Event
|
||||||
|
-- @param #string To
|
||||||
|
-- @return #EASYGCICAP self
|
||||||
|
function EASYGCICAP:onafterRestart(From,Event,To)
|
||||||
|
self:T({From,Event,To})
|
||||||
|
if self:Is("Stopped") then
|
||||||
|
self.Intel:Start()
|
||||||
|
-- self.wings[Airbasename] = { CAP_Wing, AIRBASE:FindByName(Airbasename):GetZone(), Airbasename }
|
||||||
|
for _,_wing in pairs(self.wings or {}) do
|
||||||
|
for _,_aw in pairs(_wing) do
|
||||||
|
_wing[1]:Start()
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user