- Ground ops
This commit is contained in:
Frank 2021-08-11 10:40:16 +02:00
parent 86bb256bf1
commit 88e59a2739
6 changed files with 230 additions and 55 deletions

View File

@ -109,6 +109,9 @@ function ARMYGROUP:New(group)
-- From State --> Event --> To State
self:AddTransition("*", "FullStop", "Holding") -- Hold position.
self:AddTransition("*", "Cruise", "Cruising") -- Cruise along the given route of waypoints.
self:AddTransition("*", "RTZ", "Returning") -- Group is returning to (home) zone.
self:AddTransition("Returning", "Returned", "Returned") -- Group is returned to (home) zone.
self:AddTransition("*", "Detour", "OnDetour") -- Make a detour to a coordinate and resume route afterwards.
self:AddTransition("OnDetour", "DetourReached", "Cruising") -- Group reached the detour coordinate.
@ -626,7 +629,7 @@ end
function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation)
-- Debug info.
local text=string.format("Update route n=%s, Speed=%s, Formation=%s", tostring(n), tostring(Speed), tostring(Formation))
local text=string.format("Update route state=%s: n=%s, Speed=%s, Formation=%s", self:GetState(), tostring(n), tostring(Speed), tostring(Formation))
self:T(self.lid..text)
-- Update route from this waypoint number onwards.
@ -823,6 +826,60 @@ function ARMYGROUP:onafterRearm(From, Event, To, Coordinate, Formation)
end
--- On after "RTZ" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Zone#ZONE Zone The zone to return to.
-- @param #number Formation Formation of the group.
function ARMYGROUP:onafterRTZ(From, Event, To, Zone, Formation)
-- ID of current waypoint.
local uid=self:GetWaypointCurrent().uid
-- Zone.
local zone=Zone or self.homezone
if zone then
-- Debug info.
self:I(self.lid..string.format("RTZ to Zone %s", zone:GetName()))
local Coordinate=zone:GetRandomCoordinate()
-- Add waypoint after current.
local wp=self:AddWaypoint(Coordinate, nil, uid, Formation, true)
-- Set if we want to resume route after reaching the detour waypoint.
wp.detour=0
else
self:E(self.lid.."ERROR: No RTZ zone given!")
end
end
--- On after "Returned" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function ARMYGROUP:onafterReturned(From, Event, To)
-- Debug info.
self:T(self.lid..string.format("Group returned"))
if self.legion then
-- Debug info.
self:T(self.lid..string.format("Adding group back to warehouse stock"))
-- Add asset back in 10 seconds.
self.legion:__AddAsset(10, self.group, 1)
end
end
--- On after "Rearming" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
@ -1048,6 +1105,8 @@ end
-- @param #string To To state.
function ARMYGROUP:onafterFullStop(From, Event, To)
self:I(self.lid..string.format("Full stop!"))
-- Get current position.
local pos=self:GetCoordinate()
@ -1125,7 +1184,8 @@ function ARMYGROUP:AddWaypoint(Coordinate, Speed, AfterWaypointWithID, Formation
-- Update route.
if Updateroute==nil or Updateroute==true then
self:_CheckGroupDone(1)
self:UpdateRoute()
--self:_CheckGroupDone(1)
end
return waypoint

View File

@ -71,7 +71,7 @@ function BRIGADE:New(WarehouseName, BrigadeName)
-- Add FSM transitions.
-- From State --> Event --> To State
self:AddTransition("*", "PlatoonOnMission", "*") -- Add a (mission) request to the warehouse.
self:AddTransition("*", "PlatoonAssetReturned", "*") -- An asset returned (from a mission) to the Brigade warehouse.
return self
end
@ -266,7 +266,23 @@ end
-- FSM Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after "ArmyOnMission".
-- @param #BRIGADE self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.ArmyGroup#ARMYGROUP ArmyGroup Ops army group on mission.
-- @param Ops.Auftrag#AUFTRAG Mission The requested mission.
function BRIGADE:onafterArmyOnMission(From, Event, To, ArmyGroup, Mission)
local armygroup=ArmyGroup --Ops.ArmyGroup#ARMYGROUP
local mission=Mission --Ops.Auftrag#AUFTRAG
-- Debug info.
self:T(self.lid..string.format("Group %s on %s mission %s", armygroup:GetName(), mission:GetType(), mission:GetName()))
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -579,8 +579,8 @@ end
function COHORT:onafterStart(From, Event, To)
-- Short info.
local text=string.format("Starting COHORT %s", self.name)
self:T(self.lid..text)
local text=string.format("Starting %s v%s %s", self.ClassName, self.version, self.name)
self:I(self.lid..text)
-- Start the status monitoring.
self:__Status(-1)
@ -618,15 +618,18 @@ function COHORT:_CheckAssetStatus()
text=text..", Flight: "
if asset.flightgroup and asset.flightgroup:IsAlive() then
local status=asset.flightgroup:GetState()
local fuelmin=asset.flightgroup:GetFuelMin()
local fuellow=asset.flightgroup:IsFuelLow()
local fuelcri=asset.flightgroup:IsFuelCritical()
text=text..string.format("%s", status)
text=text..string.format("%s Fuel=%d", status, fuelmin)
if fuelcri then
text=text.." (Critical!)"
elseif fuellow then
text=text.." (Low)"
if asset.flightgroup:IsFlightgroup() then
local fuelmin=asset.flightgroup:GetFuelMin()
local fuellow=asset.flightgroup:IsFuelLow()
local fuelcri=asset.flightgroup:IsFuelCritical()
text=text..string.format("Fuel=%d", fuelmin)
if fuelcri then
text=text.." (Critical!)"
elseif fuellow then
text=text.." (Low)"
end
end
local lifept, lifept0=asset.flightgroup:GetLifePoints()
@ -639,8 +642,10 @@ function COHORT:_CheckAssetStatus()
end
-- Payload info.
local payload=asset.payload and table.concat(self.legion:GetPayloadMissionTypes(asset.payload), ", ") or "None"
text=text..", Payload={"..payload.."}"
if asset.flightgroup:IsFlightgroup() then
local payload=asset.payload and table.concat(self.legion:GetPayloadMissionTypes(asset.payload), ", ") or "None"
text=text..", Payload={"..payload.."}"
end
else

View File

@ -23,8 +23,10 @@
-- ===
--
-- # The LEGION Concept
--
-- An LEGION consists of multiple COHORTs. These cohorts "live" in a WAREHOUSE, i.e. a physical structure that is connected to an airbase (airdrome, FRAP or ship).
--
-- The LEGION class contains all functions that are common for the AIRWING, BRIGADE and XXX classes, which inherit the LEGION class.
--
-- An LEGION consists of multiple COHORTs. These cohorts "live" in a WAREHOUSE, i.e. a physical structure that can be destroyed or captured.
--
-- @field #LEGION
LEGION = {
@ -79,6 +81,8 @@ function LEGION:New(WarehouseName, LegionName)
self:AddTransition("*", "ArmyOnMission", "*") -- An OPSGROUP was send on a Mission (AUFTRAG).
self:AddTransition("*", "NavyOnMission", "*") -- An OPSGROUP was send on a Mission (AUFTRAG).
self:AddTransition("*", "AssetReturned", "*") -- An asset returned (from a mission) to the Legion warehouse.
-- Defaults:
-- TODO
@ -598,10 +602,16 @@ end
-- @param Ops.OpsGroup#OPSGROUP OpsGroup Ops group on mission
-- @param Ops.Auftrag#AUFTRAG Mission The requested mission.
function LEGION:onafterOpsOnMission(From, Event, To, OpsGroup, Mission)
-- Debug info.
self:T2(self.lid..string.format("Group %s on %s mission %s", OpsGroup:GetName(), Mission:GetType(), Mission:GetName()))
if self:IsAirwing() then
-- Trigger event for Airwings.
self:FlightOnMission(OpsGroup, Mission)
elseif self:IsBrigade() then
-- Trigger event for Brigades.
self:ArmyOnMission(OpsGroup, Mission)
else
end
end
@ -684,7 +694,7 @@ function LEGION:onafterNewAsset(From, Event, To, asset, assignment)
else
--env.info("FF squad asset returned")
self:SquadAssetReturned(squad, asset)
self:AssetReturned(squad, asset)
end
@ -696,11 +706,11 @@ end
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.Squadron#SQUADRON Squadron The asset squadron.
-- @param Ops.Cohort#COHORT Cohort The cohort the asset belongs to.
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset that returned.
function LEGION:onafterSquadAssetReturned(From, Event, To, Squadron, Asset)
function LEGION:onafterAssetReturned(From, Event, To, Cohort, Asset)
-- Debug message.
self:T(self.lid..string.format("Asset %s from squadron %s returned! asset.assignment=\"%s\"", Asset.spawngroupname, Squadron.name, tostring(Asset.assignment)))
self:T(self.lid..string.format("Asset %s from Cohort %s returned! asset.assignment=\"%s\"", Asset.spawngroupname, Cohort.name, tostring(Asset.assignment)))
-- Stop flightgroup.
if Asset.flightgroup and not Asset.flightgroup:IsStopped() then
@ -708,15 +718,23 @@ function LEGION:onafterSquadAssetReturned(From, Event, To, Squadron, Asset)
end
-- Return payload.
self:ReturnPayloadFromAsset(Asset)
if Asset.flightgroup:IsFlightgroup() then
self:ReturnPayloadFromAsset(Asset)
end
-- Return tacan channel.
if Asset.tacan then
Squadron:ReturnTacan(Asset.tacan)
Cohort:ReturnTacan(Asset.tacan)
end
-- Set timestamp.
Asset.Treturned=timer.getAbsTime()
if self:IsAirwing() then
self:SquadronAssetReturned(Cohort, Asset)
elseif self:IsBrigade() then
self:PlatoonAssetReturned(Cohort, Asset)
end
end
@ -1252,8 +1270,6 @@ end
-- @return #table Assets that can do the required mission.
function LEGION:CanMission(Mission)
env.info("FF CanMission Classname "..self.ClassName)
-- Assume we CAN and NO assets are available.
local Can=true
local Assets={}

View File

@ -70,6 +70,9 @@
-- @field Ops.Auftrag#AUFTRAG missionpaused Paused mission.
-- @field #number Ndestroyed Number of destroyed units.
-- @field #number Nkills Number kills of this groups.
--
-- @field Ops.Legion#LEGION legion Legion the group belongs to.
-- @field Ops.Cohort#COHORT cohort Cohort the group belongs to.
--
-- @field Core.Point#COORDINATE coordinate Current coordinate.
--
@ -1329,7 +1332,7 @@ end
--- Despawn the group. The whole group is despawned and (optionally) a "Remove Unit" event is generated for all current units of the group.
-- @param #OPSGROUP self
-- @param #number Delay Delay in seconds before the group will be despawned. Default immediately.
-- @param #boolean NoEventRemoveUnit If true, no event "Remove Unit" is generated.
-- @param #boolean NoEventRemoveUnit If `true`, **no** event "Remove Unit" is generated.
-- @return #OPSGROUP self
function OPSGROUP:Despawn(Delay, NoEventRemoveUnit)
@ -1337,8 +1340,15 @@ function OPSGROUP:Despawn(Delay, NoEventRemoveUnit)
self.scheduleIDDespawn=self:ScheduleOnce(Delay, OPSGROUP.Despawn, self, 0, NoEventRemoveUnit)
else
-- Debug info.
self:I(self.lid..string.format("Despawning Group!"))
if self.legion and not NoEventRemoveUnit then
-- Add asset back in 10 seconds.
self.legion:AddAsset(self.group, 1)
end
-- DCS group obejct.
local DCSGroup=self:GetDCSGroup()
if DCSGroup then
@ -1819,6 +1829,14 @@ function OPSGROUP:IsRetreating()
return is
end
--- Check if the group is currently returning to a zone.
-- @param #OPSGROUP self
-- @return #boolean If true, group is returning.
function OPSGROUP:IsReturning()
local is=self:is("Returning")
return is
end
--- Check if the group is engaging another unit or group.
-- @param #OPSGROUP self
-- @return #boolean If true, group is engaging.
@ -2424,7 +2442,7 @@ function OPSGROUP:OnEventBirth(EventData)
-- Get element.
local element=self:GetElementByName(unitname)
if element then
if element and element.status~=OPSGROUP.ElementStatus.SPAWNED then
-- Set element to spawned state.
self:ElementSpawned(element)
@ -2715,7 +2733,7 @@ function OPSGROUP:AddTaskWaypoint(task, Waypoint, description, prio, duration)
self:T3({newtask=newtask})
-- Update route.
self:__UpdateRoute(-1)
--self:__UpdateRoute(-1)
return newtask
end
@ -3269,7 +3287,7 @@ function OPSGROUP:onafterTaskDone(From, Event, To, Task)
if Task.description=="Engage_Target" then
self:Disengage()
end
self:T(self.lid.."Task Done but NO mission found ==> _CheckGroupDone in 1 sec")
self:_CheckGroupDone(1)
end
@ -3429,7 +3447,7 @@ function OPSGROUP:_GetNextMission()
for _,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
if mission:GetGroupStatus(self)==AUFTRAG.Status.SCHEDULED and (mission:IsReadyToGo() or self.airwing) and (mission.importance==nil or mission.importance<=vip) then
if mission:GetGroupStatus(self)==AUFTRAG.Status.SCHEDULED and (mission:IsReadyToGo() or self.legion) and (mission.importance==nil or mission.importance<=vip) then
return mission
end
end
@ -3714,7 +3732,7 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission)
self:SwitchROE()
end
-- ROT to default
if Mission.optionROT then
if self:IsFlightgroup() and Mission.optionROT then
self:SwitchROT()
end
-- Alarm state to default.
@ -3753,9 +3771,14 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission)
if Mission.icls then
self:_SwitchICLS()
end
local delay=1
if Mission.type==AUFTRAG.Type.ARTY then
delay=10
end
-- Check if group is done.
self:_CheckGroupDone(1)
self:_CheckGroupDone(delay)
end
@ -3769,6 +3792,9 @@ function OPSGROUP:RouteToMission(mission, delay)
-- Delayed call.
self:ScheduleOnce(delay, OPSGROUP.RouteToMission, self, mission)
else
-- Debug info.
self:T(self.lid..string.format("Route To Mission"))
if self:IsDead() or self:IsStopped() then
return
@ -3907,6 +3933,12 @@ function OPSGROUP:RouteToMission(mission, delay)
if mission.icls then
self:SwitchICLS(mission.icls.Channel, mission.icls.Morse, mission.icls.UnitName)
end
if self:IsArmygroup() then
self:Cruise(mission.missionSpeed and UTILS.KmphToKnots(mission.missionSpeed) or self:GetSpeedCruise())
elseif self:IsNavygroup() then
self:Cruise(mission.missionSpeed and UTILS.KmphToKnots(mission.missionSpeed) or self:GetSpeedCruise())
end
end
end
@ -7165,6 +7197,11 @@ function OPSGROUP:_CheckGroupDone(delay)
self:UpdateRoute()
return
end
-- Group is returning
if self:IsReturning() then
return
end
-- Group is waiting. We deny all updates.
if self:IsWaiting() then
@ -7224,10 +7261,19 @@ function OPSGROUP:_CheckGroupDone(delay)
-- Passed FINAL waypoint
---
-- No further waypoints. Command a full stop.
self:__FullStop(-1)
if self.legion then
self:T(self.lid..string.format("Passed final WP, adinfinitum=FALSE, LEGION set ==> RTZ"))
self:RTZ(self.legion.spawnzone)
else
self:T(self.lid..string.format("Passed final WP, adinfinitum=FALSE ==> Full Stop"))
-- No further waypoints. Command a full stop.
self:__FullStop(-1)
self:T(self.lid..string.format("Passed final WP, adinfinitum=FALSE ==> Full Stop"))
end
else
@ -7237,7 +7283,6 @@ function OPSGROUP:_CheckGroupDone(delay)
if #self.waypoints>0 then
self:T(self.lid..string.format("NOT Passed final WP, #WP>0 ==> Update Route"))
--self:UpdateRoute()
self:Cruise()
else
self:E(self.lid..string.format("WARNING: No waypoints left! Commanding a Full Stop"))
@ -7810,6 +7855,10 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
-- Trigger Retreated event.
opsgroup:Retreated()
elseif opsgroup:IsReturning() then
opsgroup:Returned()
elseif opsgroup:IsPickingup() then
@ -8008,23 +8057,27 @@ end
-- @return #OPSGROUP self
function OPSGROUP:SwitchROT(rot)
if self:IsAlive() or self:IsInUtero() then
if self:IsFlightgroup() then
self.option.ROT=rot or self.optionDefault.ROT
if self:IsInUtero() then
self:T2(self.lid..string.format("Setting current ROT=%d when GROUP is SPAWNED", self.option.ROT))
if self:IsAlive() or self:IsInUtero() then
self.option.ROT=rot or self.optionDefault.ROT
if self:IsInUtero() then
self:T2(self.lid..string.format("Setting current ROT=%d when GROUP is SPAWNED", self.option.ROT))
else
self.group:OptionROT(self.option.ROT)
-- Debug info.
self:T(self.lid..string.format("Setting current ROT=%d (0=NoReaction, 1=Passive, 2=Evade, 3=ByPass, 4=AllowAbort)", self.option.ROT))
end
else
self.group:OptionROT(self.option.ROT)
-- Debug info.
self:T(self.lid..string.format("Setting current ROT=%d (0=NoReaction, 1=Passive, 2=Evade, 3=ByPass, 4=AllowAbort)", self.option.ROT))
self:E(self.lid.."WARNING: Cannot switch ROT! Group is not alive")
end
else
self:E(self.lid.."WARNING: Cannot switch ROT! Group is not alive")
end
return self
@ -9545,7 +9598,7 @@ function OPSGROUP:_AddElementByName(unitname)
end
-- Trigger spawned event if alive.
if unit:IsAlive() then
if unit:IsAlive() and element.status~=OPSGROUP.ElementStatus.SPAWNED then
-- This needs to be slightly delayed (or moved elsewhere) or the first element will always trigger the group spawned event as it is not known that more elements are in the group.
self:__ElementSpawned(0.05, element)
end

