- 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! -- Error!
if not Zone then if not Zone then
error( "Zone " .. ZoneName .. " does not exist." ) env.error( "ERROR: Zone " .. ZoneName .. " does not exist!" )
return nil return nil
end end

View File

@ -812,6 +812,39 @@ function ARMYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Formation,
end 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. --- On before "Rearm" event.
-- @param #ARMYGROUP self -- @param #ARMYGROUP self
-- @param #string From From state. -- @param #string From From state.
@ -1403,6 +1436,7 @@ end
-- @param #ARMYGROUP self -- @param #ARMYGROUP self
-- @param #number Radius Search radius in NM. Default 30 NM. -- @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 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) function ARMYGROUP:FindNearestAmmoSupply(Radius)
-- Radius in meters. -- Radius in meters.
@ -1411,6 +1445,9 @@ function ARMYGROUP:FindNearestAmmoSupply(Radius)
-- Current positon. -- Current positon.
local coord=self:GetCoordinate() local coord=self:GetCoordinate()
-- Get my coalition.
local myCoalition=self:GetCoalition()
-- Scanned units. -- Scanned units.
local units=coord:ScanUnits(Radius) local units=coord:ScanUnits(Radius)
@ -1421,10 +1458,10 @@ function ARMYGROUP:FindNearestAmmoSupply(Radius)
local unit=_unit --Wrapper.Unit#UNIT local unit=_unit --Wrapper.Unit#UNIT
-- Check coaliton and if unit can supply ammo. -- 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. -- Distance.
local d=unit:GetCoordinate():Get2DDistance(coord) local d=coord:Get2DDistance(unit:GetCoord())
-- Check if distance is smaller. -- Check if distance is smaller.
if d<dmin then if d<dmin then
@ -1436,10 +1473,10 @@ function ARMYGROUP:FindNearestAmmoSupply(Radius)
end end
if truck then if truck then
return truck:GetGroup() return truck:GetGroup(), dmin
end end
return nil return nil, nil
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -369,7 +369,7 @@ _AUFTRAGSNR=0
-- @field #string AMMOSUPPLY Ammo supply. -- @field #string AMMOSUPPLY Ammo supply.
-- @field #string FUELSUPPLY Fuel supply. -- @field #string FUELSUPPLY Fuel supply.
-- @field #string ALERT5 Alert 5. -- @field #string ALERT5 Alert 5.
-- @field #string ONWATCH On watch. -- @field #string ONGUARD On guard.
AUFTRAG.Type={ AUFTRAG.Type={
ANTISHIP="Anti Ship", ANTISHIP="Anti Ship",
AWACS="AWACS", AWACS="AWACS",
@ -397,8 +397,8 @@ AUFTRAG.Type={
OPSTRANSPORT="Ops Transport", OPSTRANSPORT="Ops Transport",
AMMOSUPPLY="Ammo Supply", AMMOSUPPLY="Ammo Supply",
FUELSUPPLY="Fuel Supply", FUELSUPPLY="Fuel Supply",
ALERT5="Alert 5", ALERT5="Alert5",
ONWATCH="On Watch", ONGUARD="On Guard",
} }
--- Mission status of an assigned group. --- Mission status of an assigned group.
@ -408,14 +408,14 @@ AUFTRAG.Type={
-- @field #string AMMOSUPPLY Ammo Supply. -- @field #string AMMOSUPPLY Ammo Supply.
-- @field #string FUELSUPPLY Fuel Supply. -- @field #string FUELSUPPLY Fuel Supply.
-- @field #string ALERT5 Alert 5 task. -- @field #string ALERT5 Alert 5 task.
-- @field #string ONWATCH On Watch -- @field #string ONGUARD On guard.
AUFTRAG.SpecialTask={ AUFTRAG.SpecialTask={
PATROLZONE="PatrolZone", PATROLZONE="PatrolZone",
RECON="ReconMission", RECON="ReconMission",
AMMOSUPPLY="Ammo Supply", AMMOSUPPLY="Ammo Supply",
FUELSUPPLY="Fuel Supply", FUELSUPPLY="Fuel Supply",
ALERT5="Alert 5", ALERT5="Alert5",
ONWATCH="On Watch", ONGUARD="On Guard",
} }
--- Mission status. --- Mission status.
@ -1692,6 +1692,7 @@ function AUFTRAG:NewALERT5(MissionType)
local mission=AUFTRAG:New(AUFTRAG.Type.ALERT5) local mission=AUFTRAG:New(AUFTRAG.Type.ALERT5)
mission.missionTask=self:GetMissionTaskforMissionType(MissionType) mission.missionTask=self:GetMissionTaskforMissionType(MissionType)
mission.optionROE=ENUMS.ROE.WeaponHold mission.optionROE=ENUMS.ROE.WeaponHold
mission.optionROT=ENUMS.ROT.NoReaction mission.optionROT=ENUMS.ROT.NoReaction
@ -1706,6 +1707,28 @@ function AUFTRAG:NewALERT5(MissionType)
return mission return mission
end 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. --- Create a mission to attack a TARGET object.
-- @param #AUFTRAG self -- @param #AUFTRAG self
@ -2328,7 +2351,7 @@ function AUFTRAG:AssignSquadrons(Squadrons)
for _,_squad in pairs(Squadrons) do for _,_squad in pairs(Squadrons) do
local squadron=_squad --Ops.Squadron#SQUADRON 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) self:AssignCohort(squadron)
end end
@ -3313,7 +3336,7 @@ end
function AUFTRAG:AddLegion(Legion) function AUFTRAG:AddLegion(Legion)
-- Debug info. -- 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. -- Add legion to table.
table.insert(self.legions, Legion) table.insert(self.legions, Legion)
@ -3332,7 +3355,7 @@ function AUFTRAG:RemoveLegion(Legion)
local legion=self.legions[i] --Ops.Legion#LEGION local legion=self.legions[i] --Ops.Legion#LEGION
if legion.alias==Legion.alias then if legion.alias==Legion.alias then
-- Debug info. -- 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) table.remove(self.legions, i)
return self return self
end end
@ -3353,7 +3376,7 @@ function AUFTRAG:SetLegionStatus(Legion, Status)
local status=self:GetLegionStatus(Legion) local status=self:GetLegionStatus(Legion)
-- Debug info. -- 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. -- New status.
self.statusLegion[Legion.alias]=Status self.statusLegion[Legion.alias]=Status
@ -4751,6 +4774,24 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable)
table.insert(DCStasks, DCStask) 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 else
self:E(self.lid..string.format("ERROR: Unknown mission task!")) self:E(self.lid..string.format("ERROR: Unknown mission task!"))
return nil return nil

