- Fixed oscillation between UpdateRoute and CheckGroupDone in FLIGHTGROUP
- Improvements regarding capturing zones.
- Reduced log output
This commit is contained in:
Frank 2021-09-28 23:26:33 +02:00
parent be0558849c
commit b48958995a
12 changed files with 561 additions and 160 deletions

View File

@ -1342,7 +1342,7 @@ function ZONE:New( ZoneName )
-- Error!
if not Zone then
error( "Zone " .. ZoneName .. " does not exist." )
env.error( "ERROR: Zone " .. ZoneName .. " does not exist!" )
return nil
end

View File

@ -812,6 +812,39 @@ function ARMYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Formation,
end
--- On after "OutOfAmmo" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function ARMYGROUP:onafterOutOfAmmo(From, Event, To)
self:T(self.lid..string.format("Group is out of ammo at t=%.3f", timer.getTime()))
-- Fist, check if we want to rearm once out-of-ammo.
if self.rearmOnOutOfAmmo then
local truck=self:FindNearestAmmoSupply(30)
if truck then
self:T(self.lid..string.format("Found Ammo Truck %s [%s]"))
local Coordinate=truck:GetCoordinate()
self:Rearm(Coordinate, Formation)
return
end
end
-- Second, check if we want to retreat once out of ammo.
if self.retreatOnOutOfAmmo then
self:Retreat()
return
end
-- Third, check if we want to RTZ once out of ammo.
if self.rtzOnOutOfAmmo then
self:RTZ()
end
end
--- On before "Rearm" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
@ -1403,6 +1436,7 @@ end
-- @param #ARMYGROUP self
-- @param #number Radius Search radius in NM. Default 30 NM.
-- @return Wrapper.Group#GROUP Closest ammo supplying group or `nil` if no group is in the given radius.
-- @return #number Distance to closest group in meters.
function ARMYGROUP:FindNearestAmmoSupply(Radius)
-- Radius in meters.
@ -1410,6 +1444,9 @@ function ARMYGROUP:FindNearestAmmoSupply(Radius)
-- Current positon.
local coord=self:GetCoordinate()
-- Get my coalition.
local myCoalition=self:GetCoalition()
-- Scanned units.
local units=coord:ScanUnits(Radius)
@ -1421,10 +1458,10 @@ function ARMYGROUP:FindNearestAmmoSupply(Radius)
local unit=_unit --Wrapper.Unit#UNIT
-- Check coaliton and if unit can supply ammo.
if unit:GetCoalition()==self:GetCoalition() and unit:IsAmmoSupply() then
if unit:GetCoalition()==myCoalition and unit:IsAmmoSupply() then
-- Distance.
local d=unit:GetCoordinate():Get2DDistance(coord)
local d=coord:Get2DDistance(unit:GetCoord())
-- Check if distance is smaller.
if d<dmin then
@ -1436,10 +1473,10 @@ function ARMYGROUP:FindNearestAmmoSupply(Radius)
end
if truck then
return truck:GetGroup()
return truck:GetGroup(), dmin
end
return nil
return nil, nil
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -369,7 +369,7 @@ _AUFTRAGSNR=0
-- @field #string AMMOSUPPLY Ammo supply.
-- @field #string FUELSUPPLY Fuel supply.
-- @field #string ALERT5 Alert 5.
-- @field #string ONWATCH On watch.
-- @field #string ONGUARD On guard.
AUFTRAG.Type={
ANTISHIP="Anti Ship",
AWACS="AWACS",
@ -397,8 +397,8 @@ AUFTRAG.Type={
OPSTRANSPORT="Ops Transport",
AMMOSUPPLY="Ammo Supply",
FUELSUPPLY="Fuel Supply",
ALERT5="Alert 5",
ONWATCH="On Watch",
ALERT5="Alert5",
ONGUARD="On Guard",
}
--- Mission status of an assigned group.
@ -408,14 +408,14 @@ AUFTRAG.Type={
-- @field #string AMMOSUPPLY Ammo Supply.
-- @field #string FUELSUPPLY Fuel Supply.
-- @field #string ALERT5 Alert 5 task.
-- @field #string ONWATCH On Watch
-- @field #string ONGUARD On guard.
AUFTRAG.SpecialTask={
PATROLZONE="PatrolZone",
RECON="ReconMission",
AMMOSUPPLY="Ammo Supply",
FUELSUPPLY="Fuel Supply",
ALERT5="Alert 5",
ONWATCH="On Watch",
ALERT5="Alert5",
ONGUARD="On Guard",
}
--- Mission status.
@ -1692,6 +1692,7 @@ function AUFTRAG:NewALERT5(MissionType)
local mission=AUFTRAG:New(AUFTRAG.Type.ALERT5)
mission.missionTask=self:GetMissionTaskforMissionType(MissionType)
mission.optionROE=ENUMS.ROE.WeaponHold
mission.optionROT=ENUMS.ROT.NoReaction
@ -1706,6 +1707,28 @@ function AUFTRAG:NewALERT5(MissionType)
return mission
end
--- **[GROUND, NAVAL]** Create an ON GUARD mission.
-- @param #AUFTRAG self
-- @param Core.Point#COORDINATE Coordinate Coordinate, were to be on guard.
-- @return #AUFTRAG self
function AUFTRAG:NewONGUARD(Coordinate)
local mission=AUFTRAG:New(AUFTRAG.Type.ONGUARD)
mission:_TargetFromObject(Coordinate)
mission.optionROE=ENUMS.ROE.OpenFire
mission.optionAlarm=ENUMS.AlarmState.Red
mission.missionFraction=1.0
mission.categories={AUFTRAG.Category.GROUND, AUFTRAG.Category.NAVAL}
mission.DCStask=mission:GetDCSMissionTask()
return mission
end
--- Create a mission to attack a TARGET object.
-- @param #AUFTRAG self
@ -2328,7 +2351,7 @@ function AUFTRAG:AssignSquadrons(Squadrons)
for _,_squad in pairs(Squadrons) do
local squadron=_squad --Ops.Squadron#SQUADRON
self:I(self.lid..string.format("Assigning squadron %s", tostring(squadron.name)))
self:T(self.lid..string.format("Assigning squadron %s", tostring(squadron.name)))
self:AssignCohort(squadron)
end
@ -3313,7 +3336,7 @@ end
function AUFTRAG:AddLegion(Legion)
-- Debug info.
self:I(self.lid..string.format("Adding legion %s", Legion.alias))
self:T(self.lid..string.format("Adding legion %s", Legion.alias))
-- Add legion to table.
table.insert(self.legions, Legion)
@ -3332,7 +3355,7 @@ function AUFTRAG:RemoveLegion(Legion)
local legion=self.legions[i] --Ops.Legion#LEGION
if legion.alias==Legion.alias then
-- Debug info.
self:I(self.lid..string.format("Removing legion %s", Legion.alias))
self:T(self.lid..string.format("Removing legion %s", Legion.alias))
table.remove(self.legions, i)
return self
end
@ -3353,7 +3376,7 @@ function AUFTRAG:SetLegionStatus(Legion, Status)
local status=self:GetLegionStatus(Legion)
-- Debug info.
self:I(self.lid..string.format("Setting LEGION %s to status %s-->%s", Legion.alias, tostring(status), tostring(Status)))
self:T(self.lid..string.format("Setting LEGION %s to status %s-->%s", Legion.alias, tostring(status), tostring(Status)))
-- New status.
self.statusLegion[Legion.alias]=Status
@ -4750,6 +4773,24 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable)
DCStask.params=param
table.insert(DCStasks, DCStask)
elseif self.type==AUFTRAG.Type.ONGUARD then
----------------------
-- ON GUARD Mission --
----------------------
local DCStask={}
DCStask.id=AUFTRAG.SpecialTask.ONGUARD
-- We create a "fake" DCS task and pass the parameters to the OPSGROUP.
local param={}
param.coordinate=self:GetObjective()
DCStask.params=param
table.insert(DCStasks, DCStask)
else
self:E(self.lid..string.format("ERROR: Unknown mission task!"))

View File

@ -18,7 +18,8 @@
-- @type BRIGADE
-- @field #string ClassName Name of the class.
-- @field #number verbose Verbosity of output.
-- @field #table rearmingZones Rearming zones. Each element is of type `#BRIGADE.RearmingZone`.
-- @field #table rearmingZones Rearming zones. Each element is of type `#BRIGADE.SupplyZone`.
-- @field #table refuellingZones Refuelling zones. Each element is of type `#BRIGADE.SupplyZone`.
-- @field Core.Set#SET_ZONE retreatZones Retreat zone set.
-- @extends Ops.Legion#LEGION
@ -33,16 +34,17 @@
--
-- @field #BRIGADE
BRIGADE = {
ClassName = "BRIGADE",
verbose = 0,
rearmingZones = {},
ClassName = "BRIGADE",
verbose = 0,
rearmingZones = {},
refuellingZones = {},
}
--- Rearming Zone.
-- @type BRIGADE.RearmingZone
--- Supply Zone.
-- @type BRIGADE.SupplyZone
-- @field Core.Zone#ZONE zone The zone.
-- @field #boolean occupied If `true`, a rearming truck is present in the zone.
-- @field Ops.Auftrag#AUFTRAG mission Mission assigned to supply ammo.
-- @field Ops.Auftrag#AUFTRAG mission Mission assigned to supply ammo or fuel.
-- @field #boolean markerOn If `true`, marker is on.
-- @field Wrapper.Marker#MARKER marker F10 marker.
--- BRIGADE class version.
@ -225,13 +227,12 @@ end
--- Add a rearming zone.
-- @param #BRIGADE self
-- @param Core.Zone#ZONE RearmingZone Rearming zone.
-- @return #BRIGADE.RearmingZone The rearming zone data.
-- @return #BRIGADE.SupplyZone The rearming zone data.
function BRIGADE:AddRearmingZone(RearmingZone)
local rearmingzone={} --#BRIGADE.RearmingZone
local rearmingzone={} --#BRIGADE.SupplyZone
rearmingzone.zone=RearmingZone
rearmingzone.occupied=false
rearmingzone.mission=nil
rearmingzone.marker=MARKER:New(rearmingzone.zone:GetCoordinate(), "Rearming Zone"):ToCoalition(self:GetCoalition())
@ -241,6 +242,24 @@ function BRIGADE:AddRearmingZone(RearmingZone)
end
--- Add a refuelling zone.
-- @param #BRIGADE self
-- @param Core.Zone#ZONE RefuellingZone Refuelling zone.
-- @return #BRIGADE.SupplyZone The refuelling zone data.
function BRIGADE:AddRefuellingZone(RefuellingZone)
local supplyzone={} --#BRIGADE.SupplyZone
supplyzone.zone=RefuellingZone
supplyzone.mission=nil
supplyzone.marker=MARKER:New(supplyzone.zone:GetCoordinate(), "Refuelling Zone"):ToCoalition(self:GetCoalition())
table.insert(self.rearmingZones, supplyzone)
return supplyzone
end
--- Get platoon by name.
-- @param #BRIGADE self
-- @param #string PlatoonName Name of the platoon.
@ -312,14 +331,28 @@ function BRIGADE:onafterStatus(From, Event, To)
-- Rearming Zones ---
---------------------
for i,_rearmingzone in pairs(self.rearmingZones) do
local rearmingzone=_rearmingzone --#BRIGADE.RearmingZone
for _,_rearmingzone in pairs(self.rearmingZones) do
local rearmingzone=_rearmingzone --#BRIGADE.SupplyZone
if (not rearmingzone.mission) or rearmingzone.mission:IsOver() then
rearmingzone.mission=AUFTRAG:NewAMMOSUPPLY(rearmingzone.zone)
self:AddMission(rearmingzone.mission)
end
end
-----------------------
-- Refuelling Zones ---
-----------------------
-- Check refuelling zones.
for _,_supplyzone in pairs(self.refuellingZones) do
local supplyzone=_supplyzone --#BRIGADE.SupplyZone
-- Check if mission is nil or over.
if (not supplyzone.mission) or supplyzone.mission:IsOver() then
supplyzone.mission=AUFTRAG:NewFUELSUPPLY(supplyzone.zone)
self:AddMission(supplyzone.mission)
end
end
-----------
-- Info ---
@ -396,19 +429,28 @@ function BRIGADE:onafterStatus(From, Event, To)
-------------------
-- Rearming Info --
-------------------
if self.verbose>=0 then
if self.verbose>=4 then
local text="Rearming Zones:"
for i,_rearmingzone in pairs(self.rearmingZones) do
local rearmingzone=_rearmingzone --#BRIGADE.RearmingZone
local name=rearmingzone.zone:GetName()
-- Platoon text.
text=text..string.format("\n* %s: Mission status=%s, suppliers=%d", name, rearmingzone.mission:GetState(), rearmingzone.mission:CountOpsGroups())
local rearmingzone=_rearmingzone --#BRIGADE.SupplyZone
-- Info text.
text=text..string.format("\n* %s: Mission status=%s, suppliers=%d", rearmingzone.zone:GetName(), rearmingzone.mission:GetState(), rearmingzone.mission:CountOpsGroups())
end
self:I(self.lid..text)
end
-------------------
-- Refuelling Info --
-------------------
if self.verbose>=4 then
local text="Refuelling Zones:"
for i,_refuellingzone in pairs(self.refuellingZones) do
local refuellingzone=_refuellingzone --#BRIGADE.SupplyZone
-- Info text.
text=text..string.format("\n* %s: Mission status=%s, suppliers=%d", refuellingzone.zone:GetName(), refuellingzone.mission:GetState(), refuellingzone.mission:CountOpsGroups())
end
self:I(self.lid..text)
end
end

View File

@ -60,11 +60,13 @@ CHIEF.DEFCON = {
--- Strategy.
-- @type CHIEF.Strategy
-- @field #string PASSIVE No targets at all are engaged.
-- @field #string DEFENSIVE Only target in our own terretory are engaged.
-- @field #string OFFENSIVE Targets in own terretory and yellow zones are engaged.
-- @field #string AGGRESSIVE Targets in own terretroy, yellow zones and engage zones are engaged.
-- @field #string AGGRESSIVE Targets in own terretory, conflict zones and attack zones are engaged.
-- @field #string TOTALWAR Anything is engaged anywhere.
CHIEF.Strategy = {
PASSIVE="Passive",
DEFENSIVE="Defensive",
OFFENSIVE="Offensive",
AGGRESSIVE="Aggressive",
@ -570,13 +572,25 @@ end
--- Add a rearming zone.
-- @param #CHIEF self
-- @param Core.Zone#ZONE RearmingZone Rearming zone.
-- @return Ops.Brigade#BRIGADE.RearmingZone The rearming zone data.
-- @return Ops.Brigade#BRIGADE.SupplyZone The rearming zone data.
function CHIEF:AddRearmingZone(RearmingZone)
-- Hand over to commander.
local rearmingzone=self.commander:AddRearmingZone(RearmingZone)
local supplyzone=self.commander:AddRearmingZone(RearmingZone)
return rearmingzone
return supplyzone
end
--- Add a refuelling zone.
-- @param #CHIEF self
-- @param Core.Zone#ZONE RefuellingZone Refuelling zone.
-- @return Ops.Brigade#BRIGADE.SupplyZone The refuelling zone data.
function CHIEF:AddRefuellingZone(RefuellingZone)
-- Hand over to commander.
local supplyzone=self.commander:AddRefuellingZone(RefuellingZone)
return supplyzone
end
@ -840,7 +854,8 @@ function CHIEF:onafterStatus(From, Event, To)
for i,_opszone in pairs(self.zonequeue) do
local opszone=_opszone --Ops.OpsZone#OPSZONE
text=text..string.format("\n[%d] %s [%s]: owner=%d [%d]: Blue=%d, Red=%d, Neutral=%d", i, opszone.zone:GetName(), opszone:GetState(), opszone:GetOwner(), opszone:GetPreviousOwner(), opszone.Nblu, opszone.Nred, opszone.Nnut)
text=text..string.format("\n[%d] %s [%s]: owner=%d [%d] (prio=%d, importance=%s): Blue=%d, Red=%d, Neutral=%d", i,
opszone.zone:GetName(), opszone:GetState(), opszone:GetOwner(), opszone:GetPreviousOwner(), opszone.prio, tostring(opszone.importance), opszone.Nblu, opszone.Nred, opszone.Nnut)
end
self:I(self.lid..text)
@ -1059,14 +1074,22 @@ function CHIEF:CheckTargetQueue()
local target=_target --Ops.Target#TARGET
-- Is this a threat?
local isThreat=target.threatlevel0>=self.threatLevelMin and target.threatlevel0<=self.threatLevelMax
local isThreat=target.threatlevel0>=self.threatLevelMin and target.threatlevel0<=self.threatLevelMax
-- Check that target is alive and not already a mission has been assigned.
if target:IsAlive() and (target.importance==nil or target.importance<=vip) and isThreat and not target.mission then
-- Check if this target is "valid", i.e. fits with the current strategy.
local valid=false
if self.strategy==CHIEF.Strategy.DEFENSIVE then
if self.strategy==CHIEF.Strategy.PASSIVE then
---
-- PASSIVE: No targets at all are attacked.
---
valid=false
elseif self.strategy==CHIEF.Strategy.DEFENSIVE then
---
-- DEFENSIVE: Attack inside borders only.
@ -1146,7 +1169,6 @@ function CHIEF:CheckTargetQueue()
if mission then
for _,_asset in pairs(assets) do
local asset=_asset
asset.isReserved=true
mission:AddAsset(asset)
end
Legions=legions
@ -1204,19 +1226,20 @@ function CHIEF:CheckOpsZoneQueue()
-- Sort results table wrt ?.
local function _sort(a, b)
local taskA=a --Ops.Target#TARGET
local taskB=b --Ops.Target#TARGET
local taskA=a --Ops.OpsZone#OPSZONE
local taskB=b --Ops.OpsZone#OPSZONE
return (taskA.prio<taskB.prio)
end
--table.sort(self.zonequeue, _sort)
table.sort(self.zonequeue, _sort)
-- Get the lowest importance value (lower means more important).
-- If a target with importance 1 exists, targets with importance 2 will not be assigned. Targets with no importance (nil) can still be selected.
-- If a zone with importance 1 exists that is not owned by us, zones with importance 2 will not be assigned. Zone with no importance (nil) can still be selected.
local vip=math.huge
for _,_target in pairs(self.zonequeue) do
local target=_target --Ops.Target#TARGET
if target.importance and target.importance<vip then
vip=target.importance
for _,_opszone in pairs(self.zonequeue) do
local opszone=_opszone --Ops.OpsZone#OPSZONE
if opszone.importance and opszone.importance<vip and opszone:GetOwner()~=self.coalition then
-- Most important zone that is NOT owned by us.
vip=opszone.importance
end
end
@ -1226,15 +1249,43 @@ function CHIEF:CheckOpsZoneQueue()
-- Current owner of the zone.
local ownercoalition=opszone:GetOwner()
-- Check coalition and importance.
if ownercoalition~=self.coalition and (opszone.importance==nil or opszone.importance<=vip) then
local hasMission=opszone.missionPatrol and opszone.missionPatrol:IsNotOver() or false
-- Has a patrol mission?
local hasMissionPatrol=opszone.missionPatrol and opszone.missionPatrol:IsNotOver() or false
-- Has a CAS mission?
local hasMissionCAS=opszone.missionCAS and opszone.missionCAS:IsNotOver() or false
-- Debug info.
self:T(self.lid..string.format("Zone %s [%s] is owned by coalition %d", opszone.zone:GetName(), opszone:GetState(), ownercoalition))
if ownercoalition~=self.coalition and not hasMission then
env.info(string.format("Zone %s is owned by coalition %d", opszone.zone:GetName(), ownercoalition))
if opszone:IsEmpty() then
-- Recruit ground assets that
local recruited=self:RecruitAssetsForZone(opszone, AUFTRAG.Type.PATROLZONE, 1, 3, {Group.Category.GROUND}, {GROUP.Attribute.GROUND_INFANTRY})
if not hasMissionPatrol then
-- Debug info.
self:T(self.lid..string.format("Zone is empty ==> Recruit Patrol zone infantry assets"))
-- Recruit ground assets that
local recruited=self:RecruitAssetsForZone(opszone, AUFTRAG.Type.PATROLZONE, 1, 3, {Group.Category.GROUND}, {GROUP.Attribute.GROUND_INFANTRY})
end
else
if not hasMissionCAS then
-- Debug message.
self:T(self.lid..string.format("Zone is NOT empty ==> recruit CAS assets"))
-- Recruite CAS assets.
local recruited=self:RecruitAssetsForZone(opszone, AUFTRAG.Type.CAS, 1, 3)
end
end
end
@ -1568,45 +1619,78 @@ function CHIEF:RecruitAssetsForZone(OpsZone, MissionType, NassetsMin, NassetsMax
-- Target position.
local TargetVec2=OpsZone.zone:GetVec2()
-- Recruite infantry assets.
local recruitedInf, assetsInf, legionsInf=LEGION.RecruitCohortAssets(Cohorts, MissionType, nil, NassetsMin, NassetsMax, TargetVec2, nil, nil, nil, nil, Categories, Attributes)
local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, MissionType, nil, NassetsMin, NassetsMax, TargetVec2, nil, nil, nil, nil, Categories, Attributes)
if recruitedInf then
if recruited then
env.info(string.format("Recruited %d assets from for PATROL mission", #assetsInf))
-- Recruit transport assets for infantry.
local recruitedTrans, transport=LEGION.AssignAssetsForTransport(self.commander, self.commander.legions, assetsInf, 1, 1, OpsZone.zone, nil, {Group.Category.HELICOPTER, Group.Category.GROUND})
-- Create Patrol zone mission.
local mission=AUFTRAG:NewPATROLZONE(OpsZone.zone)
mission:SetEngageDetected()
-- Add assets to mission.
for _,asset in pairs(assetsInf) do
mission:AddAsset(asset)
end
-- Attach OPS transport to mission.
mission.opstransport=transport
if MissionType==AUFTRAG.Type.PATROLZONE then
-- Debug messgage.
self:T2(self.lid..string.format("Recruited %d assets from for PATROL mission", #assets))
local recruitedTrans=true
local transport=nil
if Attributes and Attributes[1]==GROUP.Attribute.GROUND_INFANTRY then
-- Recruit transport assets for infantry.
recruitedTrans, transport=LEGION.AssignAssetsForTransport(self.commander, self.commander.legions, assets, 1, 1, OpsZone.zone, nil, {Group.Category.HELICOPTER, Group.Category.GROUND})
-- Assign mission to legions.
for _,_legion in pairs(legionsInf) do
local legion=_legion --Ops.Legion#LEGION
self.commander:MissionAssign(legion, mission)
end
-- Attach mission to ops zone.
-- TODO: Need a better way!
OpsZone.missionPatrol=mission
end
if recruitedTrans then
return true
else
LEGION.UnRecruitAssets(assetsInf)
return false
end
-- Create Patrol zone mission.
local mission=AUFTRAG:NewPATROLZONE(OpsZone.zone)
mission:SetEngageDetected()
-- Add assets to mission.
for _,asset in pairs(assets) do
mission:AddAsset(asset)
end
-- Attach OPS transport to mission.
mission.opstransport=transport
-- Assign mission to legions.
for _,_legion in pairs(legions) do
local legion=_legion --Ops.Legion#LEGION
self.commander:MissionAssign(legion, mission)
end
-- Attach mission to ops zone.
-- TODO: Need a better way!
OpsZone.missionPatrol=mission
else
LEGION.UnRecruitAssets(assets)
end
elseif MissionType==AUFTRAG.Type.CAS then
-- Create Patrol zone mission.
local mission=AUFTRAG:NewCAS(OpsZone.zone)
-- Add assets to mission.
for _,asset in pairs(assets) do
mission:AddAsset(asset)
end
-- Assign mission to legions.
for _,_legion in pairs(legions) do
local legion=_legion --Ops.Legion#LEGION
self.commander:MissionAssign(legion, mission)
end
-- Attach mission to ops zone.
-- TODO: Need a better way!
OpsZone.missionCAS=mission
end
end
return nil
end

View File

@ -906,8 +906,14 @@ function COHORT:RecruitAssets(MissionType, Npayloads)
end
--TODO: Check transport for combat readyness!
-- Check transport/cargo for combat readyness!
if flightgroup:IsLoading() or flightgroup:IsTransporting() or flightgroup:IsUnloading() or flightgroup:IsPickingup() or flightgroup:IsCarrier() then
combatready=false
end
if flightgroup:IsCargo() or flightgroup:IsBoarding() or flightgroup:IsAwaitingLift() then
combatready=false
end
-- This asset is "combatready".
if combatready then
self:I(self.lid.."Adding SPAWNED asset to ANOTHER mission as it is COMBATREADY")

View File

@ -20,7 +20,8 @@
-- @field #table legions Table of legions which are commanded.
-- @field #table missionqueue Mission queue.
-- @field #table transportqueue Transport queue.
-- @field #table rearmingZones Rearming zones. Each element is of type `#BRIGADE.RearmingZone`.
-- @field #table rearmingZones Rearming zones. Each element is of type `#BRIGADE.SupplyZone`.
-- @field #table refuellingZones Refuelling zones. Each element is of type `#BRIGADE.SupplyZone`.
-- @field Ops.Chief#CHIEF chief Chief of staff.
-- @extends Core.Fsm#FSM
@ -35,12 +36,13 @@
--
-- @field #COMMANDER
COMMANDER = {
ClassName = "COMMANDER",
verbose = 0,
legions = {},
missionqueue = {},
transportqueue = {},
rearmingZones = {},
ClassName = "COMMANDER",
verbose = 0,
legions = {},
missionqueue = {},
transportqueue = {},
rearmingZones = {},
refuellingZones = {},
}
--- COMMANDER class version.
@ -335,13 +337,12 @@ end
--- Add a rearming zone.
-- @param #COMMANDER self
-- @param Core.Zone#ZONE RearmingZone Rearming zone.
-- @return Ops.Brigade#BRIGADE.RearmingZone The rearming zone data.
-- @return Ops.Brigade#BRIGADE.SupplyZone The rearming zone data.
function COMMANDER:AddRearmingZone(RearmingZone)
local rearmingzone={} --Ops.Brigade#BRIGADE.RearmingZone
local rearmingzone={} --Ops.Brigade#BRIGADE.SupplyZone
rearmingzone.zone=RearmingZone
rearmingzone.occupied=false
rearmingzone.mission=nil
rearmingzone.marker=MARKER:New(rearmingzone.zone:GetCoordinate(), "Rearming Zone"):ToCoalition(self:GetCoalition())
@ -350,6 +351,23 @@ function COMMANDER:AddRearmingZone(RearmingZone)
return rearmingzone
end
--- Add a refuelling zone.
-- @param #COMMANDER self
-- @param Core.Zone#ZONE RefuellingZone Refuelling zone.
-- @return Ops.Brigade#BRIGADE.SupplyZone The refuelling zone data.
function COMMANDER:AddRefuellingZone(RefuellingZone)
local rearmingzone={} --Ops.Brigade#BRIGADE.SupplyZone
rearmingzone.zone=RefuellingZone
rearmingzone.mission=nil
rearmingzone.marker=MARKER:New(rearmingzone.zone:GetCoordinate(), "Refuelling Zone"):ToCoalition(self:GetCoalition())
table.insert(self.refuellingZones, rearmingzone)
return rearmingzone
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -402,13 +420,23 @@ function COMMANDER:onafterStatus(From, Event, To)
-- Check rearming zones.
for _,_rearmingzone in pairs(self.rearmingZones) do
local rearmingzone=_rearmingzone --#BRIGADE.RearmingZone
local rearmingzone=_rearmingzone --#BRIGADE.SupplyZone
-- Check if mission is nil or over.
if (not rearmingzone.mission) or rearmingzone.mission:IsOver() then
rearmingzone.mission=AUFTRAG:NewAMMOSUPPLY(rearmingzone.zone)
self:AddMission(rearmingzone.mission)
end
end
end
-- Check refuelling zones.
for _,_supplyzone in pairs(self.refuellingZones) do
local supplyzone=_supplyzone --#BRIGADE.SupplyZone
-- Check if mission is nil or over.
if (not supplyzone.mission) or supplyzone.mission:IsOver() then
supplyzone.mission=AUFTRAG:NewFUELSUPPLY(supplyzone.zone)
self:AddMission(supplyzone.mission)
end
end
---
-- LEGIONS

View File

@ -1140,7 +1140,7 @@ function FLIGHTGROUP:OnEventEngineShutdown(EventData)
if element.unit and element.unit:IsAlive() then
local airbase=self:GetClosestAirbase()
local parking=self:GetParkingSpot(element, 10, airbase)
local parking=self:GetParkingSpot(element, 100, airbase)
if airbase and parking then
self:ElementArrived(element, airbase, parking)
@ -1548,7 +1548,7 @@ end
function FLIGHTGROUP:onafterParking(From, Event, To)
-- Get closest airbase
local airbase=self:GetClosestAirbase() --self.group:GetCoordinate():GetClosestAirbase()
local airbase=self:GetClosestAirbase()
local airbasename=airbase:GetName() or "unknown"
-- Debug info
@ -2006,7 +2006,7 @@ function FLIGHTGROUP:onafterUpdateRoute(From, Event, To, n, N)
end
-- Set current waypoint or we get problem that the _PassingWaypoint function is triggered too early, i.e. right now and not when passing the next WP.
local current=self.group:GetCoordinate():WaypointAir(COORDINATE.WaypointAltType.BARO, waypointType, waypointAction, speed, true, nil, {}, "Current")
local current=self:GetCoordinate():WaypointAir(COORDINATE.WaypointAltType.BARO, waypointType, waypointAction, speed, true, nil, {}, "Current")
table.insert(wp, current)
-- Add remaining waypoints to route.
@ -2087,14 +2087,14 @@ function FLIGHTGROUP:_CheckGroupDone(delay, waittime)
if delay and delay>0 then
-- Debug info.
self:T(self.lid..string.format("Check FLIGHTGROUP [state=%s] done in %.3f seconds...", fsmstate, delay))
self:T(self.lid..string.format("Check FLIGHTGROUP [state=%s] done in %.3f seconds... (t=%.4f)", fsmstate, delay, timer.getTime()))
-- Delayed call.
self:ScheduleOnce(delay, FLIGHTGROUP._CheckGroupDone, self)
else
-- Debug info.
self:T(self.lid..string.format("Check FLIGHTGROUP [state=%s] done?", fsmstate))
self:T(self.lid..string.format("Check FLIGHTGROUP [state=%s] done? (t=%.4f)", fsmstate, timer.getTime()))
-- First check if there is a paused mission that
if self.missionpaused then
@ -2134,7 +2134,9 @@ function FLIGHTGROUP:_CheckGroupDone(delay, waittime)
self:T(self.lid..string.format("Remaining (final=%s): missions=%d, tasks=%d, transports=%d", tostring(self.passedfinalwp), nMissions, nTasks, nTransports))
-- Final waypoint passed?
if self:HasPassedFinalWaypoint() then
-- Or next waypoint index is the first waypoint. Could be that the group was on a mission and the mission waypoints were deleted. then the final waypoint is FALSE but no real waypoint left.
-- Since we do not do ad infinitum, this leads to a rapid oscillation between UpdateRoute and CheckGroupDone!
if self:HasPassedFinalWaypoint() or self:GetWaypointIndexNext()==1 then
---
-- Final Waypoint PASSED
@ -2376,7 +2378,7 @@ function FLIGHTGROUP:_LandAtAirbase(airbase, SpeedTo, SpeedHold, SpeedLand)
local althold=self.isHelo and 1000+math.random(10)*100 or math.random(4,10)*1000
-- Holding points.
local c0=self.group:GetCoordinate()
local c0=self:GetCoordinate()
local p0=airbase:GetZone():GetRandomCoordinate():SetAltitude(UTILS.FeetToMeters(althold))
local p1=nil
local wpap=nil
@ -2527,7 +2529,7 @@ end
function FLIGHTGROUP:onafterWait(From, Event, To, Duration, Altitude, Speed)
-- Group will orbit at its current position.
local Coord=self.group:GetCoordinate()
local Coord=self:GetCoordinate()
-- Set altitude: 1000 ft for helos and 10,000 ft for panes.
if Altitude then
@ -2597,7 +2599,7 @@ function FLIGHTGROUP:onafterRefuel(From, Event, To, Coordinate)
local Speed=self.speedCruise
local coordinate=self.group:GetCoordinate()
local coordinate=self:GetCoordinate()
Coordinate=Coordinate or coordinate:Translate(UTILS.NMToMeters(5), self.group:GetHeading(), true)
@ -3972,7 +3974,7 @@ function FLIGHTGROUP:_UpdateMenu(delay)
self:I(self.lid.."FF updating menu NOW")
-- Get current position of group.
local position=self.group:GetCoordinate()
local position=self:GetCoordinate()
-- Get all FLIGHTCONTROLS
local fc={}

View File

@ -841,6 +841,13 @@ function LEGION:onafterTransportCancel(From, Event, To, Transport)
opsgroup:TransportCancel(Transport)
end
-- Delete awaited transport.
local cargos=Transport:GetCargoOpsGroups(false)
for _,_cargo in pairs(cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP
cargo:_DelMyLift(Transport)
end
-- Remove asset from mission.
Transport:DelAsset(asset)
@ -1068,7 +1075,7 @@ function LEGION:onafterAssetSpawned(From, Event, To, group, asset, request)
if cohort then
-- Debug info.
self:I(self.lid..string.format("Cohort asset spawned %s", asset.spawngroupname))
self:T(self.lid..string.format("Cohort asset spawned %s", asset.spawngroupname))
-- Create a flight group.
local flightgroup=self:_CreateFlightGroup(asset)
@ -1150,7 +1157,7 @@ function LEGION:onafterAssetSpawned(From, Event, To, group, asset, request)
-- Add group to the detection set of the CHIEF (INTEL).
local chief=self.chief or (self.commander and self.commander.chief or nil) --Ops.Chief#CHIEF
if chief then
self:I(self.lid..string.format("Adding group %s to agents of CHIEF", group:GetName()))
self:T(self.lid..string.format("Adding group %s to agents of CHIEF", group:GetName()))
chief.detectionset:AddGroup(asset.flightgroup.group)
end
@ -1932,7 +1939,7 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
local RightAttribute=CheckAttribute(cohort)
-- Debug info.
cohort:I(cohort.lid..string.format("State=%s: Capable=%s, InRange=%s, Refuel=%s, CanCarry=%s, RightCategory=%s, RightAttribute=%s",
cohort:T(cohort.lid..string.format("State=%s: Capable=%s, InRange=%s, Refuel=%s, CanCarry=%s, RightCategory=%s, RightAttribute=%s",
cohort:GetState(), tostring(Capable), tostring(InRange), tostring(Refuel), tostring(CanCarry), tostring(RightCategory), tostring(RightAttribute)))
-- Check OnDuty, capable, in range and refueling type (if TANKER).

View File

@ -69,6 +69,8 @@
-- @field #number Ndestroyed Number of destroyed units.
-- @field #number Nkills Number kills of this groups.
--
-- @field #boolean rearmOnOutOfAmmo If `true`, group will go to rearm once it runs out of ammo.
--
-- @field Ops.Legion#LEGION legion Legion the group belongs to.
-- @field Ops.Cohort#COHORT cohort Cohort the group belongs to.
--
@ -424,11 +426,13 @@ OPSGROUP.CarrierStatus={
--- Cargo status.
-- @type OPSGROUP.CargoStatus
-- @field #string AWAITING Group is awaiting carrier.
-- @field #string NOTCARGO This group is no cargo yet.
-- @field #string ASSIGNED Cargo is assigned to a carrier.
-- @field #string BOARDING Cargo is boarding a carrier.
-- @field #string LOADED Cargo is loaded into a carrier.
OPSGROUP.CargoStatus={
AWAITING="Awaiting carrier",
NOTCARGO="not cargo",
ASSIGNED="assigned to carrier",
BOARDING="boarding",
@ -1170,6 +1174,14 @@ function OPSGROUP:SetEngageDetectedOff()
return self
end
--- Set that group is going to rearm once it runs out of ammo.
-- @param #OPSGROUP self
-- @return #OPSGROUP self
function OPSGROUP:SetRearmOnOutOfAmmo()
self.rearmOnOutOfAmmo=true
return self
end
--- Check if an element of the group has line of sight to a coordinate.
-- @param #OPSGROUP self
-- @param Core.Point#COORDINATE Coordinate The position to which we check the LoS.
@ -2277,6 +2289,49 @@ function OPSGROUP:IsNotCargo(CheckTransport)
return notcargo
end
--- Check if awaiting a transport.
-- @param #OPSGROUP self
-- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport.
-- @return #OPSGROUP self
function OPSGROUP:_AddMyLift(Transport)
self.mylifts=self.mylifts or {}
self.mylifts[Transport.uid]=true
return self
end
--- Remove my lift.
-- @param #OPSGROUP self
-- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport.
-- @return #OPSGROUP self
function OPSGROUP:_DelMyLift(Transport)
if self.mylifts then
self.mylifts[Transport.uid]=nil
end
return self
end
--- Check if awaiting a transport lift.
-- @param #OPSGROUP self
-- @param Ops.OpsTransport#OPSTRANSPORT Transport (Optional) The transport.
-- @return #boolean If true, group is awaiting transport lift..
function OPSGROUP:IsAwaitingLift(Transport)
if self.mylifts then
for uid,iswaiting in pairs(self.mylifts) do
if Transport==nil or Transport.uid==uid then
if iswaiting==true then
return true
end
end
end
end
return false
end
--- Check if the group is currently boarding a carrier.
-- @param #OPSGROUP self
-- @param #string CarrierGroupName (Optional) Additionally check if group is boarding this particular carrier group.
@ -3589,10 +3644,20 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
elseif Task.dcstask.id==AUFTRAG.SpecialTask.ALERT5 then
---
-- Task Alert 5 mission.
-- Task "Alert 5" mission.
---
-- Just stay put on the airfield and wait until something happens.
elseif Task.dcstask.id==AUFTRAG.SpecialTask.ONGUARD then
---
-- Task "On Guard" Mission.
---
-- Just stay put.
--TODO: Change ALARM STATE
else
@ -3690,7 +3755,9 @@ function OPSGROUP:onafterTaskCancel(From, Event, To, Task)
elseif Task.dcstask.id==AUFTRAG.SpecialTask.FUELSUPPLY then
done=true
elseif Task.dcstask.id==AUFTRAG.SpecialTask.ALERT5 then
done=true
done=true
elseif Task.dcstask.id==AUFTRAG.SpecialTask.ONGUARD then
done=true
elseif stopflag==1 or (not self:IsAlive()) or self:IsDead() or self:IsStopped() then
-- Manual call TaskDone if setting flag to one was not successful.
done=true
@ -4200,7 +4267,7 @@ function OPSGROUP:onafterMissionCancel(From, Event, To, Mission)
---
-- Alert 5 missoins dont have a task set, which could be cancelled.
if Mission.type==AUFTRAG.Type.ALERT5 then
if Mission.type==AUFTRAG.Type.ALERT5 or Mission.type==AUFTRAG.Type.ONGUARD then
self:MissionDone(Mission)
return
end
@ -4440,6 +4507,10 @@ function OPSGROUP:RouteToMission(mission, delay)
elseif mission.type==AUFTRAG.Type.ARTY then
---
-- ARTY
---
-- Get weapon range.
local weapondata=self:GetWeaponData(mission.engageWeaponType)
@ -5990,7 +6061,7 @@ end
-- @param #string Event Event.
-- @param #string To To state.
function OPSGROUP:onafterOutOfAmmo(From, Event, To)
self:T(self.lid..string.format("Group is out of ammo at t=%.3f", timer.getTime()))
self:T(self.lid..string.format("Group is out of ammo at t=%.3f", timer.getTime()))
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -7174,7 +7245,7 @@ function OPSGROUP:onafterLoad(From, Event, To, CargoGroup, Carrier)
-- New cargo status.
CargoGroup:_NewCargoStatus(OPSGROUP.CargoStatus.LOADED)
-- Clear all waypoints.
CargoGroup:ClearWaypoints()
@ -7191,6 +7262,7 @@ function OPSGROUP:onafterLoad(From, Event, To, CargoGroup, Carrier)
-- Trigger "Loaded" event for current cargo transport.
if self.cargoTransport then
CargoGroup:_DelMyLift(self.cargoTransport)
self.cargoTransport:Loaded(CargoGroup, self, carrier)
else
self:T(self.lid..string.format("WARNING: Loaded cargo but no current OPSTRANSPORT assignment!"))
@ -7341,7 +7413,7 @@ function OPSGROUP:onafterTransport(From, Event, To)
end
-- ARMYGROUP
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid) ; waypoint.detour=1
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, nil, self:GetWaypointCurrent().uid, ENUMS.Formation.Vehicle.OnRoad) ; waypoint.detour=1
-- Give cruise command.
self:Cruise()
@ -8444,7 +8516,7 @@ function OPSGROUP:_CheckAmmoStatus()
if self.outofMissilesAA and ammo.MissilesAA>0 then
self.outofMissilesAA=false
end
if ammo.MissilesAA and self.ammo.MissilesAA>0 and not self.outofMissilesAA then
if ammo.MissilesAA==0 and self.ammo.MissilesAA>0 and not self.outofMissilesAA then
self.outofMissilesAA=true
self:OutOfMissilesAA()
end
@ -8453,7 +8525,7 @@ function OPSGROUP:_CheckAmmoStatus()
if self.outofMissilesAG and ammo.MissilesAG>0 then
self.outofMissilesAG=false
end
if ammo.MissilesAG and self.ammo.MissilesAG>0 and not self.outofMissilesAG then
if ammo.MissilesAG==0 and self.ammo.MissilesAG>0 and not self.outofMissilesAG then
self.outofMissilesAG=true
self:OutOfMissilesAG()
end
@ -8462,7 +8534,7 @@ function OPSGROUP:_CheckAmmoStatus()
if self.outofMissilesAS and ammo.MissilesAS>0 then
self.outofMissilesAS=false
end
if ammo.MissilesAS and self.ammo.MissilesAS>0 and not self.outofMissilesAS then
if ammo.MissilesAS==0 and self.ammo.MissilesAS>0 and not self.outofMissilesAS then
self.outofMissilesAS=true
self:OutOfMissilesAS()
end

View File

@ -485,6 +485,8 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet, TransportZoneCombo)
table.insert(TransportZoneCombo.Cargos, cargo)
TransportZoneCombo.Ncargo=TransportZoneCombo.Ncargo+1
cargo.opsgroup:_AddMyLift(self)
end
else
@ -1296,7 +1298,7 @@ end
function OPSTRANSPORT:AddLegion(Legion)
-- Debug info.
self:I(self.lid..string.format("Adding legion %s", Legion.alias))
self:T(self.lid..string.format("Adding legion %s", Legion.alias))
-- Add legion to table.
table.insert(self.legions, Legion)
@ -1315,7 +1317,7 @@ function OPSTRANSPORT:RemoveLegion(Legion)
local legion=self.legions[i] --Ops.Legion#LEGION
if legion.alias==Legion.alias then
-- Debug info.
self:I(self.lid..string.format("Removing legion %s", Legion.alias))
self:T(self.lid..string.format("Removing legion %s", Legion.alias))
table.remove(self.legions, i)
return self
end
@ -1409,7 +1411,7 @@ function OPSTRANSPORT:SetLegionStatus(Legion, Status)
local status=self:GetLegionStatus(Legion)
-- Debug info.
self:I(self.lid..string.format("Setting LEGION %s to status %s-->%s", Legion.alias, tostring(status), tostring(Status)))
self:T(self.lid..string.format("Setting LEGION %s to status %s-->%s", Legion.alias, tostring(status), tostring(Status)))
-- New status.
self.statusLegion[Legion.alias]=Status
@ -1681,7 +1683,7 @@ function OPSTRANSPORT:onafterCancel(From, Event, To)
local Ngroups = #self.carriers
-- Debug info.
self:I(self.lid..string.format("CANCELLING mission in status %s. Will wait for %d groups to report mission DONE before evaluation", self.status, Ngroups))
self:I(self.lid..string.format("CANCELLING transport in status %s. Will wait for %d carrier groups to report DONE before evaluation", self.status, Ngroups))
-- Time stamp.
self.Tover=timer.getAbsTime()
@ -1728,6 +1730,14 @@ function OPSTRANSPORT:onafterCancel(From, Event, To)
carrier:TransportCancel(self)
end
-- Delete awaited transport.
local cargos=self:GetCargoOpsGroups(false)
for _,_cargo in pairs(cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP
cargo:_DelMyLift(self)
end
end
-- Special mission states.
@ -1969,7 +1979,7 @@ function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier, TransportZone
local isInUtero=cargo:IsInUtero()
-- Debug info.
self:I(self.lid..string.format("Cargo=%s: notcargo=%s, iscarrier=%s inzone=%s, inutero=%s", cargo:GetName(), tostring(cargo:IsNotCargo(true)), tostring(iscarrier(cargo)), tostring(isInZone), tostring(isInUtero)))
self:T(self.lid..string.format("Cargo=%s: notcargo=%s, iscarrier=%s inzone=%s, inutero=%s", cargo:GetName(), tostring(cargo:IsNotCargo(true)), tostring(iscarrier(cargo)), tostring(isInZone), tostring(isInUtero)))
-- We look for groups that are not cargo, in the zone or in utero.
if isNotCargo and (isInZone or isInUtero) then

View File

@ -36,6 +36,8 @@
-- @field #boolean neutralCanCapture Neutral units can capture. Default `false`.
-- @field #boolean drawZone If `true`, draw the zone on the F10 map.
-- @field #boolean markZone If `true`, mark the zone on the F10 map.
-- @field #number prio Priority of the zone (for CHIEF queue).
-- @field #number importance Importance of the zone (for CHIEF queue).
-- @extends Core.Fsm#FSM
--- Be surprised!
@ -90,15 +92,34 @@ function OPSZONE:New(Zone, CoalitionOwner)
local self=BASE:Inherit(self, FSM:New()) -- #OPSZONE
-- Check if zone name instead of ZONE object was passed.
if type(Zone)=="string" then
Zone=ZONE:New(Zone)
if Zone then
if type(Zone)=="string" then
-- Convert string into a ZONE or ZONE_AIRBASE
local Name=Zone
Zone=ZONE:New(Name)
if not Zone then
local airbase=AIRBASE:FindByName(Name)
if airbase then
Zone=ZONE_AIRBASE:New(Name, 2000)
end
end
if not Zone then
self:E(string.format("ERROR: No ZONE or ZONE_AIRBASE found for name: %s", Name))
return nil
end
end
else
self:E("ERROR: First parameter Zone is nil in OPSZONE:New(Zone) call!")
return nil
end
-- Basic checks.
if not Zone then
self:E("ERROR: OPSZONE not found!")
return nil
elseif not Zone:IsInstanceOf("ZONE_RADIUS") then
if Zone:IsInstanceOf("ZONE_AIRBASE") then
self.airbase=Zone._.ZoneAirbase
self.airbaseName=self.airbase:GetName()
elseif Zone:IsInstanceOf("ZONE_RADIUS") then
-- Nothing to do.
else
self:E("ERROR: OPSZONE must be a SPHERICAL zone due to DCS restrictions!")
return nil
end
@ -115,10 +136,21 @@ function OPSZONE:New(Zone, CoalitionOwner)
self.ownerCurrent=CoalitionOwner or coalition.side.NEUTRAL
self.ownerPrevious=CoalitionOwner or coalition.side.NEUTRAL
-- We take the airbase coalition.
if self.airbase then
self.ownerCurrent=self.airbase:GetCoalition()
self.ownerPrevious=self.airbase:GetCoalition()
end
-- Set priority (default 50) and importance (default nil).
self:SetPriority()
self:SetImportance()
-- Set object categories.
self:SetObjectCategories()
self:SetUnitCategories()
-- TODO: make input function
self.drawZone=true
-- Status timer.
@ -138,8 +170,7 @@ function OPSZONE:New(Zone, CoalitionOwner)
self:AddTransition("Empty", "Guarded", "Guarded") -- Owning coalition left the zone and returned.
self:AddTransition("*", "Empty", "Empty") -- No red or blue units inside the zone.
self:AddTransition("*", "Attacked", "Attacked") -- A guarded zone is under attack.
self:AddTransition("*", "Defeated", "Guarded") -- The owning coalition defeated an attack.
@ -318,6 +349,25 @@ function OPSZONE:SetNeutralCanCapture(CanCapture)
return self
end
--- **[CHIEF]** Set mission priority.
-- @param #OPSZONE self
-- @param #number Prio Priority 1=high, 100=low. Default 50.
-- @return #OPSZONE self
function OPSZONE:SetPriority(Prio)
self.prio=Prio or 50
return self
end
--- **[CHIEF]** Set importance.
-- @param #OPSZONE self
-- @param #number Importance Number 1-10. If missions with lower value are in the queue, these have to be finished first. Default is `nil`.
-- @return #OPSZONE self
function OPSZONE:SetImportance(Importance)
self.importance=Importance
return self
end
--- Get current owner of the zone.
-- @param #OPSZONE self
-- @return #number Owner coalition.
@ -426,21 +476,14 @@ function OPSZONE:onafterStart(From, Event, To)
-- Reinit the timer.
self.timerStatus=self.timerStatus or TIMER:New(OPSZONE.Status, self)
-- Perform initial scan.
self:Scan()
if self.Nblu==0 and self.Nred==0 then
elseif self.Nblu>0 and self.Nred>0 then
elseif self.Nblu>0 then
elseif self.Nred>0 then
end
-- Status update.
self.timerStatus:Start(1, 60)
-- Handle base captured event.
if self.airbase then
self:HandleEvent(EVENTS.BaseCaptured)
end
end
--- Stop OPSZONE FSM.
@ -456,6 +499,9 @@ function OPSZONE:onafterStop(From, Event, To)
-- Reinit the timer.
self.timerStatus:Stop()
-- Unhandle events.
self:UnHandleEvent(EVENTS.BaseCaptured)
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -481,6 +527,9 @@ function OPSZONE:Status()
-- Scanning zone.
self:Scan()
-- Evaluate the scan result.
self:EvaluateZone()
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -782,10 +831,14 @@ function OPSZONE:EvaluateZone()
if Nblu>0 then
-- Blue captured red zone.
self:Captured(coalition.side.BLUE)
if not self.airbase then
self:Captured(coalition.side.BLUE)
end
elseif Nnut>0 and self.neutralCanCapture then
-- Neutral captured red zone.
self:Captured(coalition.side.NEUTRAL)
if not self.airbase then
self:Captured(coalition.side.NEUTRAL)
end
else
-- Red zone is now empty (but will remain red).
if not self:IsEmpty() then
@ -835,10 +888,14 @@ function OPSZONE:EvaluateZone()
if Nred>0 then
-- Red captured blue zone.
self:Captured(coalition.side.RED)
if not self.airbase then
self:Captured(coalition.side.RED)
end
elseif Nnut>0 and self.neutralCanCapture then
-- Neutral captured blue zone.
self:Captured(coalition.side.NEUTRAL)
if not self.airbase then
self:Captured(coalition.side.NEUTRAL)
end
else
-- Blue zone is empty now.
if not self:IsEmpty() then
@ -896,10 +953,14 @@ function OPSZONE:EvaluateZone()
self.isContested=true
elseif Nred>0 then
-- Red captured neutral zone.
self:Captured(coalition.side.RED)
if not self.airbase then
self:Captured(coalition.side.RED)
end
elseif Nblu>0 then
-- Blue captured neutral zone.
self:Captured(coalition.side.BLUE)
if not self.airbase then
self:Captured(coalition.side.BLUE)
end
else
-- Neutral zone is empty now.
if not self:IsEmpty() then
@ -947,7 +1008,7 @@ function OPSZONE:OnEventHit(EventData)
end
--- Monitor hit events.
--- Monitor base captured events.
-- @param #OPSZONE self
-- @param Core.Event#EVENTDATA EventData The event data.
function OPSZONE:OnEventBaseCaptured(EventData)
@ -960,6 +1021,17 @@ function OPSZONE:OnEventBaseCaptured(EventData)
-- Check that this airbase belongs or did belong to this warehouse.
if EventData.PlaceName==self.airbaseName then
-- New coalition of the airbase
local CoalitionNew=airbase:GetCoalition()
-- Debug info.
self:I(self.lid..string.format("EVENT BASE CAPTURED: New coalition of airbase %s: %d [previous=%d]", self.airbaseName, CoalitionNew, self.ownerCurrent))
-- Check that coalition actually changed.
if CoalitionNew~=self.ownerCurrent then
self:Captured(CoalitionNew)
end
end
end