View File

@ -18,6 +18,7 @@
-- @type PLATOON
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity level.
-- @field Ops.OpsGroup#OPSGROUP.WeaponData weaponData Weapon data table with key=BitType.
-- @extends Ops.Cohort#COHORT
--- *Some cool cohort quote* -- Known Author
@ -34,6 +35,7 @@
PLATOON = {
ClassName = "PLATOON",
verbose = 0,
weaponData = {},
}
--- PLATOON class version.
@ -87,6 +89,29 @@ function PLATOON:GetBrigade()
return self.legion
end
--- Add a weapon range for ARTY auftrag.
-- @param #PLATOON self
-- @param #number RangeMin Minimum range in nautical miles. Default 0 NM.
-- @param #number RangeMax Maximum range in nautical miles. Default 10 NM.
-- @param #number BitType Bit mask of weapon type for which the given min/max ranges apply. Default is `ENUMS.WeaponFlag.Auto`, i.e. for all weapon types.
-- @return #PLATOON self
function PLATOON:AddWeaponRange(RangeMin, RangeMax, BitType)
RangeMin=UTILS.NMToMeters(RangeMin or 0)
RangeMax=UTILS.NMToMeters(RangeMax or 10)
local weapon={} --Ops.OpsGroup#OPSGROUP.WeaponData
weapon.BitType=BitType or ENUMS.WeaponFlag.Auto
weapon.RangeMax=RangeMax
weapon.RangeMin=RangeMin
self.weaponData=self.weaponData or {}
self.weaponData[weapon.BitType]=weapon
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -99,7 +124,7 @@ end
function PLATOON:onafterStart(From, Event, To)
-- Short info.
local text=string.format("Starting PLATOON %s", self.name)
local text=string.format("Starting %s v%s %s", self.ClassName, self.version, self.name)
self:I(self.lid..text)
-- Start the status monitoring.