View File

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

View File

@ -60,11 +60,13 @@ CHIEF.DEFCON = {
--- Strategy. --- Strategy.
-- @type CHIEF.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 DEFENSIVE Only target in our own terretory are engaged.
-- @field #string OFFENSIVE Targets in own terretory and yellow zones 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. -- @field #string TOTALWAR Anything is engaged anywhere.
CHIEF.Strategy = { CHIEF.Strategy = {
PASSIVE="Passive",
DEFENSIVE="Defensive", DEFENSIVE="Defensive",
OFFENSIVE="Offensive", OFFENSIVE="Offensive",
AGGRESSIVE="Aggressive", AGGRESSIVE="Aggressive",
@ -570,13 +572,25 @@ end
--- Add a rearming zone. --- Add a rearming zone.
-- @param #CHIEF self -- @param #CHIEF self
-- @param Core.Zone#ZONE RearmingZone Rearming zone. -- @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) function CHIEF:AddRearmingZone(RearmingZone)
-- Hand over to commander. -- 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 end
@ -840,7 +854,8 @@ function CHIEF:onafterStatus(From, Event, To)
for i,_opszone in pairs(self.zonequeue) do for i,_opszone in pairs(self.zonequeue) do
local opszone=_opszone --Ops.OpsZone#OPSZONE 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 end
self:I(self.lid..text) self:I(self.lid..text)
@ -1066,7 +1081,15 @@ function CHIEF:CheckTargetQueue()
-- Check if this target is "valid", i.e. fits with the current strategy. -- Check if this target is "valid", i.e. fits with the current strategy.
local valid=false 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. -- DEFENSIVE: Attack inside borders only.
@ -1146,7 +1169,6 @@ function CHIEF:CheckTargetQueue()
if mission then if mission then
for _,_asset in pairs(assets) do for _,_asset in pairs(assets) do
local asset=_asset local asset=_asset
asset.isReserved=true
mission:AddAsset(asset) mission:AddAsset(asset)
end end
Legions=legions Legions=legions
@ -1204,19 +1226,20 @@ function CHIEF:CheckOpsZoneQueue()
-- Sort results table wrt ?. -- Sort results table wrt ?.
local function _sort(a, b) local function _sort(a, b)
local taskA=a --Ops.Target#TARGET local taskA=a --Ops.OpsZone#OPSZONE
local taskB=b --Ops.Target#TARGET local taskB=b --Ops.OpsZone#OPSZONE
return (taskA.prio<taskB.prio) return (taskA.prio<taskB.prio)
end end
--table.sort(self.zonequeue, _sort) table.sort(self.zonequeue, _sort)
-- Get the lowest importance value (lower means more important). -- 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 local vip=math.huge
for _,_target in pairs(self.zonequeue) do for _,_opszone in pairs(self.zonequeue) do
local target=_target --Ops.Target#TARGET local opszone=_opszone --Ops.OpsZone#OPSZONE
if target.importance and target.importance<vip then if opszone.importance and opszone.importance<vip and opszone:GetOwner()~=self.coalition then
vip=target.importance -- Most important zone that is NOT owned by us.
vip=opszone.importance
end end
end end
@ -1227,14 +1250,42 @@ function CHIEF:CheckOpsZoneQueue()
-- Current owner of the zone. -- Current owner of the zone.
local ownercoalition=opszone:GetOwner() local ownercoalition=opszone:GetOwner()
local hasMission=opszone.missionPatrol and opszone.missionPatrol:IsNotOver() or false -- Check coalition and importance.
if ownercoalition~=self.coalition and (opszone.importance==nil or opszone.importance<=vip) then
if ownercoalition~=self.coalition and not hasMission then -- 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
env.info(string.format("Zone %s is owned by coalition %d", opszone.zone:GetName(), ownercoalition)) -- Debug info.
self:T(self.lid..string.format("Zone %s [%s] is owned by coalition %d", opszone.zone:GetName(), opszone:GetState(), ownercoalition))
-- Recruit ground assets that if opszone:IsEmpty() then
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 end
@ -1570,42 +1621,75 @@ function CHIEF:RecruitAssetsForZone(OpsZone, MissionType, NassetsMin, NassetsMax
local TargetVec2=OpsZone.zone:GetVec2() local TargetVec2=OpsZone.zone:GetVec2()
-- Recruite infantry assets. -- 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)) if MissionType==AUFTRAG.Type.PATROLZONE then
-- Recruit transport assets for infantry. -- Debug messgage.
local recruitedTrans, transport=LEGION.AssignAssetsForTransport(self.commander, self.commander.legions, assetsInf, 1, 1, OpsZone.zone, nil, {Group.Category.HELICOPTER, Group.Category.GROUND}) 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})
end
if recruitedTrans then
-- Create Patrol zone mission.
local mission=AUFTRAG:NewPATROLZONE(OpsZone.zone)
mission:SetEngageDetected()
-- Create Patrol zone mission. -- Add assets to mission.
local mission=AUFTRAG:NewPATROLZONE(OpsZone.zone) for _,asset in pairs(assets) do
mission:SetEngageDetected() 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
-- Add assets to mission.
for _,asset in pairs(assetsInf) do
mission:AddAsset(asset)
end end
-- Attach OPS transport to mission.
mission.opstransport=transport
-- 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
return true
else
LEGION.UnRecruitAssets(assetsInf)
return false
end end
return nil return nil

View File

@ -906,7 +906,13 @@ function COHORT:RecruitAssets(MissionType, Npayloads)
end 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". -- This asset is "combatready".
if combatready then if combatready then

View File

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

View File

@ -1140,7 +1140,7 @@ function FLIGHTGROUP:OnEventEngineShutdown(EventData)
if element.unit and element.unit:IsAlive() then if element.unit and element.unit:IsAlive() then
local airbase=self:GetClosestAirbase() local airbase=self:GetClosestAirbase()
local parking=self:GetParkingSpot(element, 10, airbase) local parking=self:GetParkingSpot(element, 100, airbase)
if airbase and parking then if airbase and parking then
self:ElementArrived(element, airbase, parking) self:ElementArrived(element, airbase, parking)
@ -1548,7 +1548,7 @@ end
function FLIGHTGROUP:onafterParking(From, Event, To) function FLIGHTGROUP:onafterParking(From, Event, To)
-- Get closest airbase -- Get closest airbase
local airbase=self:GetClosestAirbase() --self.group:GetCoordinate():GetClosestAirbase() local airbase=self:GetClosestAirbase()
local airbasename=airbase:GetName() or "unknown" local airbasename=airbase:GetName() or "unknown"
-- Debug info -- Debug info
@ -2006,7 +2006,7 @@ function FLIGHTGROUP:onafterUpdateRoute(From, Event, To, n, N)
end 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. -- 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) table.insert(wp, current)
-- Add remaining waypoints to route. -- Add remaining waypoints to route.
@ -2087,14 +2087,14 @@ function FLIGHTGROUP:_CheckGroupDone(delay, waittime)
if delay and delay>0 then if delay and delay>0 then
-- Debug info. -- 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. -- Delayed call.
self:ScheduleOnce(delay, FLIGHTGROUP._CheckGroupDone, self) self:ScheduleOnce(delay, FLIGHTGROUP._CheckGroupDone, self)
else else
-- Debug info. -- 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 -- First check if there is a paused mission that
if self.missionpaused then 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)) self:T(self.lid..string.format("Remaining (final=%s): missions=%d, tasks=%d, transports=%d", tostring(self.passedfinalwp), nMissions, nTasks, nTransports))
-- Final waypoint passed? -- 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 -- 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 local althold=self.isHelo and 1000+math.random(10)*100 or math.random(4,10)*1000
-- Holding points. -- Holding points.
local c0=self.group:GetCoordinate() local c0=self:GetCoordinate()
local p0=airbase:GetZone():GetRandomCoordinate():SetAltitude(UTILS.FeetToMeters(althold)) local p0=airbase:GetZone():GetRandomCoordinate():SetAltitude(UTILS.FeetToMeters(althold))
local p1=nil local p1=nil
local wpap=nil local wpap=nil
@ -2527,7 +2529,7 @@ end
function FLIGHTGROUP:onafterWait(From, Event, To, Duration, Altitude, Speed) function FLIGHTGROUP:onafterWait(From, Event, To, Duration, Altitude, Speed)
-- Group will orbit at its current position. -- 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. -- Set altitude: 1000 ft for helos and 10,000 ft for panes.
if Altitude then if Altitude then
@ -2597,7 +2599,7 @@ function FLIGHTGROUP:onafterRefuel(From, Event, To, Coordinate)
local Speed=self.speedCruise 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) 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") self:I(self.lid.."FF updating menu NOW")
-- Get current position of group. -- Get current position of group.
local position=self.group:GetCoordinate() local position=self:GetCoordinate()
-- Get all FLIGHTCONTROLS -- Get all FLIGHTCONTROLS
local fc={} local fc={}

View File

@ -841,6 +841,13 @@ function LEGION:onafterTransportCancel(From, Event, To, Transport)
opsgroup:TransportCancel(Transport) opsgroup:TransportCancel(Transport)
end 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. -- Remove asset from mission.
Transport:DelAsset(asset) Transport:DelAsset(asset)
@ -1068,7 +1075,7 @@ function LEGION:onafterAssetSpawned(From, Event, To, group, asset, request)
if cohort then if cohort then
-- Debug info. -- 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. -- Create a flight group.
local flightgroup=self:_CreateFlightGroup(asset) 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). -- 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 local chief=self.chief or (self.commander and self.commander.chief or nil) --Ops.Chief#CHIEF
if chief then 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) chief.detectionset:AddGroup(asset.flightgroup.group)
end end
@ -1932,7 +1939,7 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
local RightAttribute=CheckAttribute(cohort) local RightAttribute=CheckAttribute(cohort)
-- Debug info. -- 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))) cohort:GetState(), tostring(Capable), tostring(InRange), tostring(Refuel), tostring(CanCarry), tostring(RightCategory), tostring(RightAttribute)))
-- Check OnDuty, capable, in range and refueling type (if TANKER). -- 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 Ndestroyed Number of destroyed units.
-- @field #number Nkills Number kills of this groups. -- @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.Legion#LEGION legion Legion the group belongs to.
-- @field Ops.Cohort#COHORT cohort Cohort the group belongs to. -- @field Ops.Cohort#COHORT cohort Cohort the group belongs to.
-- --
@ -424,11 +426,13 @@ OPSGROUP.CarrierStatus={
--- Cargo status. --- Cargo status.
-- @type OPSGROUP.CargoStatus -- @type OPSGROUP.CargoStatus
-- @field #string AWAITING Group is awaiting carrier.
-- @field #string NOTCARGO This group is no cargo yet. -- @field #string NOTCARGO This group is no cargo yet.
-- @field #string ASSIGNED Cargo is assigned to a carrier. -- @field #string ASSIGNED Cargo is assigned to a carrier.
-- @field #string BOARDING Cargo is boarding a carrier. -- @field #string BOARDING Cargo is boarding a carrier.
-- @field #string LOADED Cargo is loaded into a carrier. -- @field #string LOADED Cargo is loaded into a carrier.
OPSGROUP.CargoStatus={ OPSGROUP.CargoStatus={
AWAITING="Awaiting carrier",
NOTCARGO="not cargo", NOTCARGO="not cargo",
ASSIGNED="assigned to carrier", ASSIGNED="assigned to carrier",
BOARDING="boarding", BOARDING="boarding",
@ -1170,6 +1174,14 @@ function OPSGROUP:SetEngageDetectedOff()
return self return self
end 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. --- Check if an element of the group has line of sight to a coordinate.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param Core.Point#COORDINATE Coordinate The position to which we check the LoS. -- @param Core.Point#COORDINATE Coordinate The position to which we check the LoS.
@ -2277,6 +2289,49 @@ function OPSGROUP:IsNotCargo(CheckTransport)
return notcargo return notcargo
end 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. --- Check if the group is currently boarding a carrier.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #string CarrierGroupName (Optional) Additionally check if group is boarding this particular carrier group. -- @param #string CarrierGroupName (Optional) Additionally check if group is boarding this particular carrier group.
@ -3589,11 +3644,21 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
elseif Task.dcstask.id==AUFTRAG.SpecialTask.ALERT5 then 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. -- 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 else
-- If task is scheduled (not waypoint) set task. -- If task is scheduled (not waypoint) set task.
@ -3691,6 +3756,8 @@ function OPSGROUP:onafterTaskCancel(From, Event, To, Task)
done=true done=true
elseif Task.dcstask.id==AUFTRAG.SpecialTask.ALERT5 then 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 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. -- Manual call TaskDone if setting flag to one was not successful.
done=true 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. -- 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) self:MissionDone(Mission)
return return
end end
@ -4440,6 +4507,10 @@ function OPSGROUP:RouteToMission(mission, delay)
elseif mission.type==AUFTRAG.Type.ARTY then elseif mission.type==AUFTRAG.Type.ARTY then
---
-- ARTY
---
-- Get weapon range. -- Get weapon range.
local weapondata=self:GetWeaponData(mission.engageWeaponType) local weapondata=self:GetWeaponData(mission.engageWeaponType)
@ -7191,6 +7262,7 @@ function OPSGROUP:onafterLoad(From, Event, To, CargoGroup, Carrier)
-- Trigger "Loaded" event for current cargo transport. -- Trigger "Loaded" event for current cargo transport.
if self.cargoTransport then if self.cargoTransport then
CargoGroup:_DelMyLift(self.cargoTransport)
self.cargoTransport:Loaded(CargoGroup, self, carrier) self.cargoTransport:Loaded(CargoGroup, self, carrier)
else else
self:T(self.lid..string.format("WARNING: Loaded cargo but no current OPSTRANSPORT assignment!")) 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 end
-- ARMYGROUP -- 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. -- Give cruise command.
self:Cruise() self:Cruise()
@ -8444,7 +8516,7 @@ function OPSGROUP:_CheckAmmoStatus()
if self.outofMissilesAA and ammo.MissilesAA>0 then if self.outofMissilesAA and ammo.MissilesAA>0 then
self.outofMissilesAA=false self.outofMissilesAA=false
end 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=true
self:OutOfMissilesAA() self:OutOfMissilesAA()
end end
@ -8453,7 +8525,7 @@ function OPSGROUP:_CheckAmmoStatus()
if self.outofMissilesAG and ammo.MissilesAG>0 then if self.outofMissilesAG and ammo.MissilesAG>0 then
self.outofMissilesAG=false self.outofMissilesAG=false
end 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=true
self:OutOfMissilesAG() self:OutOfMissilesAG()
end end
@ -8462,7 +8534,7 @@ function OPSGROUP:_CheckAmmoStatus()
if self.outofMissilesAS and ammo.MissilesAS>0 then if self.outofMissilesAS and ammo.MissilesAS>0 then
self.outofMissilesAS=false self.outofMissilesAS=false
end 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=true
self:OutOfMissilesAS() self:OutOfMissilesAS()
end end

View File

@ -485,6 +485,8 @@ function OPSTRANSPORT:AddCargoGroups(GroupSet, TransportZoneCombo)
table.insert(TransportZoneCombo.Cargos, cargo) table.insert(TransportZoneCombo.Cargos, cargo)
TransportZoneCombo.Ncargo=TransportZoneCombo.Ncargo+1 TransportZoneCombo.Ncargo=TransportZoneCombo.Ncargo+1
cargo.opsgroup:_AddMyLift(self)
end end
else else
@ -1296,7 +1298,7 @@ end
function OPSTRANSPORT:AddLegion(Legion) function OPSTRANSPORT:AddLegion(Legion)
-- Debug info. -- 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. -- Add legion to table.
table.insert(self.legions, Legion) table.insert(self.legions, Legion)
@ -1315,7 +1317,7 @@ function OPSTRANSPORT:RemoveLegion(Legion)
local legion=self.legions[i] --Ops.Legion#LEGION local legion=self.legions[i] --Ops.Legion#LEGION
if legion.alias==Legion.alias then if legion.alias==Legion.alias then
-- Debug info. -- 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) table.remove(self.legions, i)
return self return self
end end
@ -1409,7 +1411,7 @@ function OPSTRANSPORT:SetLegionStatus(Legion, Status)
local status=self:GetLegionStatus(Legion) local status=self:GetLegionStatus(Legion)
-- Debug info. -- 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. -- New status.
self.statusLegion[Legion.alias]=Status self.statusLegion[Legion.alias]=Status
@ -1681,7 +1683,7 @@ function OPSTRANSPORT:onafterCancel(From, Event, To)
local Ngroups = #self.carriers local Ngroups = #self.carriers
-- Debug info. -- 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. -- Time stamp.
self.Tover=timer.getAbsTime() self.Tover=timer.getAbsTime()
@ -1728,6 +1730,14 @@ function OPSTRANSPORT:onafterCancel(From, Event, To)
carrier:TransportCancel(self) carrier:TransportCancel(self)
end 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 end
-- Special mission states. -- Special mission states.
@ -1969,7 +1979,7 @@ function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier, TransportZone
local isInUtero=cargo:IsInUtero() local isInUtero=cargo:IsInUtero()
-- Debug info. -- 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. -- We look for groups that are not cargo, in the zone or in utero.
if isNotCargo and (isInZone or isInUtero) then if isNotCargo and (isInZone or isInUtero) then

View File

@ -36,6 +36,8 @@
-- @field #boolean neutralCanCapture Neutral units can capture. Default `false`. -- @field #boolean neutralCanCapture Neutral units can capture. Default `false`.
-- @field #boolean drawZone If `true`, draw the zone on the F10 map. -- @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 #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 -- @extends Core.Fsm#FSM
--- Be surprised! --- Be surprised!
@ -90,15 +92,34 @@ function OPSZONE:New(Zone, CoalitionOwner)
local self=BASE:Inherit(self, FSM:New()) -- #OPSZONE local self=BASE:Inherit(self, FSM:New()) -- #OPSZONE
-- Check if zone name instead of ZONE object was passed. -- Check if zone name instead of ZONE object was passed.
if type(Zone)=="string" then if Zone then
Zone=ZONE:New(Zone) 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 end
-- Basic checks. -- Basic checks.
if not Zone then if Zone:IsInstanceOf("ZONE_AIRBASE") then
self:E("ERROR: OPSZONE not found!") self.airbase=Zone._.ZoneAirbase
return nil self.airbaseName=self.airbase:GetName()
elseif not Zone:IsInstanceOf("ZONE_RADIUS") then elseif Zone:IsInstanceOf("ZONE_RADIUS") then
-- Nothing to do.
else
self:E("ERROR: OPSZONE must be a SPHERICAL zone due to DCS restrictions!") self:E("ERROR: OPSZONE must be a SPHERICAL zone due to DCS restrictions!")
return nil return nil
end end
@ -115,10 +136,21 @@ function OPSZONE:New(Zone, CoalitionOwner)
self.ownerCurrent=CoalitionOwner or coalition.side.NEUTRAL self.ownerCurrent=CoalitionOwner or coalition.side.NEUTRAL
self.ownerPrevious=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. -- Set object categories.
self:SetObjectCategories() self:SetObjectCategories()
self:SetUnitCategories() self:SetUnitCategories()
-- TODO: make input function
self.drawZone=true self.drawZone=true
-- Status timer. -- Status timer.
@ -139,7 +171,6 @@ function OPSZONE:New(Zone, CoalitionOwner)
self:AddTransition("*", "Empty", "Empty") -- No red or blue units inside the zone. self:AddTransition("*", "Empty", "Empty") -- No red or blue units inside the zone.
self:AddTransition("*", "Attacked", "Attacked") -- A guarded zone is under attack. self:AddTransition("*", "Attacked", "Attacked") -- A guarded zone is under attack.
self:AddTransition("*", "Defeated", "Guarded") -- The owning coalition defeated an attack. self:AddTransition("*", "Defeated", "Guarded") -- The owning coalition defeated an attack.
@ -318,6 +349,25 @@ function OPSZONE:SetNeutralCanCapture(CanCapture)
return self return self
end 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. --- Get current owner of the zone.
-- @param #OPSZONE self -- @param #OPSZONE self
-- @return #number Owner coalition. -- @return #number Owner coalition.
@ -426,21 +476,14 @@ function OPSZONE:onafterStart(From, Event, To)
-- Reinit the timer. -- Reinit the timer.
self.timerStatus=self.timerStatus or TIMER:New(OPSZONE.Status, self) 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. -- Status update.
self.timerStatus:Start(1, 60) self.timerStatus:Start(1, 60)
-- Handle base captured event.
if self.airbase then
self:HandleEvent(EVENTS.BaseCaptured)
end
end end
--- Stop OPSZONE FSM. --- Stop OPSZONE FSM.
@ -456,6 +499,9 @@ function OPSZONE:onafterStop(From, Event, To)
-- Reinit the timer. -- Reinit the timer.
self.timerStatus:Stop() self.timerStatus:Stop()
-- Unhandle events.
self:UnHandleEvent(EVENTS.BaseCaptured)
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -481,6 +527,9 @@ function OPSZONE:Status()
-- Scanning zone. -- Scanning zone.
self:Scan() self:Scan()
-- Evaluate the scan result.
self:EvaluateZone()
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -782,10 +831,14 @@ function OPSZONE:EvaluateZone()
if Nblu>0 then if Nblu>0 then
-- Blue captured red zone. -- 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 elseif Nnut>0 and self.neutralCanCapture then
-- Neutral captured red zone. -- Neutral captured red zone.
self:Captured(coalition.side.NEUTRAL) if not self.airbase then
self:Captured(coalition.side.NEUTRAL)
end
else else
-- Red zone is now empty (but will remain red). -- Red zone is now empty (but will remain red).
if not self:IsEmpty() then if not self:IsEmpty() then
@ -835,10 +888,14 @@ function OPSZONE:EvaluateZone()
if Nred>0 then if Nred>0 then
-- Red captured blue zone. -- 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 elseif Nnut>0 and self.neutralCanCapture then
-- Neutral captured blue zone. -- Neutral captured blue zone.
self:Captured(coalition.side.NEUTRAL) if not self.airbase then
self:Captured(coalition.side.NEUTRAL)
end
else else
-- Blue zone is empty now. -- Blue zone is empty now.
if not self:IsEmpty() then if not self:IsEmpty() then
@ -896,10 +953,14 @@ function OPSZONE:EvaluateZone()
self.isContested=true self.isContested=true
elseif Nred>0 then elseif Nred>0 then
-- Red captured neutral zone. -- Red captured neutral zone.
self:Captured(coalition.side.RED) if not self.airbase then
self:Captured(coalition.side.RED)
end
elseif Nblu>0 then elseif Nblu>0 then
-- Blue captured neutral zone. -- Blue captured neutral zone.
self:Captured(coalition.side.BLUE) if not self.airbase then
self:Captured(coalition.side.BLUE)
end
else else
-- Neutral zone is empty now. -- Neutral zone is empty now.
if not self:IsEmpty() then if not self:IsEmpty() then
@ -947,7 +1008,7 @@ function OPSZONE:OnEventHit(EventData)
end end
--- Monitor hit events. --- Monitor base captured events.
-- @param #OPSZONE self -- @param #OPSZONE self
-- @param Core.Event#EVENTDATA EventData The event data. -- @param Core.Event#EVENTDATA EventData The event data.
function OPSZONE:OnEventBaseCaptured(EventData) function OPSZONE:OnEventBaseCaptured(EventData)
@ -960,6 +1021,17 @@ function OPSZONE:OnEventBaseCaptured(EventData)
-- Check that this airbase belongs or did belong to this warehouse. -- Check that this airbase belongs or did belong to this warehouse.
if EventData.PlaceName==self.airbaseName then 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
end end