**CHIEF**
- Added resources as parameters to `:AddStrategicZone` function

**COMMANDER**
- Added function to relocate cohorts `:RelocateCohort`

**AUFTRAG**
- Added new type `AIRDEFENSE`
- Added new type `EWR`
- Added option to teleport assets to the mission ingress waypoint via `:SetTeleport`
- Added `:SetRequiredAttribute` and `:SetRequiredProperty` functions
- Added `:SetEmission` function

**LEGION**
- Fixed bug that assets on GCI dont get additional score for INTERCEPT missions
- Assets on ONGUARD or PATROLZONE are not considered for ARTY and GROUNDATTACK missions
- Added option for transport to `RelocateCohort` function
- Ground/naval assets now automatically return when out of ammo

**OPSGROUP**
- Immobile groups are teleported to mission ingress point

**RECOVERYTANKER**
- Added parameter to set TACAN mode/band (e.g. "X")

**GROUP**
- Fixed bug in `:GetSpeedMax` function

**BEACON**
- Allowed TACAN "X" mode for AA
This commit is contained in:
Frank 2022-04-27 22:36:13 +02:00
parent 2d02f4f962
commit ed0a3a22ab
16 changed files with 1061 additions and 274 deletions

View File

@ -170,6 +170,8 @@ end
function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration) function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
self:T({channel=Channel, mode=Mode, callsign=Message, bearing=Bearing, duration=Duration}) self:T({channel=Channel, mode=Mode, callsign=Message, bearing=Bearing, duration=Duration})
Mode=Mode or "Y"
-- Get frequency. -- Get frequency.
local Frequency=UTILS.TACANToFrequency(Channel, Mode) local Frequency=UTILS.TACANToFrequency(Channel, Mode)
@ -187,11 +189,16 @@ function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
-- Check if unit is an aircraft and set system accordingly. -- Check if unit is an aircraft and set system accordingly.
local AA=self.Positionable:IsAir() local AA=self.Positionable:IsAir()
if AA then if AA then
System=5 --NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER System=5 --NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
-- Check if "Y" mode is selected for aircraft. -- Check if "Y" mode is selected for aircraft.
if Mode~="Y" then if Mode=="X" then
self:E({"WARNING: The POSITIONABLE you want to attach the AA Tacan Beacon is an aircraft: Mode should Y !The BEACON is not emitting.", self.Positionable}) --self:E({"WARNING: The POSITIONABLE you want to attach the AA Tacan Beacon is an aircraft: Mode should Y!", self.Positionable})
System=BEACON.System.TACAN_TANKER_X
else
System=BEACON.System.TACAN_TANKER_Y
end end
end end
@ -267,13 +274,12 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
IsValid = false IsValid = false
end end
-- I'm using the beacon type 4 (BEACON_TYPE_TACAN). For System, I'm using 5 (TACAN_TANKER_MODE_Y) if the bearing shows its bearing -- I'm using the beacon type 4 (BEACON_TYPE_TACAN). For System, I'm using 5 (TACAN_TANKER_MODE_Y) if the bearing shows its bearing or 14 (TACAN_AA_MODE_Y) if it does not
-- or 14 (TACAN_AA_MODE_Y) if it does not
local System local System
if Bearing then if Bearing then
System = 5 System = BEACON.System.TACAN_TANKER_Y
else else
System = 14 System = BEACON.System.TACAN_AA_MODE_Y
end end
if IsValid then -- Starts the BEACON if IsValid then -- Starts the BEACON
@ -281,10 +287,13 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
self.Positionable:SetCommand({ self.Positionable:SetCommand({
id = "ActivateBeacon", id = "ActivateBeacon",
params = { params = {
type = 4, type = BEACON.Type.TACAN,
system = System, system = System,
callsign = Message, callsign = Message,
AA = true,
frequency = Frequency, frequency = Frequency,
bearing = Bearing,
modeChannel = "Y",
} }
}) })

View File

@ -60,6 +60,7 @@
-- @field #number DrawID Unique ID of the drawn zone on the F10 map. -- @field #number DrawID Unique ID of the drawn zone on the F10 map.
-- @field #table Color Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value. -- @field #table Color Table with four entries, e.g. {1, 0, 0, 0.15}. First three are RGB color code. Fourth is the transparency Alpha value.
-- @field #number ZoneID ID of zone. Only zones defined in the ME have an ID! -- @field #number ZoneID ID of zone. Only zones defined in the ME have an ID!
-- @field #number Surface Type of surface. Only determined at the center of the zone!
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
@ -111,6 +112,7 @@ ZONE_BASE = {
DrawID=nil, DrawID=nil,
Color={}, Color={},
ZoneID=nil, ZoneID=nil,
Sureface=nil,
} }
@ -335,15 +337,22 @@ end
-- @param #ZONE_BASE self -- @param #ZONE_BASE self
-- @return #nil The bounding square. -- @return #nil The bounding square.
function ZONE_BASE:GetBoundingSquare() function ZONE_BASE:GetBoundingSquare()
--return { x1 = 0, y1 = 0, x2 = 0, y2 = 0 }
return nil return nil
end end
--- Get surface type of the zone.
-- @param #ZONE_BASE self
-- @return DCS#SurfaceType Type of surface.
function ZONE_BASE:GetSurfaceType()
local coord=self:GetCoordinate()
local surface=coord:GetSurfaceType()
return surface
end
--- Bound the zone boundaries with a tires. --- Bound the zone boundaries with a tires.
-- @param #ZONE_BASE self -- @param #ZONE_BASE self
function ZONE_BASE:BoundZone() function ZONE_BASE:BoundZone()
self:F2() self:F2()
end end
@ -1281,8 +1290,8 @@ end
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 3D location within the zone. --- Returns a @{Core.Point#COORDINATE} object reflecting a random 3D location within the zone.
-- @param #ZONE_RADIUS self -- @param #ZONE_RADIUS self
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0. -- @param #number inner (Optional) Minimal distance from the center of the zone in meters. Default is 0 m.
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone. -- @param #number outer (Optional) Maximal distance from the outer edge of the zone in meters. Default is the radius of the zone.
-- @param #table surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type! -- @param #table surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type!
-- @return Core.Point#COORDINATE The random coordinate. -- @return Core.Point#COORDINATE The random coordinate.
function ZONE_RADIUS:GetRandomCoordinate(inner, outer, surfacetypes) function ZONE_RADIUS:GetRandomCoordinate(inner, outer, surfacetypes)

View File

@ -300,6 +300,9 @@ function AIRWING:AddSquadron(Squadron)
self:NewPayload(Squadron.templategroup, -1, AUFTRAG.Type.TANKER) self:NewPayload(Squadron.templategroup, -1, AUFTRAG.Type.TANKER)
end end
-- Relocate mission.
self:NewPayload(Squadron.templategroup, -1, AUFTRAG.Type.RELOCATECOHORT, 0)
-- Set airwing to squadron. -- Set airwing to squadron.
Squadron:SetAirwing(self) Squadron:SetAirwing(self)

View File

@ -33,7 +33,6 @@
-- @field #boolean formationPerma Formation that is used permanently and overrules waypoint formations. -- @field #boolean formationPerma Formation that is used permanently and overrules waypoint formations.
-- @field #boolean isMobile If true, group is mobile. -- @field #boolean isMobile If true, group is mobile.
-- @field #ARMYGROUP.Target engage Engage target. -- @field #ARMYGROUP.Target engage Engage target.
-- @field #boolean retreatOnOutOfAmmo If true, the group will automatically retreat when out of ammo. Needs a retreat zone!
-- @field Core.Set#SET_ZONE retreatZones Set of retreat zones. -- @field Core.Set#SET_ZONE retreatZones Set of retreat zones.
-- @extends Ops.OpsGroup#OPSGROUP -- @extends Ops.OpsGroup#OPSGROUP
@ -710,7 +709,7 @@ function ARMYGROUP:Status()
local ammo=self:GetAmmoTot().Total local ammo=self:GetAmmoTot().Total
-- Detected units. -- Detected units.
local ndetected=self.detectionOn and tostring(self.detectedunits:Count()) or "OFF" local ndetected=self.detectionOn and tostring(self.detectedunits:Count()) or "Off"
-- Get cargo weight. -- Get cargo weight.
local cargo=0 local cargo=0

View File

@ -72,6 +72,8 @@
-- --
-- @field Ops.Target#TARGET engageTarget Target data to engage. -- @field Ops.Target#TARGET engageTarget Target data to engage.
-- --
-- @field #boolean teleport Groups are teleported to the mission ingress waypoint.
--
-- @field Core.Zone#ZONE_RADIUS engageZone *Circular* engagement zone. -- @field Core.Zone#ZONE_RADIUS engageZone *Circular* engagement zone.
-- @field #table engageTargetTypes Table of target types that are engaged in the engagement zone. -- @field #table engageTargetTypes Table of target types that are engaged in the engagement zone.
-- @field #number engageAltitude Engagement altitude in meters. -- @field #number engageAltitude Engagement altitude in meters.
@ -162,6 +164,7 @@
-- @field #number optionRTBammo RTB on out-of-ammo. -- @field #number optionRTBammo RTB on out-of-ammo.
-- @field #number optionRTBfuel RTB on out-of-fuel. -- @field #number optionRTBfuel RTB on out-of-fuel.
-- @field #number optionECM ECM. -- @field #number optionECM ECM.
-- @field #boolean optionEmission Emission is on or off.
-- --
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
@ -312,7 +315,16 @@
-- --
-- ## Commander Level -- ## Commander Level
-- --
-- Assigning an AUFTRAG to acommander is done via the @{Ops.Commander#COMMANDER.AddMission} function. See COMMANDER docs for details. -- Assigning an AUFTRAG to a commander is done via the @{Ops.Commander#COMMANDER.AddMission} function.
-- The commander will select the best assets available from all the legions under his command. See COMMANDER docs for details.
--
-- ## Chief Level
--
-- Assigning an AUFTRAG to a commander is done via the @{Ops.Chief#CHIEF.AddMission} function. The chief will simply pass on the mission to his/her commander.
--
-- # Transportation
--
-- TODO
-- --
-- --
-- # Events -- # Events
@ -393,6 +405,8 @@ _AUFTRAGSNR=0
-- @field #string GROUNDATTACK Ground attack. -- @field #string GROUNDATTACK Ground attack.
-- @field #string CARGOTRANSPORT Cargo transport. -- @field #string CARGOTRANSPORT Cargo transport.
-- @field #string RELOCATECOHORT Relocate a cohort from one legion to another. -- @field #string RELOCATECOHORT Relocate a cohort from one legion to another.
-- @field #string AIRDEFENSE Air defense.
-- @field #string EWR Early Warning Radar.
-- @field #string NOTHING Nothing. -- @field #string NOTHING Nothing.
AUFTRAG.Type={ AUFTRAG.Type={
ANTISHIP="Anti Ship", ANTISHIP="Anti Ship",
@ -430,8 +444,10 @@ AUFTRAG.Type={
HOVER="Hover", HOVER="Hover",
GROUNDATTACK="Ground Attack", GROUNDATTACK="Ground Attack",
CARGOTRANSPORT="Cargo Transport", CARGOTRANSPORT="Cargo Transport",
NOTHING="Nothing",
RELOCATECOHORT="Relocate Cohort", RELOCATECOHORT="Relocate Cohort",
AIRDEFENSE="Air Defence",
EWR="Early Warning Radar",
NOTHING="Nothing",
} }
--- Special task description. --- Special task description.
@ -448,8 +464,9 @@ AUFTRAG.Type={
-- @field #string HOVER Hover. -- @field #string HOVER Hover.
-- @field #string GROUNDATTACK Ground attack. -- @field #string GROUNDATTACK Ground attack.
-- @field #string FERRY Ferry mission. -- @field #string FERRY Ferry mission.
-- @field #string NOTHING Nothing.
-- @field #string RELOCATECOHORT Relocate cohort. -- @field #string RELOCATECOHORT Relocate cohort.
-- @field #string AIRDEFENSE Air defense.
-- @field #string NOTHING Nothing.
AUFTRAG.SpecialTask={ AUFTRAG.SpecialTask={
FORMATION="Formation", FORMATION="Formation",
PATROLZONE="PatrolZone", PATROLZONE="PatrolZone",
@ -464,8 +481,10 @@ AUFTRAG.SpecialTask={
HOVER="Hover", HOVER="Hover",
GROUNDATTACK="Ground Attack", GROUNDATTACK="Ground Attack",
FERRY="Ferry", FERRY="Ferry",
NOTHING="Nothing",
RELOCATECOHORT="Relocate Cohort", RELOCATECOHORT="Relocate Cohort",
AIRDEFENSE="Air Defense",
EWR="Early Warning Radar",
NOTHING="Nothing",
} }
--- Mission status. --- Mission status.
@ -586,7 +605,7 @@ AUFTRAG.Category={
--- AUFTRAG class version. --- AUFTRAG class version.
-- @field #string version -- @field #string version
AUFTRAG.version="0.9.3" AUFTRAG.version="0.9.4"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -647,7 +666,6 @@ function AUFTRAG:New(Type)
self:SetPriority() self:SetPriority()
self:SetTime() self:SetTime()
self:SetRequiredAssets() self:SetRequiredAssets()
--self:SetRequiredCarriers()
self.engageAsGroup=true self.engageAsGroup=true
self.dTevaluate=5 self.dTevaluate=5
@ -1341,7 +1359,7 @@ function AUFTRAG:NewBAI(Target, Altitude)
mission:_TargetFromObject(Target) mission:_TargetFromObject(Target)
-- DCS Task options: -- DCS Task options:
mission.engageWeaponType=ENUMS.WeaponFlag.AnyAG mission.engageWeaponType=ENUMS.WeaponFlag.Auto
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 5000) mission.engageAltitude=UTILS.FeetToMeters(Altitude or 5000)
@ -1362,7 +1380,7 @@ end
--- **[AIR]** Create a SEAD mission. --- **[AIR]** Create a SEAD mission.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param Wrapper.Positionable#POSITIONABLE Target The target to attack. Can be a GROUP or UNIT object. -- @param Wrapper.Positionable#POSITIONABLE Target The target to attack. Can be a GROUP or UNIT object.
-- @param #number Altitude Engage altitude in feet. Default 8000 ft. -- @param #number Altitude Engage altitude in feet. Default 25000 ft.
-- @return #AUFTRAG self -- @return #AUFTRAG self
function AUFTRAG:NewSEAD(Target, Altitude) function AUFTRAG:NewSEAD(Target, Altitude)
@ -1371,9 +1389,9 @@ function AUFTRAG:NewSEAD(Target, Altitude)
mission:_TargetFromObject(Target) mission:_TargetFromObject(Target)
-- DCS Task options: -- DCS Task options:
mission.engageWeaponType=ENUMS.WeaponFlag.AnyAG --ENUMS.WeaponFlag.Cannons mission.engageWeaponType=ENUMS.WeaponFlag.Auto
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 8000) mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
-- Mission options: -- Mission options:
mission.missionTask=ENUMS.MissionTask.SEAD mission.missionTask=ENUMS.MissionTask.SEAD
@ -1402,7 +1420,7 @@ function AUFTRAG:NewSTRIKE(Target, Altitude)
mission:_TargetFromObject(Target) mission:_TargetFromObject(Target)
-- DCS Task options: -- DCS Task options:
mission.engageWeaponType=ENUMS.WeaponFlag.AnyAG mission.engageWeaponType=ENUMS.WeaponFlag.Auto
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 2000) mission.engageAltitude=UTILS.FeetToMeters(Altitude or 2000)
@ -1432,7 +1450,7 @@ function AUFTRAG:NewBOMBING(Target, Altitude)
mission:_TargetFromObject(Target) mission:_TargetFromObject(Target)
-- DCS task options: -- DCS task options:
mission.engageWeaponType=ENUMS.WeaponFlag.AnyBomb mission.engageWeaponType=ENUMS.WeaponFlag.Auto
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000) mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
@ -1470,7 +1488,7 @@ function AUFTRAG:NewBOMBRUNWAY(Airdrome, Altitude)
mission:_TargetFromObject(Airdrome) mission:_TargetFromObject(Airdrome)
-- DCS task options: -- DCS task options:
mission.engageWeaponType=ENUMS.WeaponFlag.AnyBomb mission.engageWeaponType=ENUMS.WeaponFlag.Auto
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000) mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
@ -1505,7 +1523,7 @@ function AUFTRAG:NewBOMBCARPET(Target, Altitude, CarpetLength)
mission:_TargetFromObject(Target) mission:_TargetFromObject(Target)
-- DCS task options: -- DCS task options:
mission.engageWeaponType=ENUMS.WeaponFlag.AnyBomb mission.engageWeaponType=ENUMS.WeaponFlag.Auto
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000) mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
mission.engageCarpetLength=CarpetLength or 500 mission.engageCarpetLength=CarpetLength or 500
@ -1996,10 +2014,55 @@ function AUFTRAG:NewONGUARD(Coordinate)
return mission return mission
end end
--- **[PRIVATE, AIR, GROUND, NAVAL]** Create a mission to relocate assets to another LEGION. --- **[GROUND, NAVAL]** Create an AIRDEFENSE mission.
-- @param #AUFTRAG self
-- @param Core.Zone#ZONE Zone Zone where the air defense group(s) should be stationed.
-- @return #AUFTRAG self
function AUFTRAG:NewAIRDEFENSE(Zone)
local mission=AUFTRAG:New(AUFTRAG.Type.AIRDEFENSE)
mission:_TargetFromObject(Zone)
mission.optionROE=ENUMS.ROE.OpenFire
mission.optionAlarm=ENUMS.AlarmState.Auto
mission.missionFraction=1.0
mission.categories={AUFTRAG.Category.GROUND, AUFTRAG.Category.NAVAL}
mission.DCStask=mission:GetDCSMissionTask()
return mission
end
--- **[GROUND]** Create an EWR mission.
-- @param #AUFTRAG self
-- @param Core.Zone#ZONE Zone Zone where the Early Warning Radar group(s) should be stationed.
-- @return #AUFTRAG self
function AUFTRAG:NewEWR(Zone)
local mission=AUFTRAG:New(AUFTRAG.Type.EWR)
mission:_TargetFromObject(Zone)
mission.optionROE=ENUMS.ROE.WeaponHold
mission.optionAlarm=ENUMS.AlarmState.Auto
mission.missionFraction=1.0
mission.categories={AUFTRAG.Category.GROUND}
mission.DCStask=mission:GetDCSMissionTask()
return mission
end
--- **[PRIVATE, AIR, GROUND, NAVAL]** Create a mission to relocate all cohort assets to another LEGION.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param Ops.Legion#LEGION Legion The new legion. -- @param Ops.Legion#LEGION Legion The new legion.
-- @param Ops.Cohort#COHORT Cohort The new cohort. -- @param Ops.Cohort#COHORT Cohort The cohort to be relocated.
-- @return #AUFTRAG self -- @return #AUFTRAG self
function AUFTRAG:_NewRELOCATECOHORT(Legion, Cohort) function AUFTRAG:_NewRELOCATECOHORT(Legion, Cohort)
@ -2312,6 +2375,14 @@ function AUFTRAG:SetDuration(Duration)
return self return self
end end
--- Set that mission assets are teleported to the mission execution waypoint.
-- @param #AUFTRAG self
-- @return #AUFTRAG self
function AUFTRAG:SetTeleport()
self.teleport=true
return self
end
--- Set mission push time. This is the time the mission is executed. If the push time is not passed, the group will wait at the mission execution waypoint. --- Set mission push time. This is the time the mission is executed. If the push time is not passed, the group will wait at the mission execution waypoint.
-- @param #AUFTRAG self -- @param #AUFTRAG self
@ -2637,6 +2708,29 @@ function AUFTRAG:AddTransportCarriers(Carriers)
end end
--- Set required attribute(s) the assets must have.
-- @param #AUFTRAG self
-- @param #table Attributes Generalized attribute(s).
-- @return #AUFTRAG self
function AUFTRAG:SetRequiredAttribute(Attributes)
if Attributes and type(Attributes)~="table" then
Attributes={Attributes}
end
self.attributes=Attributes
end
--- Set required property or properties the assets must have.
-- These are DCS attributes.
-- @param #AUFTRAG self
-- @param #table Properties Property or table of properties.
-- @return #AUFTRAG self
function AUFTRAG:SetRequiredProperty(Properties)
if Properties and type(Properties)~="table" then
Properties={Properties}
end
self.properties=Properties
end
--- Set number of required carrier groups if an OPSTRANSPORT assignment is required. --- Set number of required carrier groups if an OPSTRANSPORT assignment is required.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param #number NcarriersMin Number of carriers *at least* required. Default 1. -- @param #number NcarriersMin Number of carriers *at least* required. Default 1.
@ -2806,6 +2900,21 @@ function AUFTRAG:SetEPLRS(OnOffSwitch)
return self return self
end end
--- Set emission setting for this mission.
-- @param #AUFTRAG self
-- @param #boolean OnOffSwitch If `true` or `nil`, emission is on. If `false`, emission is off.
-- @return #AUFTRAG self
function AUFTRAG:SetEmission(OnOffSwitch)
if OnOffSwitch==nil then
self.optionEmission=true
else
self.optionEmission=OnOffSwitch
end
return self
end
--- Set formation for this mission. --- Set formation for this mission.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param #number Formation Formation. -- @param #number Formation Formation.
@ -3765,12 +3874,19 @@ function AUFTRAG:RemoveLegion(Legion)
-- Loop over legions -- Loop over legions
for i=#self.legions,1,-1 do for i=#self.legions,1,-1 do
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:T(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)
-- Set legion status to nil.
self.statusLegion[Legion.alias]=nil
return self return self
end end
end end
self:T(self.lid..string.format("ERROR: Legion %s not found and could not be removed!", Legion.alias)) self:T(self.lid..string.format("ERROR: Legion %s not found and could not be removed!", Legion.alias))
@ -4392,15 +4508,15 @@ function AUFTRAG:onafterRepeat(From, Event, To)
if self.chief then if self.chief then
-- Set status for chief.
self.statusChief=AUFTRAG.Status.PLANNED self.statusChief=AUFTRAG.Status.PLANNED
-- Remove mission from wingcommander because Chief will assign it again. -- Remove mission from wingcommander because Chief will assign it again.
if self.commander then if self.commander then
self.commander:RemoveMission(self)
self.statusCommander=AUFTRAG.Status.PLANNED self.statusCommander=AUFTRAG.Status.PLANNED
end end
-- Remove mission from airwing because WC will assign it again but maybe to a different wing. -- Remove mission from legions because commander will assign it again but maybe to different legion(s).
for _,_legion in pairs(self.legions) do for _,_legion in pairs(self.legions) do
local legion=_legion --Ops.Legion#LEGION local legion=_legion --Ops.Legion#LEGION
legion:RemoveMission(self) legion:RemoveMission(self)
@ -4408,9 +4524,10 @@ function AUFTRAG:onafterRepeat(From, Event, To)
elseif self.commander then elseif self.commander then
-- Set status for commander.
self.statusCommander=AUFTRAG.Status.PLANNED self.statusCommander=AUFTRAG.Status.PLANNED
-- Remove mission from airwing because WC will assign it again but maybe to a different wing. -- Remove mission from legion(s) because commander will assign it again but maybe to different legion(s).
for _,_legion in pairs(self.legions) do for _,_legion in pairs(self.legions) do
local legion=_legion --Ops.Legion#LEGION local legion=_legion --Ops.Legion#LEGION
legion:RemoveMission(self) legion:RemoveMission(self)
@ -5440,19 +5557,6 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable)
DCStask.params=param DCStask.params=param
--[[ Task script.
local DCSScript = {}
local altitude = self.hoverAltitude
DCSScript[#DCSScript+1] = 'local group = ...'
DCSScript[#DCSScript+1] = 'local helo = GROUP:Find(group)'
DCSScript[#DCSScript+1] = 'helo:SetSpeed(0.1,true)'
DCSScript[#DCSScript+1] = string.format('helo:SetAltitude(UTILS.FeetToMeters(%d),true,"BARO")',altitude) -- Call the function, e.g. myfunction.(warehouse,mygroup)
-- Create task.
local DCSTask=CONTROLLABLE.TaskWrappedAction(self, CONTROLLABLE.CommandDoScript(self, table.concat(DCSScript)))
--]]
table.insert(DCStasks, DCStask) table.insert(DCStasks, DCStask)
elseif self.type==AUFTRAG.Type.ONGUARD or self.type==AUFTRAG.Type.ARMOREDGUARD then elseif self.type==AUFTRAG.Type.ONGUARD or self.type==AUFTRAG.Type.ARMOREDGUARD then
@ -5473,6 +5577,46 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable)
table.insert(DCStasks, DCStask) table.insert(DCStasks, DCStask)
elseif self.type==AUFTRAG.Type.AIRDEFENSE then
------------------------
-- AIRDEFENSE Mission --
------------------------
local DCStask={}
DCStask.id=AUFTRAG.SpecialTask.AIRDEFENSE
-- We create a "fake" DCS task and pass the parameters to the OPSGROUP.
local param={}
param.zone=self:GetObjective()
DCStask.params=param
table.insert(DCStasks, DCStask)
elseif self.type==AUFTRAG.Type.EWR then
-----------------
-- EWR Mission --
-----------------
local DCStask={}
DCStask.id=AUFTRAG.SpecialTask.EWR
-- We create a "fake" DCS task and pass the parameters to the OPSGROUP.
local param={}
param.zone=self:GetObjective()
DCStask.params=param
table.insert(DCStasks, DCStask)
-- EWR is an enroute task
local Enroutetask=CONTROLLABLE.EnRouteTaskEWR()
table.insert(self.enrouteTasks, Enroutetask)
else else
self:T(self.lid..string.format("ERROR: Unknown mission task!")) self:T(self.lid..string.format("ERROR: Unknown mission task!"))
return nil return nil

View File

@ -153,17 +153,12 @@
-- The default mission types and number of assets can be customized for the two scenarious (zone empty or zone occupied by the enemy). -- The default mission types and number of assets can be customized for the two scenarious (zone empty or zone occupied by the enemy).
-- --
-- In order to do this, you need to create resource lists (one for each scenario) via the @{#CHIEF.CreateResource}() function. -- In order to do this, you need to create resource lists (one for each scenario) via the @{#CHIEF.CreateResource}() function.
-- These list can than be used to replace the default resources employed with -- These lists can than passed as additional parameters to the @{#CHIEF.AddStrategicZone} function.
--
-- * @{CHIEF.SetStrategicZoneResourceOccupied}(*StrateticZone, ResourceOccupied*) for the case that the zone is occupied by the enemy and
-- * @{CHIEF.SetStrategicZoneResourceEmpty}(*StrateticZone, ResourceEmpty*) for the case that the zone is empty.
--
-- The first parameter *StrateticZone* is the strategic zone object that is returned by the @{#CHIEF.AddStrategicZone}() function.
-- The second parameter is the resource list created with the @{#CHIEF.CreateResource}() function.
-- --
-- For example: -- For example:
-- --
-- -- Create a resource list of mission types and required assets for the case that the zone is occupied. -- --- Create a resource list of mission types and required assets for the case that the zone is OCCUPIED.
-- --
-- -- Here, we create an enhanced CAS mission and employ at least on and at most two asset groups. -- -- Here, we create an enhanced CAS mission and employ at least on and at most two asset groups.
-- local ResourceOccupied=myChief:CreateResource(AUFTRAG.Type.CASENHANCED, 1, 2) -- local ResourceOccupied=myChief:CreateResource(AUFTRAG.Type.CASENHANCED, 1, 2)
-- -- We also add ARTY missions with at least one and at most two assets. We additionally require these to be MLRS groups (and not howitzers). -- -- We also add ARTY missions with at least one and at most two assets. We additionally require these to be MLRS groups (and not howitzers).
@ -173,11 +168,8 @@
-- -- Add at least one but at most two BOMBCARPET missions. -- -- Add at least one but at most two BOMBCARPET missions.
-- myChief:AddToResource(ResourceOccupied, AUFTRAG.Type.BOMBCARPET, 1, 2) -- myChief:AddToResource(ResourceOccupied, AUFTRAG.Type.BOMBCARPET, 1, 2)
-- --
-- -- Replace the default list with the customized one. -- --- Create a resource list of mission types and required assets for the case that the zone is EMPTY.
-- myChief:SetStrategicZoneResourceOccupied(myStratZone, ResourceOccupied) -- --
--
--
-- -- Create a resource list of mission types and required assets for the case that the zone is empty.
-- -- Here, we create an ONGUARD mission and employ at least on and at most five infantry assets. -- -- Here, we create an ONGUARD mission and employ at least on and at most five infantry assets.
-- local ResourceEmpty=myChief:CreateResource(AUFTRAG.Type.ONGUARD, 1, 5, GROUP.Attribute.GROUND_INFANTRY) -- local ResourceEmpty=myChief:CreateResource(AUFTRAG.Type.ONGUARD, 1, 5, GROUP.Attribute.GROUND_INFANTRY)
-- -- Additionally, we send up to three tank groups. -- -- Additionally, we send up to three tank groups.
@ -185,10 +177,10 @@
-- -- Finally, we send two groups that patrol the zone. -- -- Finally, we send two groups that patrol the zone.
-- myChief:AddToResource(ResourceEmpty, AUFTRAG.Type.PATROLZONE, 2) -- myChief:AddToResource(ResourceEmpty, AUFTRAG.Type.PATROLZONE, 2)
-- --
-- -- Set this to be the resources employed when the zone is empty. -- -- Add stratetic zone with customized reaction.
-- myChief:SetStrategicZoneResourceEmpty(myStratZone, ResourceEmpty) -- myChief:AddStrategicZone(myOpsZone, nil , 2, ResourceOccupied, ResourceEmpty)
-- --
-- As the location of the enemies is not known, only mission types that don't require and explicit target group are possible. These are -- As the location of the enemies is not known, only mission types that don't require an explicit target group are possible. These are
-- --
-- * `AUFTRAG.Type.CASENHANCED` -- * `AUFTRAG.Type.CASENHANCED`
-- * `AUFTRAG.Type.ARTY` -- * `AUFTRAG.Type.ARTY`
@ -284,7 +276,7 @@ CHIEF.Strategy = {
--- CHIEF class version. --- CHIEF class version.
-- @field #string version -- @field #string version
CHIEF.version="0.3.0" CHIEF.version="0.3.1"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -1006,23 +998,28 @@ function CHIEF:RemoveTarget(Target)
end end
--- Add strategically important zone. --- Add strategically important zone.
-- By default two resource lists are created. One for the case that the zone is empty and the other for the case that the zone is occupied -- By default two resource lists are created. One for the case that the zone is empty and the other for the case that the zone is occupied.
-- Empty: --
-- Occupied:
-- --
-- * `AUFTRAG.Type.ARTY` with Nmin=1, Nmax=2 -- * `AUFTRAG.Type.ARTY` with Nmin=1, Nmax=2
-- * `AUFTRAG.Type.CASENHANCED` with Nmin=1, Nmax=2 -- * `AUFTRAG.Type.CASENHANCED` with Nmin=1, Nmax=2
-- --
-- Occupied: -- Empty:
-- --
-- * `AUFTRAG.Type.ONGUARD` with Nmin=1 and Nmax=3 assets, Attribute=`GROUP.Attribute.GROUND_INFANTRY`. -- * `AUFTRAG.Type.ONGUARD` with Nmin=1 and Nmax=3 assets, Attribute=`GROUP.Attribute.GROUND_INFANTRY`.
-- * `AUFTRAG.Type.ONGURAD` with Nmin=1 and Nmax=1 assets, Attribute=`GROUP.Attribute.GROUND_TANK`. -- * `AUFTRAG.Type.ONGURAD` with Nmin=1 and Nmax=1 assets, Attribute=`GROUP.Attribute.GROUND_TANK`.
-- --
-- Resources can be created with the @{#CHIEF.CreateResource} and @{#CHIEF.AddToResource} functions.
--
-- @param #CHIEF self -- @param #CHIEF self
-- @param Ops.OpsZone#OPSZONE OpsZone OPS zone object. -- @param Ops.OpsZone#OPSZONE OpsZone OPS zone object.
-- @param #number Priority Priority. -- @param #number Priority Priority. Default 50.
-- @param #number Importance Importance. -- @param #number Importance Importance. Default nil.
-- @param #CHIEF.Resource ResourceOccupied (Optional) Resources used then zone is occupied by the enemy.
-- @param #CHIEF.Resource ResourceEmpty (Optional) Resources used then zone is empty.
-- @return #CHIEF.StrategicZone The strategic zone. -- @return #CHIEF.StrategicZone The strategic zone.
function CHIEF:AddStrategicZone(OpsZone, Priority, Importance) function CHIEF:AddStrategicZone(OpsZone, Priority, Importance, ResourceOccupied, ResourceEmpty)
local stratzone={} --#CHIEF.StrategicZone local stratzone={} --#CHIEF.StrategicZone
@ -1038,12 +1035,20 @@ function CHIEF:AddStrategicZone(OpsZone, Priority, Importance)
end end
-- Add resources if zone is occupied. -- Add resources if zone is occupied.
if ResourceOccupied then
stratzone.resourceOccup=UTILS.DeepCopy(ResourceOccupied)
else
stratzone.resourceOccup=self:CreateResource(AUFTRAG.Type.ARTY, 1, 2) stratzone.resourceOccup=self:CreateResource(AUFTRAG.Type.ARTY, 1, 2)
self:AddToResource(stratzone.resourceOccup, AUFTRAG.Type.CASENHANCED, 1, 2) self:AddToResource(stratzone.resourceOccup, AUFTRAG.Type.CASENHANCED, 1, 2)
end
-- Add resources if zone is empty -- Add resources if zone is empty
if ResourceEmpty then
stratzone.resourceEmpty=UTILS.DeepCopy(ResourceEmpty)
else
stratzone.resourceEmpty=self:CreateResource(AUFTRAG.Type.ONGUARD, 1, 3, GROUP.Attribute.GROUND_INFANTRY) stratzone.resourceEmpty=self:CreateResource(AUFTRAG.Type.ONGUARD, 1, 3, GROUP.Attribute.GROUND_INFANTRY)
self:AddToResource(stratzone.resourceEmpty, AUFTRAG.Type.ONGUARD, 1, 1, GROUP.Attribute.GROUND_TANK) self:AddToResource(stratzone.resourceEmpty, AUFTRAG.Type.ONGUARD, 1, 1, GROUP.Attribute.GROUND_TANK)
end
-- Add to table. -- Add to table.
table.insert(self.zonequeue, stratzone) table.insert(self.zonequeue, stratzone)
@ -2442,14 +2447,15 @@ function CHIEF:_GetMissionPerformanceFromTarget(Target)
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.SEAD, 100)) table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.SEAD, 100))
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.GROUNDATTACK, 50)) table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.GROUNDATTACK, 50))
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ARTY, 30))
elseif attribute==GROUP.Attribute.GROUND_EWR then elseif attribute==GROUP.Attribute.GROUND_EWR then
-- EWR -- EWR
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.SEAD, 100)) table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.BAI, 100))
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.BAI, 90))
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.GROUNDATTACK, 50)) table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.GROUNDATTACK, 50))
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ARTY, 30))
elseif attribute==GROUP.Attribute.GROUND_AAA then elseif attribute==GROUP.Attribute.GROUND_AAA then
@ -2484,11 +2490,13 @@ function CHIEF:_GetMissionPerformanceFromTarget(Target)
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.CAS, 100)) table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.CAS, 100))
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.GROUNDATTACK, 50)) table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.GROUNDATTACK, 50))
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ARMORATTACK, 40)) table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ARMORATTACK, 40))
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ARTY, 30))
else else
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.BAI, 100)) table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.BAI, 100))
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.GROUNDATTACK, 50)) table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.GROUNDATTACK, 50))
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ARTY, 30))
end end

View File

@ -26,6 +26,9 @@
-- @field #string aircrafttype Type of the units the cohort is using. -- @field #string aircrafttype Type of the units the cohort is using.
-- @field #number category Group category of the assets: `Group.Category.AIRPLANE`, `Group.Category.HELICOPTER`, `Group.Category.GROUND`, `Group.Category.SHIP`, `Group.Category.TRAIN`. -- @field #number category Group category of the assets: `Group.Category.AIRPLANE`, `Group.Category.HELICOPTER`, `Group.Category.GROUND`, `Group.Category.SHIP`, `Group.Category.TRAIN`.
-- @field Wrapper.Group#GROUP templategroup Template group. -- @field Wrapper.Group#GROUP templategroup Template group.
-- @field #boolean isAir
-- @field #boolean isGround Is ground.
-- @field #boolean isNaval Is naval.
-- @field #table assets Cohort assets. -- @field #table assets Cohort assets.
-- @field #table missiontypes Capabilities (mission types and performances) of the cohort. -- @field #table missiontypes Capabilities (mission types and performances) of the cohort.
-- @field #number maintenancetime Time in seconds needed for maintenance of a returned flight. -- @field #number maintenancetime Time in seconds needed for maintenance of a returned flight.
@ -83,7 +86,7 @@ COHORT = {
--- COHORT class version. --- COHORT class version.
-- @field #string version -- @field #string version
COHORT.version="0.3.2" COHORT.version="0.3.4"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -226,6 +229,74 @@ function COHORT:New(TemplateGroupName, Ngroups, CohortName)
-- @param #COHORT self -- @param #COHORT self
-- @param #number delay Delay in seconds. -- @param #number delay Delay in seconds.
--- Triggers the FSM event "Pause".
-- @function [parent=#COHORT] Pause
-- @param #COHORT self
--- Triggers the FSM event "Pause" after a delay.
-- @function [parent=#COHORT] __Pause
-- @param #COHORT self
-- @param #number delay Delay in seconds.
--- On after "Pause" event.
-- @function [parent=#AUFTRAG] OnAfterPause
-- @param #AUFTRAG self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
--- Triggers the FSM event "Unpause".
-- @function [parent=#COHORT] Unpause
-- @param #COHORT self
--- Triggers the FSM event "Unpause" after a delay.
-- @function [parent=#COHORT] __Unpause
-- @param #COHORT self
-- @param #number delay Delay in seconds.
--- On after "Unpause" event.
-- @function [parent=#AUFTRAG] OnAfterUnpause
-- @param #AUFTRAG self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
--- Triggers the FSM event "Relocate".
-- @function [parent=#COHORT] Relocate
-- @param #COHORT self
--- Triggers the FSM event "Relocate" after a delay.
-- @function [parent=#COHORT] __Relocate
-- @param #COHORT self
-- @param #number delay Delay in seconds.
--- On after "Relocate" event.
-- @function [parent=#AUFTRAG] OnAfterRelocate
-- @param #AUFTRAG self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
--- Triggers the FSM event "Relocated".
-- @function [parent=#COHORT] Relocated
-- @param #COHORT self
--- Triggers the FSM event "Relocated" after a delay.
-- @function [parent=#COHORT] __Relocated
-- @param #COHORT self
-- @param #number delay Delay in seconds.
--- On after "Relocated" event.
-- @function [parent=#AUFTRAG] OnAfterRelocated
-- @param #AUFTRAG self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
return self return self
end end
@ -905,9 +976,9 @@ end
-- @return #table Assets that can do the required mission. -- @return #table Assets that can do the required mission.
-- @return #number Number of payloads still available after recruiting the assets. -- @return #number Number of payloads still available after recruiting the assets.
function COHORT:RecruitAssets(MissionType, Npayloads) function COHORT:RecruitAssets(MissionType, Npayloads)
self:T("RecruitAssets for " .. MissionType .. " with " ..Npayloads)
-- Debug info. -- Debug info.
self:T3(self.lid..string.format("Recruiting asset for Mission type=%s", MissionType)) self:T2(self.lid..string.format("Recruiting asset for Mission type=%s", MissionType))
-- Recruited assets. -- Recruited assets.
local assets={} local assets={}
@ -916,12 +987,21 @@ function COHORT:RecruitAssets(MissionType, Npayloads)
for _,_asset in pairs(self.assets) do for _,_asset in pairs(self.assets) do
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
--self:I("Looking at Asset " .. asset.spawngroupname) -- Get info.
local isRequested=asset.requested
local isReserved=asset.isReserved
local isSpawned=asset.spawned
local isOnMission=self.legion:IsAssetOnMission(asset)
local opsgroup=asset.flightgroup
-- Debug info.
self:T(self.lid..string.format("Asset %s: requested=%s, reserved=%s, spawned=%s, onmission=%s",
asset.spawngroupname, tostring(isRequested), tostring(isReserved), tostring(isSpawned), tostring(isOnMission)))
-- First check that asset is not requested or reserved. This could happen if multiple requests are processed simultaniously. -- First check that asset is not requested or reserved. This could happen if multiple requests are processed simultaniously.
if not (asset.requested or asset.isReserved) then if not (isRequested or isReserved) then
--self:I("Not requested or reserved")
-- Check if asset is currently on a mission (STARTED or QUEUED). -- Check if asset is currently on a mission (STARTED or QUEUED).
if self.legion:IsAssetOnMission(asset) then if self.legion:IsAssetOnMission(asset) then
--- ---
@ -929,13 +1009,32 @@ function COHORT:RecruitAssets(MissionType, Npayloads)
--- ---
-- Check if this asset is currently on a GCICAP mission (STARTED or EXECUTING). -- Check if this asset is currently on a GCICAP mission (STARTED or EXECUTING).
if self.legion:IsAssetOnMission(asset, AUFTRAG.Type.GCICAP) and MissionType==AUFTRAG.Type.INTERCEPT then if MissionType==AUFTRAG.Type.RELOCATECOHORT then
-- Relocation: Take all assets. Mission will be cancelled.
table.insert(assets, asset)
elseif self.legion:IsAssetOnMission(asset, AUFTRAG.Type.GCICAP) and MissionType==AUFTRAG.Type.INTERCEPT then
-- Check if the payload of this asset is compatible with the mission. -- Check if the payload of this asset is compatible with the mission.
-- Note: we do not check the payload as an asset that is on a GCICAP mission should be able to do an INTERCEPT as well! -- Note: we do not check the payload as an asset that is on a GCICAP mission should be able to do an INTERCEPT as well!
self:T(self.lid..string.format("Adding asset on GCICAP mission for an INTERCEPT mission")) self:T(self.lid..string.format("Adding asset on GCICAP mission for an INTERCEPT mission"))
table.insert(assets, asset) table.insert(assets, asset)
elseif self.legion:IsAssetOnMission(asset, AUFTRAG.Type.ONGUARD) and (MissionType==AUFTRAG.Type.ARTY or MissionType==AUFTRAG.Type.GROUNDATTACK) then
if not opsgroup:IsOutOfAmmo() then
self:T(self.lid..string.format("Adding asset on ONGUARD mission for an XXX mission"))
table.insert(assets, asset)
end
elseif self.legion:IsAssetOnMission(asset, AUFTRAG.Type.PATROLZONE) and (MissionType==AUFTRAG.Type.ARTY or MissionType==AUFTRAG.Type.GROUNDATTACK) then
if not opsgroup:IsOutOfAmmo() then
self:T(self.lid..string.format("Adding asset on PATROLZONE mission for an XXX mission"))
table.insert(assets, asset)
end
elseif self.legion:IsAssetOnMission(asset, AUFTRAG.Type.ALERT5) and AUFTRAG.CheckMissionCapability(MissionType, asset.payload.capabilities) then elseif self.legion:IsAssetOnMission(asset, AUFTRAG.Type.ALERT5) and AUFTRAG.CheckMissionCapability(MissionType, asset.payload.capabilities) then
-- Check if the payload of this asset is compatible with the mission. -- Check if the payload of this asset is compatible with the mission.

View File

@ -2,7 +2,7 @@
-- --
-- **Main Features:** -- **Main Features:**
-- --
-- * Manages AIRWINGS, BRIGADEs and FLOTILLAs -- * Manages AIRWINGS, BRIGADEs and FLEETs
-- * Handles missions (AUFTRAG) and finds the best assets for the job -- * Handles missions (AUFTRAG) and finds the best assets for the job
-- --
-- === -- ===
@ -95,7 +95,7 @@
-- --
-- The COMMANDER will -- The COMMANDER will
-- --
-- # OPSGROUP on Mission -- ## OPSGROUP on Mission
-- --
-- Whenever an OPSGROUP (FLIGHTGROUP, ARMYGROUP or NAVYGROUP) is send on a mission, the `OnAfterOpsOnMission()` event is triggered. -- Whenever an OPSGROUP (FLIGHTGROUP, ARMYGROUP or NAVYGROUP) is send on a mission, the `OnAfterOpsOnMission()` event is triggered.
-- Mission designers can hook into the event with the @{#COMMANDER.OnAfterOpsOnMission}() function -- Mission designers can hook into the event with the @{#COMMANDER.OnAfterOpsOnMission}() function
@ -104,7 +104,7 @@
-- -- Your code -- -- Your code
-- end -- end
-- --
-- # Canceling a Mission -- ## Canceling a Mission
-- --
-- A mission can be cancelled with the @{#COMMMANDER.MissionCancel}() function -- A mission can be cancelled with the @{#COMMMANDER.MissionCancel}() function
-- --
@ -136,7 +136,7 @@ COMMANDER = {
--- COMMANDER class version. --- COMMANDER class version.
-- @field #string version -- @field #string version
COMMANDER.version="0.1.1" COMMANDER.version="0.1.2"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -398,7 +398,7 @@ function COMMANDER:AddAirwing(Airwing)
return self return self
end end
--- Add an BRIGADE to the commander. --- Add a BRIGADE to the commander.
-- @param #COMMANDER self -- @param #COMMANDER self
-- @param Ops.Brigade#BRIGADE Brigade The brigade to add. -- @param Ops.Brigade#BRIGADE Brigade The brigade to add.
-- @return #COMMANDER self -- @return #COMMANDER self
@ -410,6 +410,19 @@ function COMMANDER:AddBrigade(Brigade)
return self return self
end end
--- Add a FLEET to the commander.
-- @param #COMMANDER self
-- @param Ops.Fleet#FLEET Fleet The fleet to add.
-- @return #COMMANDER self
function COMMANDER:AddFleet(Fleet)
-- Add legion.
self:AddLegion(Fleet)
return self
end
--- Add a LEGION to the commander. --- Add a LEGION to the commander.
-- @param #COMMANDER self -- @param #COMMANDER self
-- @param Ops.Legion#LEGION Legion The legion to add. -- @param Ops.Legion#LEGION Legion The legion to add.
@ -653,6 +666,83 @@ function COMMANDER:IsMission(Mission)
return false return false
end end
--- Relocate a cohort to another legion.
-- Assets in stock are spawned and routed to the new legion.
-- If assets are spawned, running missions will be cancelled.
-- Cohort assets will not be available until relocation is finished.
-- @param #COMMANDER self
-- @param Ops.Cohort#COHORT Cohort The cohort to be relocated.
-- @param Ops.Legion#LEGION Legion The legion where the cohort is relocated to.
-- @param #number Delay Delay in seconds before relocation takes place. Default `nil`, *i.e.* ASAP.
-- @param #number NcarriersMin Min number of transport carriers in case the troops should be transported. Default `nil` for no transport.
-- @param #number NcarriersMax Max number of transport carriers.
-- @param #table TransportLegions Legion(s) assigned for transportation. Default is all legions of the commander.
-- @return #COMMANDER self
function COMMANDER:RelocateCohort(Cohort, Legion, Delay, NcarriersMin, NcarriersMax, TransportLegions)
if Delay and Delay>0 then
self:ScheduleOnce(Delay, COMMANDER.RelocateCohort, self, Cohort, Legion, 0, NcarriersMin, NcarriersMax, TransportLegions)
else
-- Add cohort to legion.
if Legion:IsCohort(Cohort.name) then
self:E(self.lid..string.format("ERROR: Cohort %s is already part of new legion %s ==> CANNOT Relocate!", Cohort.name, Legion.alias))
return self
else
table.insert(Legion.cohorts, Cohort)
end
-- Old legion.
local LegionOld=Cohort.legion
-- Check that cohort is part of this legion
if not LegionOld:IsCohort(Cohort.name) then
self:E(self.lid..string.format("ERROR: Cohort %s is NOT part of this legion %s ==> CANNOT Relocate!", Cohort.name, self.alias))
return self
end
-- Check that legions are different.
if LegionOld.alias==Legion.alias then
self:E(self.lid..string.format("ERROR: old legion %s is same as new legion %s ==> CANNOT Relocate!", LegionOld.alias, Legion.alias))
return self
end
-- Trigger Relocate event.
Cohort:Relocate()
-- Create a relocation mission.
local mission=AUFTRAG:_NewRELOCATECOHORT(Legion, Cohort)
-- Assign cohort to mission.
mission:AssignCohort(Cohort)
-- All assets required.
mission:SetRequiredAssets(#Cohort.assets)
-- Set transportation.
if NcarriersMin and NcarriersMin>0 then
mission:SetRequiredTransport(Legion.spawnzone, NcarriersMin, NcarriersMax)
end
-- Assign transport legions.
if TransportLegions then
for _,legion in pairs(TransportLegions) do
mission:AssignTransportLegion(legion)
end
else
for _,legion in pairs(self.legions) do
mission:AssignTransportLegion(legion)
end
end
-- Add mission.
self:AddMission(mission)
end
return self
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status -- Start & Status
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -974,7 +1064,7 @@ function COMMANDER:onafterMissionCancel(From, Event, To, Mission)
end end
--- On after "TransportAssign" event. Transport is added to a LEGION mission queue. --- On after "TransportAssign" event. Transport is added to a LEGION transport queue.
-- @param #COMMANDER self -- @param #COMMANDER self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
@ -1215,7 +1305,8 @@ function COMMANDER:RecruitAssetsForMission(Mission)
local Payloads=Mission.payloads local Payloads=Mission.payloads
-- Recruite assets. -- Recruite assets.
local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, Mission.type, Mission.alert5MissionType, NreqMin, NreqMax, TargetVec2, Payloads, Mission.engageRange, Mission.refuelSystem) local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, Mission.type, Mission.alert5MissionType, NreqMin, NreqMax, TargetVec2, Payloads,
Mission.engageRange, Mission.refuelSystem, nil, nil, nil, Mission.attributes, Mission.properties, {Mission.engageWeaponType})
return recruited, assets, legions return recruited, assets, legions
end end

View File

@ -867,7 +867,7 @@ function FLIGHTGROUP:Status()
local ammo=self:GetAmmoTot().Total local ammo=self:GetAmmoTot().Total
-- Detected units. -- Detected units.
local ndetected=self.detectionOn and tostring(self.detectedunits:Count()) or "OFF" local ndetected=self.detectionOn and tostring(self.detectedunits:Count()) or "Off"
-- Get cargo weight. -- Get cargo weight.
local cargo=0 local cargo=0

View File

@ -430,13 +430,16 @@ end
-- Cohort assets will not be available until relocation is finished. -- Cohort assets will not be available until relocation is finished.
-- @param #LEGION self -- @param #LEGION self
-- @param Ops.Cohort#COHORT Cohort The cohort to be relocated. -- @param Ops.Cohort#COHORT Cohort The cohort to be relocated.
-- @param Ops.Legion#LEGION Legion. -- @param Ops.Legion#LEGION Legion The legion where the cohort is relocated to.
-- @param #number Delay Delay in seconds before relocation takes place. Default 0 sec. -- @param #number Delay Delay in seconds before relocation takes place. Default `nil`, *i.e.* ASAP.
-- @param #number NcarriersMin Min number of transport carriers in case the troops should be transported. Default `nil` for no transport.
-- @param #number NcarriersMax Max number of transport carriers.
-- @param #table TransportLegions Legion(s) assigned for transportation. Default is that transport assets can only be recruited from this legion.
-- @return #LEGION self -- @return #LEGION self
function LEGION:RelocateCohort(Cohort, Legion, Delay) function LEGION:RelocateCohort(Cohort, Legion, Delay, NcarriersMin, NcarriersMax, TransportLegions)
if Delay and Delay>0 then if Delay and Delay>0 then
self:ScheduleOnce(Delay, LEGION.RelocateCohort, self, Cohort, Legion, 0) self:ScheduleOnce(Delay, LEGION.RelocateCohort, self, Cohort, Legion, 0, NcarriersMin, NcarriersMax, TransportLegions)
else else
-- Add cohort to legion. -- Add cohort to legion.
@ -465,6 +468,9 @@ function LEGION:RelocateCohort(Cohort, Legion, Delay)
-- Create a relocation mission. -- Create a relocation mission.
local mission=AUFTRAG:_NewRELOCATECOHORT(Legion, Cohort) local mission=AUFTRAG:_NewRELOCATECOHORT(Legion, Cohort)
if false then
--- Disabled for now.
-- Add assets to mission. -- Add assets to mission.
mission:_AddAssets(Cohort.assets) mission:_AddAssets(Cohort.assets)
@ -474,8 +480,33 @@ function LEGION:RelocateCohort(Cohort, Legion, Delay)
-- Assign mission to this legion. -- Assign mission to this legion.
self:MissionAssign(mission, {self}) self:MissionAssign(mission, {self})
else
-- Assign cohort to mission.
mission:AssignCohort(Cohort)
-- All assets required.
mission:SetRequiredAssets(#Cohort.assets)
-- Set transportation.
if NcarriersMin and NcarriersMin>0 then
mission:SetRequiredTransport(Legion.spawnzone, NcarriersMin, NcarriersMax)
end end
-- Assign transport legions.
if TransportLegions then
for _,legion in pairs(TransportLegions) do
mission:AssignTransportLegion(legion)
end
end
-- Add mission.
self:AddMission(mission)
end
end
return self
end end
--- Get cohort by name. --- Get cohort by name.
@ -822,27 +853,29 @@ function LEGION:onafterMissionRequest(From, Event, To, Mission)
local currM=asset.flightgroup:GetMissionCurrent() local currM=asset.flightgroup:GetMissionCurrent()
if currM then if currM then
-- Cancel?
local cancel=false local cancel=false
-- Pause?
local pause=false
-- Check if mission is INTERCEPT and asset is currently on GCI mission. If so, GCI is paused. -- Check if mission is INTERCEPT and asset is currently on GCI mission. If so, GCI is paused.
if currM.type==AUFTRAG.Type.GCICAP and Mission.type==AUFTRAG.Type.INTERCEPT then if currM.type==AUFTRAG.Type.GCICAP and Mission.type==AUFTRAG.Type.INTERCEPT then
self:T(self.lid..string.format("Pausing %s mission %s to send flight on intercept mission %s", currM.type, currM.name, Mission.name)) pause=true
asset.flightgroup:PauseMission() elseif (currM.type==AUFTRAG.Type.ONGUARD or currM.type==AUFTRAG.Type.PATROLZONE) and (Mission.type==AUFTRAG.Type.ARTY or Mission.type==AUFTRAG.Type.GROUNDATTACK) then
pause=true
end end
-- Cancel current ALERT5 mission -- Cancel current ALERT5 mission.
if currM.type==AUFTRAG.Type.ALERT5 then if currM.type==AUFTRAG.Type.ALERT5 then
cancel=true cancel=true
end end
-- Cancel the current mission. -- Cancel current mission for relcation.
if currM.type==AUFTRAG.Type.ONGUARD or currM.type==AUFTRAG.Type.ARMOREDGUARD then
cancel=true
end
if Mission.type==AUFTRAG.Type.RELOCATECOHORT then if Mission.type==AUFTRAG.Type.RELOCATECOHORT then
cancel=true cancel=true
-- Get request ID.
local requestID=currM.requestID[self.alias] local requestID=currM.requestID[self.alias]
-- Get request. -- Get request.
@ -854,17 +887,25 @@ function LEGION:onafterMissionRequest(From, Event, To, Mission)
else else
self:E(self.lid.."ERROR: no request for spawned asset!") self:E(self.lid.."ERROR: no request for spawned asset!")
end end
end end
-- Cancel mission.
if cancel then if cancel then
self:T(self.lid..string.format("Cancel current mission %s [%s] to send group on mission %s [%s]", currM.name, currM.type, Mission.name, Mission.type))
asset.flightgroup:MissionCancel(currM) asset.flightgroup:MissionCancel(currM)
elseif pause then
self:T(self.lid..string.format("Pausing current mission %s [%s] to send group on mission %s [%s]", currM.name, currM.type, Mission.name, Mission.type))
asset.flightgroup:PauseMission()
end end
-- Not reserved any more.
asset.isReserved=false
end end
-- Trigger event. -- Trigger event.
self:__OpsOnMission(5, asset.flightgroup, Mission) self:__OpsOnMission(2, asset.flightgroup, Mission)
else else
self:E(self.lid.."ERROR: OPSGROUP for asset does NOT exist but it seems to be SPAWNED (asset.spawned=true)!") self:E(self.lid.."ERROR: OPSGROUP for asset does NOT exist but it seems to be SPAWNED (asset.spawned=true)!")
@ -893,6 +934,13 @@ function LEGION:onafterMissionRequest(From, Event, To, Mission)
-- Set asset to requested! Important so that new requests do not use this asset! -- Set asset to requested! Important so that new requests do not use this asset!
asset.requested=true asset.requested=true
-- Spawned asset are not requested.
if asset.spawned then
asset.requested=false
end
-- Not reserved and more.
asset.isReserved=false asset.isReserved=false
-- Set mission task so that the group is spawned with the right one. -- Set mission task so that the group is spawned with the right one.
@ -1344,7 +1392,6 @@ function LEGION:onafterAssetSpawned(From, Event, To, group, asset, request)
local Tacan=cohort:FetchTacan() local Tacan=cohort:FetchTacan()
if Tacan then if Tacan then
asset.tacan=Tacan asset.tacan=Tacan
--flightgroup:SetDefaultTACAN(Tacan,Morse,UnitName,Band,OffSwitch)
flightgroup:SwitchTACAN(Tacan, Morse, UnitName, Band) flightgroup:SwitchTACAN(Tacan, Morse, UnitName, Band)
end end
@ -1401,6 +1448,11 @@ function LEGION:onafterAssetSpawned(From, Event, To, group, asset, request)
-- Add mission to flightgroup queue. If mission has an OPSTRANSPORT attached, all added OPSGROUPS are added as CARGO for a transport. -- Add mission to flightgroup queue. If mission has an OPSTRANSPORT attached, all added OPSGROUPS are added as CARGO for a transport.
flightgroup:AddMission(mission) flightgroup:AddMission(mission)
-- RTZ on out of ammo.
if self:IsBrigade() or self:IsFleet() then
flightgroup:SetReturnOnOutOfAmmo()
end
-- Trigger event. -- Trigger event.
self:__OpsOnMission(5, flightgroup, mission) self:__OpsOnMission(5, flightgroup, mission)
@ -1670,25 +1722,6 @@ function LEGION:IsAssetOnMission(asset, MissionTypes)
end end
-- Alternative: run over all missions and compare to mission assets.
--[[
for _,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG
if mission:IsNotOver() then
for _,_asset in pairs(mission.assets) do
local sqasset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
if sqasset.uid==asset.uid then
return true
end
end
end
end
]]
return false return false
end end
@ -1907,7 +1940,6 @@ function LEGION:CountAssetsOnMission(MissionTypes, Cohort)
end end
end end
--env.info(string.format("FF N=%d Np=%d, Nq=%d", Np+Nq, Np, Nq))
return Np+Nq, Np, Nq return Np+Nq, Np, Nq
end end
@ -2047,7 +2079,7 @@ function LEGION:RecruitAssetsForMission(Mission)
-- Recuit assets. -- Recuit assets.
local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, Mission.type, Mission.alert5MissionType, NreqMin, NreqMax, TargetVec2, Payloads, local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, Mission.type, Mission.alert5MissionType, NreqMin, NreqMax, TargetVec2, Payloads,
Mission.engageRange, Mission.refuelSystem, nil, nil, nil, nil, nil, {Mission.engageWeaponType}) Mission.engageRange, Mission.refuelSystem, nil, nil, nil, Mission.attributes, Mission.properties, {Mission.engageWeaponType})
return recruited, assets, legions return recruited, assets, legions
end end
@ -2226,6 +2258,9 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
local cohort=_cohort --Ops.Cohort#COHORT local cohort=_cohort --Ops.Cohort#COHORT
if WeaponTypes and #WeaponTypes>0 then if WeaponTypes and #WeaponTypes>0 then
for _,WeaponType in pairs(WeaponTypes) do for _,WeaponType in pairs(WeaponTypes) do
if WeaponType==ENUMS.WeaponFlag.Auto then
return true
else
for _,_weaponData in pairs(cohort.weaponData or {}) do for _,_weaponData in pairs(cohort.weaponData or {}) do
local weaponData=_weaponData --Ops.OpsGroup#OPSGROUP.WeaponData local weaponData=_weaponData --Ops.OpsGroup#OPSGROUP.WeaponData
if weaponData.BitType==WeaponType then if weaponData.BitType==WeaponType then
@ -2233,6 +2268,7 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
end end
end end
end end
end
return false return false
else else
return true return true
@ -2263,8 +2299,6 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
end end
end end
--env.info(string.format("Cohort=%s: RefuelSystem=%s, TankerSystem=%s ==> Refuel=%s", cohort.name, tostring(RefuelSystem), tostring(cohort.tankerSystem), tostring(Refuel)))
-- Is capable of the mission type? -- Is capable of the mission type?
local Capable=AUFTRAG.CheckMissionCapability({MissionTypeRecruit}, cohort.missiontypes) local Capable=AUFTRAG.CheckMissionCapability({MissionTypeRecruit}, cohort.missiontypes)
@ -2283,12 +2317,19 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
-- Right weapon type. -- Right weapon type.
local RightWeapon=CheckWeapon(cohort) local RightWeapon=CheckWeapon(cohort)
-- Cohort ready to execute mission.
local Ready=cohort:IsOnDuty()
if MissionTypeRecruit==AUFTRAG.Type.RELOCATECOHORT then
Ready=cohort:IsRelocating()
Capable=true
end
-- Debug info. -- Debug info.
cohort:T2(cohort.lid..string.format("State=%s: Capable=%s, InRange=%s, Refuel=%s, CanCarry=%s, Category=%s, Attribute=%s, Property=%s, Weapon=%s", cohort:T2(cohort.lid..string.format("State=%s: Capable=%s, InRange=%s, Refuel=%s, CanCarry=%s, Category=%s, Attribute=%s, Property=%s, Weapon=%s",
cohort:GetState(), tostring(Capable), tostring(InRange), tostring(Refuel), tostring(CanCarry), tostring(RightCategory), tostring(RightAttribute), tostring(RightProperty), tostring(RightWeapon))) cohort:GetState(), tostring(Capable), tostring(InRange), tostring(Refuel), tostring(CanCarry), tostring(RightCategory), tostring(RightAttribute), tostring(RightProperty), tostring(RightWeapon)))
-- Check OnDuty, capable, in range and refueling type (if TANKER). -- Check OnDuty, capable, in range and refueling type (if TANKER).
if cohort:IsOnDuty() and Capable and InRange and Refuel and CanCarry and RightCategory and RightAttribute and RightProperty and RightWeapon then if Ready and Capable and InRange and Refuel and CanCarry and RightCategory and RightAttribute and RightProperty and RightWeapon then
-- Recruit assets from cohort. -- Recruit assets from cohort.
local assets, npayloads=cohort:RecruitAssets(MissionTypeRecruit, 999) local assets, npayloads=cohort:RecruitAssets(MissionTypeRecruit, 999)
@ -2702,9 +2743,10 @@ function LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, Inclu
-- Reduce score for legions that are futher away. -- Reduce score for legions that are futher away.
score=score-distance score=score-distance
-- Intercepts need to be carried out quickly. We prefer spawned assets. -- Check for spawned assets.
if asset.spawned and asset.flightgroup and asset.flightgroup:IsAlive() then if asset.spawned and asset.flightgroup and asset.flightgroup:IsAlive() then
-- Get current mission.
local currmission=asset.flightgroup:GetMissionCurrent() local currmission=asset.flightgroup:GetMissionCurrent()
if currmission then if currmission then
@ -2712,10 +2754,13 @@ function LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, Inclu
if currmission.type==AUFTRAG.Type.ALERT5 and currmission.alert5MissionType==MissionType then if currmission.type==AUFTRAG.Type.ALERT5 and currmission.alert5MissionType==MissionType then
-- Prefer assets that are on ALERT5 for this mission type. -- Prefer assets that are on ALERT5 for this mission type.
score=score+25 score=score+25
elseif currmission==AUFTRAG.Type.GCICAP and MissionType==AUFTRAG.Type.INTERCEPT then elseif currmission.type==AUFTRAG.Type.GCICAP and MissionType==AUFTRAG.Type.INTERCEPT then
-- Prefer assets that are on GCICAP to perform INTERCEPTS -- Prefer assets that are on GCICAP to perform INTERCEPTS
score=score+25 score=score+25
elseif (currmission.type==AUFTRAG.Type.ONGUARD or currmission.type==AUFTRAG.Type.PATROLZONE) and (MissionType==AUFTRAG.Type.ARTY or MissionType==AUFTRAG.Type.GROUNDATTACK) then
score=score+25
end end
end end
if MissionType==AUFTRAG.Type.OPSTRANSPORT or MissionType==AUFTRAG.Type.AMMOSUPPLY or MissionType==AUFTRAG.Type.AWACS or MissionType==AUFTRAG.Type.FUELSUPPLY or MissionType==AUFTRAG.Type.TANKER then if MissionType==AUFTRAG.Type.OPSTRANSPORT or MissionType==AUFTRAG.Type.AMMOSUPPLY or MissionType==AUFTRAG.Type.AWACS or MissionType==AUFTRAG.Type.FUELSUPPLY or MissionType==AUFTRAG.Type.TANKER then
@ -2743,6 +2788,10 @@ function LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, Inclu
-- Fuel amount? -- Fuel amount?
-- Range of assets? -- Range of assets?
if asset.legion and asset.legion.verbose>=2 then
asset.legion:I(asset.legion.lid..string.format("Asset %s [spawned=%s] score=%d", asset.spawngroupname, tostring(asset.spawned), score))
end
return score return score
end end

View File

@ -828,7 +828,7 @@ function NAVYGROUP:Status(From, Event, To)
local ammo=self:GetAmmoTot().Total local ammo=self:GetAmmoTot().Total
-- Detected units. -- Detected units.
local ndetected=self.detectionOn and tostring(self.detectedunits:Count()) or "OFF" local ndetected=self.detectionOn and tostring(self.detectedunits:Count()) or "Off"
-- Get cargo weight. -- Get cargo weight.
local cargo=0 local cargo=0

View File

@ -18,6 +18,7 @@
-- @field #string lid Class id string for output to DCS log file. -- @field #string lid Class id string for output to DCS log file.
-- @field #string groupname Name of the group. -- @field #string groupname Name of the group.
-- @field Wrapper.Group#GROUP group Group object. -- @field Wrapper.Group#GROUP group Group object.
-- @field DCS#Group dcsgroup The DCS group object.
-- @field DCS#Controller controller The DCS controller of the group. -- @field DCS#Controller controller The DCS controller of the group.
-- @field DCS#Template template Template table of the group. -- @field DCS#Template template Template table of the group.
-- @field #table elements Table of elements, i.e. units of the group. -- @field #table elements Table of elements, i.e. units of the group.
@ -57,6 +58,7 @@
-- @field #number speedMax Max speed in km/h. -- @field #number speedMax Max speed in km/h.
-- @field #number speedCruise Cruising speed in km/h. -- @field #number speedCruise Cruising speed in km/h.
-- @field #number speedWp Speed to the next waypoint in m/s. -- @field #number speedWp Speed to the next waypoint in m/s.
-- @field #boolean isMobile If `true`, group is mobile (speed > 1 m/s)
-- @field #boolean passedfinalwp Group has passed the final waypoint. -- @field #boolean passedfinalwp Group has passed the final waypoint.
-- @field #number wpcounter Running number counting waypoints. -- @field #number wpcounter Running number counting waypoints.
-- @field Core.Set#SET_ZONE checkzones Set of zones. -- @field Core.Set#SET_ZONE checkzones Set of zones.
@ -200,6 +202,7 @@ OPSGROUP = {
-- @field Wrapper.Unit#UNIT unit The UNIT object. -- @field Wrapper.Unit#UNIT unit The UNIT object.
-- @field Wrapper.Group#GROUP group The GROUP object. -- @field Wrapper.Group#GROUP group The GROUP object.
-- @field DCS#Unit DCSunit The DCS unit object. -- @field DCS#Unit DCSunit The DCS unit object.
-- @field DCS#Controller controller The DCS controller of the unit.
-- @field #boolean ai If true, element is AI. -- @field #boolean ai If true, element is AI.
-- @field #string skill Skill level. -- @field #string skill Skill level.
-- --
@ -466,7 +469,7 @@ OPSGROUP.CargoStatus={
--- OpsGroup version. --- OpsGroup version.
-- @field #string version -- @field #string version
OPSGROUP.version="0.7.7" OPSGROUP.version="0.7.8"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
@ -1045,6 +1048,108 @@ function OPSGROUP:SetDetection(Switch)
return self return self
end end
--- Get DCS group object.
-- @param #OPSGROUP self
-- @return DCS#Group DCS group object.
function OPSGROUP:GetDCSObject()
return self.dcsgroup
end
--- Set detection on or off.
-- If detection is on, detected targets of the group will be evaluated and FSM events triggered.
-- @param #OPSGROUP self
-- @param Wrapper.Positionable#POSITIONABLE TargetObject The target object.
-- @param #boolean KnowType Make type known.
-- @param #boolean KnowDist Make distance known.
-- @param #number Delay Delay in seconds before the target is known.
-- @return #OPSGROUP self
function OPSGROUP:KnowTarget(TargetObject, KnowType, KnowDist, Delay)
if Delay and Delay>0 then
-- Delayed call.
self:ScheduleOnce(Delay, OPSGROUP.KnowTarget, self, TargetObject, KnowType, KnowDist, 0)
else
if TargetObject:IsInstanceOf("GROUP") then
TargetObject=TargetObject:GetUnit(1)
elseif TargetObject:IsInstanceOf("OPSGROUP") then
TargetObject=TargetObject.group:GetUnit(1)
end
-- Get the DCS object.
local object=TargetObject:GetDCSObject()
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
if element.controller then
element.controller:knowTarget(object, true, true)
--self:T(self.lid..string.format("Element %s should now know target %s", element.name, TargetObject:GetName()))
end
end
-- Debug info.
self:T(self.lid..string.format("We should now know target %s", TargetObject:GetName()))
end
return self
end
--- Check if target is detected.
-- @param #OPSGROUP self
-- @param Wrapper.Positionable#POSITIONABLE TargetObject The target object.
-- @return #boolean If `true`, target was detected.
function OPSGROUP:IsTargetDetected(TargetObject)
local objects={}
if TargetObject:IsInstanceOf("GROUP") then
for _,unit in pairs(TargetObject:GetUnits()) do
table.insert(objects, unit:GetDCSObject())
end
elseif TargetObject:IsInstanceOf("OPSGROUP") then
for _,unit in pairs(TargetObject.group:GetUnits()) do
table.insert(objects, unit:GetDCSObject())
end
elseif TargetObject:IsInstanceOf("UNIT") or TargetObject:IsInstanceOf("STATIC") then
table.insert(objects, TargetObject:GetDCSObject())
end
for _,object in pairs(objects or {}) do
-- Check group controller.
local detected, visible, lastTime, type, distance, lastPos, lastVel = self.controller:isTargetDetected(object, 1, 2, 4, 8, 16, 32)
--env.info(self.lid..string.format("Detected target %s: %s", TargetObject:GetName(), tostring(detected)))
if detected then
return true
end
-- Check all elements.
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
if element.controller then
-- Check.
local detected, visible, lastTime, type, distance, lastPos, lastVel=
element.controller:isTargetDetected(object, 1, 2, 4, 8, 16, 32)
--env.info(self.lid..string.format("Element %s detected target %s: %s", element.name, TargetObject:GetName(), tostring(detected)))
if detected then
return true
end
end
end
end
return false
end
--- Set LASER parameters. --- Set LASER parameters.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #number Code Laser code. Default 1688. -- @param #number Code Laser code. Default 1688.
@ -1285,6 +1390,23 @@ function OPSGROUP:SetRearmOnOutOfAmmo()
return self return self
end end
--- Set that group is retreating once it runs out of ammo.
-- @param #OPSGROUP self
-- @return #OPSGROUP self
function OPSGROUP:SetRetreatOnOutOfAmmo()
self.retreatOnOutOfAmmo=true
return self
end
--- Set that group is return to legion once it runs out of ammo.
-- @param #OPSGROUP self
-- @return #OPSGROUP self
function OPSGROUP:SetReturnOnOutOfAmmo()
self.rtzOnOutOfAmmo=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.
@ -3634,6 +3756,29 @@ function OPSGROUP:onbeforeTaskExecute(From, Event, To, Task)
end end
if Mission and Mission.opstransport then
local delivered=Mission.opstransport:IsCargoDelivered(self.groupname)
if not delivered then
local dt=30
-- Debug info.
self:T(self.lid..string.format("Mission %s task execute suspended for %d seconds because we were not delivered", Mission.name, dt))
-- Reexecute task.
self:__TaskExecute(-dt, Task)
if (self:IsArmygroup() or self:IsNavygroup()) and self:IsCruising() then
self:FullStop()
end
-- Deny transition.
return false
end
end
return true return true
end end
@ -3817,6 +3962,21 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
-- FLIGHTGROUP not implemented (intended!) for this AUFTRAG type. -- FLIGHTGROUP not implemented (intended!) for this AUFTRAG type.
end end
elseif Task.dcstask.id==AUFTRAG.SpecialTask.AIRDEFENSE or Task.dcstask.id==AUFTRAG.SpecialTask.EWR then
---
-- Task "AIRDEFENSE" or "EWR" Mission.
---
-- Just stay put.
--TODO: Change ALARM STATE
if self:IsArmygroup() or self:IsNavygroup() then
self:FullStop()
else
-- FLIGHTGROUP not implemented (intended!) for this AUFTRAG type.
end
elseif Task.dcstask.id==AUFTRAG.SpecialTask.GROUNDATTACK or Task.dcstask.id==AUFTRAG.SpecialTask.ARMORATTACK then elseif Task.dcstask.id==AUFTRAG.SpecialTask.GROUNDATTACK or Task.dcstask.id==AUFTRAG.SpecialTask.ARMORATTACK then
--- ---
@ -3903,20 +4063,67 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
-- If task is scheduled (not waypoint) set task. -- If task is scheduled (not waypoint) set task.
if Task.type==OPSGROUP.TaskType.SCHEDULED or Task.ismission then if Task.type==OPSGROUP.TaskType.SCHEDULED or Task.ismission then
local DCSTask=nil --UTILS.DeepCopy(Task.dcstask) -- DCS task.
local DCSTask=nil
-- BARRAGE is special! -- BARRAGE is special!
if Task.dcstask.id==AUFTRAG.SpecialTask.BARRAGE then if Task.dcstask.id==AUFTRAG.SpecialTask.BARRAGE then
---
-- BARRAGE
-- Current vec2.
local vec2=self:GetVec2() local vec2=self:GetVec2()
-- Task parameters.
local param=Task.dcstask.params local param=Task.dcstask.params
-- Set heading and altitude.
local heading=param.heading or math.random(1, 360) local heading=param.heading or math.random(1, 360)
local Altitude=param.altitude or 500 local Altitude=param.altitude or 500
local Alpha=param.angle or math.random(45, 85) local Alpha=param.angle or math.random(45, 85)
local distance=Altitude/math.tan(math.rad(Alpha)) local distance=Altitude/math.tan(math.rad(Alpha))
local tvec2=UTILS.Vec2Translate(vec2, distance, heading) local tvec2=UTILS.Vec2Translate(vec2, distance, heading)
-- Debug info.
self:T(self.lid..string.format("Barrage: Shots=%s, Altitude=%d m, Angle=%d°, heading=%03d°, distance=%d m", tostring(param.shots), Altitude, Alpha, heading, distance)) self:T(self.lid..string.format("Barrage: Shots=%s, Altitude=%d m, Angle=%d°, heading=%03d°, distance=%d m", tostring(param.shots), Altitude, Alpha, heading, distance))
-- Set fire at point task.
DCSTask=CONTROLLABLE.TaskFireAtPoint(nil, tvec2, param.radius, param.shots, param.weaponType, Altitude) DCSTask=CONTROLLABLE.TaskFireAtPoint(nil, tvec2, param.radius, param.shots, param.weaponType, Altitude)
elseif Task.ismission and Task.dcstask.id=='FireAtPoint' then
-- Copy DCS task.
DCSTask=UTILS.DeepCopy(Task.dcstask)
-- Get current ammo.
local ammo=self:GetAmmoTot()
-- Number of ammo avail.
local nAmmo=ammo.Total
if DCSTask.params.weaponType then
--TODO: use weapon type infor, e.g. for cruise missiles
end
--TODO: Update target location while we're at it anyway.
--TODO: Adjust mission result evaluation time? E.g. cruise missiles can fly a long time depending on target distance.
-- Number of shots to be fired.
local nShots=DCSTask.params.expendQty or 1
-- Debug info.
self:T(self.lid..string.format("Fire at point with nshots=%d of %d", nShots, nAmmo))
-- Only fire number of avail shots.
nShots=math.min(nShots, nAmmo)
-- Set quantity of task.
DCSTask.params.expendQty=nShots
else else
---
-- Take DCS task
---
DCSTask=Task.dcstask DCSTask=Task.dcstask
end end
@ -4126,12 +4333,12 @@ function OPSGROUP:onafterTaskDone(From, Event, To, Task)
else else
if Task.description=="Engage_Target" then if Task.description=="Engage_Target" then
self:T(self.lid.."Taske DONE Engage_Target ==> Cruise") self:T(self.lid.."Task DONE Engage_Target ==> Cruise")
self:Disengage() self:Disengage()
end end
if Task.description==AUFTRAG.SpecialTask.ONGUARD or Task.description==AUFTRAG.SpecialTask.ARMOREDGUARD then if Task.description==AUFTRAG.SpecialTask.ONGUARD or Task.description==AUFTRAG.SpecialTask.ARMOREDGUARD then
self:T(self.lid.."Taske DONE OnGuard ==> Cruise") self:T(self.lid.."Task DONE OnGuard ==> Cruise")
self:Cruise() self:Cruise()
end end
@ -4173,7 +4380,6 @@ function OPSGROUP:AddMission(Mission)
table.insert(self.missionqueue, Mission) table.insert(self.missionqueue, Mission)
-- ad infinitum? -- ad infinitum?
self.adinfinitum = Mission.DCStask.params.adinfinitum and Mission.DCStask.params.adinfinitum or false self.adinfinitum = Mission.DCStask.params.adinfinitum and Mission.DCStask.params.adinfinitum or false
-- Info text. -- Info text.
@ -4335,7 +4541,7 @@ function OPSGROUP:_GetNextMission()
for _,_opsgroup in pairs(cargos) do for _,_opsgroup in pairs(cargos) do
local opscargo=_opsgroup --Ops.OpsGroup#OPSGROUP local opscargo=_opsgroup --Ops.OpsGroup#OPSGROUP
if opscargo.groupname==self.groupname then if opscargo.groupname==self.groupname then
isTransport=false --isTransport=false
break break
end end
end end
@ -4346,8 +4552,15 @@ function OPSGROUP:_GetNextMission()
local isReadyToGo=(mission:IsReadyToGo() or self.legion) local isReadyToGo=(mission:IsReadyToGo() or self.legion)
local isImportant=(mission.importance==nil or mission.importance<=vip) local isImportant=(mission.importance==nil or mission.importance<=vip)
-- Everything on go?
local go=isScheduled and isReadyToGo and isImportant and isTransport and isEscort
-- Debug info.
self:T3(self.lid..string.format("Mission %s [%s]: Go=%s [Scheduled=%s, Ready=%s, Important=%s, Transport=%s, Escort=%s]", mission:GetName(), mission:GetType(), tostring(go),
tostring(isScheduled), tostring(isReadyToGo), tostring(isImportant), tostring(isTransport), tostring(isEscort)))
-- Check necessary conditions. -- Check necessary conditions.
if isScheduled and isReadyToGo and isImportant and isTransport and isEscort then if go then
return mission return mission
end end
@ -4483,7 +4696,7 @@ function OPSGROUP:onafterMissionStart(From, Event, To, Mission)
Mission:__Started(3) Mission:__Started(3)
-- Route group to mission zone. -- Route group to mission zone.
if self.speedMax>3.6 then if self.speedMax>3.6 or true then
self:RouteToMission(Mission, 3) self:RouteToMission(Mission, 3)
@ -4492,10 +4705,12 @@ function OPSGROUP:onafterMissionStart(From, Event, To, Mission)
-- IMMOBILE Group -- IMMOBILE Group
--- ---
--env.info("FF Immobile GROUP") env.info(self.lid.."FF Immobile GROUP")
-- Add waypoint task. UpdateRoute is called inside. -- Add waypoint task. UpdateRoute is called inside.
local Clock=Mission.Tpush and UTILS.SecondsToClock(Mission.Tpush) or 5 local Clock=Mission.Tpush and UTILS.SecondsToClock(Mission.Tpush) or 5
-- Add mission task.
local Task=self:AddTask(Mission.DCStask, Clock, Mission.name, Mission.prio, Mission.duration) local Task=self:AddTask(Mission.DCStask, Clock, Mission.name, Mission.prio, Mission.duration)
Task.ismission=true Task.ismission=true
@ -4555,6 +4770,8 @@ function OPSGROUP:onafterPauseMission(From, Event, To)
-- Cancelling the mission is actually cancelling the current task. -- Cancelling the mission is actually cancelling the current task.
self:TaskCancel(Task) self:TaskCancel(Task)
self:_RemoveMissionWaypoints(Mission)
-- Set mission to pause so we can unpause it later. -- Set mission to pause so we can unpause it later.
self.missionpaused=Mission self.missionpaused=Mission
@ -4603,8 +4820,14 @@ 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 or Mission.type==AUFTRAG.Type.ONGUARD or Mission.type==AUFTRAG.Type.ARMOREDGUARD then if Mission.type==AUFTRAG.Type.ALERT5 or
Mission.type==AUFTRAG.Type.ONGUARD or
Mission.type==AUFTRAG.Type.ARMOREDGUARD or
Mission.type==AUFTRAG.Type.AIRDEFENSE or
Mission.type==AUFTRAG.Type.EWR then
self:MissionDone(Mission) self:MissionDone(Mission)
return return
end end
@ -4705,10 +4928,14 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission)
if Mission.optionAlarm then if Mission.optionAlarm then
self:SwitchAlarmstate() self:SwitchAlarmstate()
end end
-- Alarm state to default. -- EPLRS to default.
if Mission.optionEPLRS then if Mission.optionEPLRS then
self:SwitchEPLRS() self:SwitchEPLRS()
end end
-- Emission to default.
if Mission.optionEmission then
self:SwitchEmission()
end
-- Formation to default. -- Formation to default.
if Mission.optionFormation then if Mission.optionFormation then
self:SwitchFormation() self:SwitchFormation()
@ -4822,6 +5049,9 @@ function OPSGROUP:RouteToMission(mission, delay)
-- Ingress waypoint coordinate where the mission is executed. -- Ingress waypoint coordinate where the mission is executed.
local waypointcoord=nil --Core.Point#COORDINATE local waypointcoord=nil --Core.Point#COORDINATE
-- Target zone.
local targetzone=nil --Core.Zone#ZONE
-- Random radius of 1000 meters. -- Random radius of 1000 meters.
local randomradius=mission.missionWaypointRadius or 1000 local randomradius=mission.missionWaypointRadius or 1000
@ -4833,26 +5063,80 @@ function OPSGROUP:RouteToMission(mission, delay)
surfacetypes={land.SurfaceType.WATER, land.SurfaceType.SHALLOW_WATER} surfacetypes={land.SurfaceType.WATER, land.SurfaceType.SHALLOW_WATER}
end end
-- Get ingress waypoint. -- Get ingress waypoint.
if mission.type==AUFTRAG.Type.PATROLZONE or mission.type==AUFTRAG.Type.BARRAGE or mission.type==AUFTRAG.Type.AMMOSUPPLY or mission.type.FUELSUPPLY then if mission.opstransport and not mission.opstransport:IsCargoDelivered(self.groupname) then
local zone=mission.engageTarget:GetObject() --Core.Zone#ZONE
waypointcoord=zone:GetRandomCoordinate(nil , nil, surfacetypes) --env.info(self.lid.."FF mission waypoint in embark zone")
-- Get transport zone combo.
local tzc=mission.opstransport:GetTZCofCargo(self.groupname)
local pickupzone=tzc.PickupZone
if self:IsInZone(pickupzone) then
-- We are already in the pickup zone.
self:PauseMission()
self:FullStop()
return
else
-- Get a random coordinate inside the pickup zone.
waypointcoord=pickupzone:GetRandomCoordinate()
--waypointcoord:MarkToAll(self.lid.." embark here")
end
elseif mission.type==AUFTRAG.Type.PATROLZONE or
mission.type==AUFTRAG.Type.BARRAGE or
mission.type==AUFTRAG.Type.AMMOSUPPLY or
mission.type==AUFTRAG.Type.FUELSUPPLY or
mission.type==AUFTRAG.Type.AIRDEFENSE or
mission.type==AUFTRAG.Type.EWR then
---
-- Missions with ZONE as target
---
-- Get the zone.
targetzone=mission.engageTarget:GetObject() --Core.Zone#ZONE
-- Random coordinate.
waypointcoord=targetzone:GetRandomCoordinate(nil , nil, surfacetypes)
elseif mission.type==AUFTRAG.Type.ONGUARD or mission.type==AUFTRAG.Type.ARMOREDGUARD then elseif mission.type==AUFTRAG.Type.ONGUARD or mission.type==AUFTRAG.Type.ARMOREDGUARD then
---
-- Guard
---
-- Mission waypoint
waypointcoord=mission:GetMissionWaypointCoord(self.group, nil, surfacetypes) waypointcoord=mission:GetMissionWaypointCoord(self.group, nil, surfacetypes)
elseif mission.type==AUFTRAG.Type.HOVER then
---
-- Hover
---
local zone=mission.engageTarget:GetObject() --Core.Zone#ZONE
waypointcoord=zone:GetCoordinate()
elseif mission.type==AUFTRAG.Type.RELOCATECOHORT then elseif mission.type==AUFTRAG.Type.RELOCATECOHORT then
---
-- Relocation
---
-- Roughly go to the new legion.
local ToCoordinate=mission.DCStask.params.legion:GetCoordinate() local ToCoordinate=mission.DCStask.params.legion:GetCoordinate()
if self.isFlightgroup then if self.isFlightgroup then
waypointcoord=self:GetCoordinate():GetIntermediateCoordinate(ToCoordinate, 0.2):SetAltitude(self.altitudeCruise) waypointcoord=self:GetCoordinate():GetIntermediateCoordinate(ToCoordinate, 0.2):SetAltitude(self.altitudeCruise)
else else
waypointcoord=self:GetCoordinate():GetIntermediateCoordinate(ToCoordinate, 0.05) waypointcoord=self:GetCoordinate():GetIntermediateCoordinate(ToCoordinate, 0.05)
end end
else
waypointcoord=mission:GetMissionWaypointCoord(self.group, randomradius, surfacetypes)
end
if mission.type==AUFTRAG.Type.HOVER then else
local zone=mission.engageTarget:GetObject() --Core.Zone#ZONE ---
waypointcoord=zone:GetCoordinate() -- Default case
---
waypointcoord=mission:GetMissionWaypointCoord(self.group, randomradius, surfacetypes)
end end
-- Add enroute tasks. -- Add enroute tasks.
@ -4963,6 +5247,7 @@ function OPSGROUP:RouteToMission(mission, delay)
end end
-- Add waypoint. -- Add waypoint.
local waypoint=nil --#OPSGROUP.Waypoint local waypoint=nil --#OPSGROUP.Waypoint
if self:IsFlightgroup() then if self:IsFlightgroup() then
@ -5001,11 +5286,39 @@ function OPSGROUP:RouteToMission(mission, delay)
mission:SetGroupEgressWaypointUID(self, Ewaypoint.uid) mission:SetGroupEgressWaypointUID(self, Ewaypoint.uid)
end end
---
-- Mission Specific Settings
---
self:_SetMissionOptions(mission)
-- Get current pos.
local coord=self:GetCoordinate()
-- Distance to waypoint coordinate.
local d=coord:Get2DDistance(waypointcoord)
-- Debug info.
self:T(self.lid..string.format("FF distance to ingress waypoint=%.1f m", d))
-- Check if we are already where we want to be.
if targetzone and self:IsInZone(targetzone) then
self:T(self.lid.."Already in mission zone ==> TaskExecute()")
self:TaskExecute(waypointtask)
return
elseif d<25 then
self:T(self.lid.."Already within 25 meters of mission waypoint ==> TaskExecute()")
self:TaskExecute(waypointtask)
return
end
-- Check if group is mobile. Note that some immobile units report a speed of 1 m/s = 3.6 km/h.
if self.speedMax<=3.6 or mission.teleport then
-- Teleport to waypoint coordinate. Mission will not be paused.
self:Teleport(waypointcoord, nil, true)
-- Execute task in one second.
self:__TaskExecute(-1, waypointtask)
else
-- Give cruise command/update route.
if self:IsArmygroup() then if self:IsArmygroup() then
self:Cruise(SpeedToMission) self:Cruise(SpeedToMission)
elseif self:IsNavygroup() then elseif self:IsNavygroup() then
@ -5015,6 +5328,13 @@ function OPSGROUP:RouteToMission(mission, delay)
end end
end end
---
-- Mission Specific Settings
---
self:_SetMissionOptions(mission)
end
end end
--- Set mission specific options for ROE, Alarm state, etc. --- Set mission specific options for ROE, Alarm state, etc.
@ -5038,6 +5358,10 @@ function OPSGROUP:_SetMissionOptions(mission)
if mission.optionEPLRS then if mission.optionEPLRS then
self:SwitchEPLRS(mission.optionEPLRS) self:SwitchEPLRS(mission.optionEPLRS)
end end
-- Emission
if mission.optionEPLRS then
self:SwitchEmission(mission.optionEmission)
end
-- Formation -- Formation
if mission.optionFormation and self:IsFlightgroup() then if mission.optionFormation and self:IsFlightgroup() then
self:SwitchFormation(mission.optionFormation) self:SwitchFormation(mission.optionFormation)
@ -5441,6 +5765,13 @@ function OPSGROUP:_SetWaypointTasks(Waypoint)
-- Check if there is mission task -- Check if there is mission task
if missiontask then if missiontask then
self:T(self.lid.."Executing mission task") self:T(self.lid.."Executing mission task")
local mission=self:GetMissionByTaskID(missiontask.id)
if mission then
if mission.opstransport and not mission.opstransport:IsCargoDelivered(self.groupname) then
self:PauseMission()
return
end
end
self:TaskExecute(missiontask) self:TaskExecute(missiontask)
return 1 return 1
end end
@ -5497,8 +5828,6 @@ end
-- @param #number Speed (Optional) Speed to waypoint in knots. -- @param #number Speed (Optional) Speed to waypoint in knots.
function OPSGROUP:onafterGotoWaypoint(From, Event, To, UID, Speed) function OPSGROUP:onafterGotoWaypoint(From, Event, To, UID, Speed)
--env.info("FF goto waypoint uid="..tostring(UID))
local n=self:GetWaypointIndex(UID) local n=self:GetWaypointIndex(UID)
if n then if n then
@ -6263,11 +6592,12 @@ end
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param Core.Point#COORDINATE Coordinate Coordinate where the group is teleported to. -- @param Core.Point#COORDINATE Coordinate Coordinate where the group is teleported to.
-- @param #number Delay Delay in seconds before respawn happens. Default 0. -- @param #number Delay Delay in seconds before respawn happens. Default 0.
-- @param #boolean NoPauseMission If `true`, dont pause a running mission.
-- @return #OPSGROUP self -- @return #OPSGROUP self
function OPSGROUP:Teleport(Coordinate, Delay) function OPSGROUP:Teleport(Coordinate, Delay, NoPauseMission)
if Delay and Delay>0 then if Delay and Delay>0 then
self:ScheduleOnce(Delay, OPSGROUP.Teleport, self, Coordinate) self:ScheduleOnce(Delay, OPSGROUP.Teleport, self, Coordinate, 0, NoPauseMission)
else else
-- Debug message. -- Debug message.
@ -6275,8 +6605,8 @@ function OPSGROUP:Teleport(Coordinate, Delay)
--Coordinate:MarkToAll("Teleport "..self.groupname) --Coordinate:MarkToAll("Teleport "..self.groupname)
-- Check if we have a mission running. -- Check if we have a mission running.
if self:IsOnMission() then if self:IsOnMission() and not NoPauseMission then
self:T(self.lid.."Pausing current mission") self:T(self.lid.."Pausing current mission for telport")
self:PauseMission() self:PauseMission()
end end
@ -6286,6 +6616,14 @@ function OPSGROUP:Teleport(Coordinate, Delay)
-- Set late activation of template to current state. -- Set late activation of template to current state.
Template.lateActivation=self:IsLateActivated() Template.lateActivation=self:IsLateActivated()
-- Not uncontrolled.
Template.uncontrolled=false
-- Set waypoint in air for flighgroups.
if self:IsFlightgroup() then
Template.route.points[1]=Coordinate:WaypointAir("BARO", COORDINATE.WaypointType.TurningPoint, COORDINATE.WaypointAction.TurningPoint, 300, true, nil, nil, "Spawnpoint")
end
-- Template units. -- Template units.
local units=Template.units local units=Template.units
@ -7841,16 +8179,35 @@ function OPSGROUP:onafterLoading(From, Event, To)
for _,_cargo in pairs(self.cargoTZC.Cargos) do for _,_cargo in pairs(self.cargoTZC.Cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
-- Check if this group can carry the cargo.
local canCargo=self:CanCargo(cargo.opsgroup)
-- Check if this group is currently acting as carrier.
local isCarrier=cargo.opsgroup:IsPickingup() or cargo.opsgroup:IsLoading() or cargo.opsgroup:IsTransporting() or cargo.opsgroup:IsUnloading() local isCarrier=cargo.opsgroup:IsPickingup() or cargo.opsgroup:IsLoading() or cargo.opsgroup:IsTransporting() or cargo.opsgroup:IsUnloading()
local isOnMission=cargo.opsgroup:IsOnMission() -- Check if cargo is not already cargo.
local isNotCargo=cargo.opsgroup:IsNotCargo(true)
-- Check if cargo is holding.
local isHolding=cargo.opsgroup:IsHolding()
-- Check if cargo is in embark/pickup zone. -- Check if cargo is in embark/pickup zone.
-- Added InUtero here, if embark zone is moving (ship) and cargo has been spawned late activated and its position is not updated. Not sure if that breaks something else! -- Added InUtero here, if embark zone is moving (ship) and cargo has been spawned late activated and its position is not updated. Not sure if that breaks something else!
local inzone=cargo.opsgroup:IsInZone(self.cargoTZC.EmbarkZone) --or cargo.opsgroup:IsInUtero() local inZone=cargo.opsgroup:IsInZone(self.cargoTZC.EmbarkZone) --or cargo.opsgroup:IsInUtero()
-- Check if cargo is currently on a mission.
local isOnMission=cargo.opsgroup:IsOnMission()
-- Check if current mission is using this ops transport.
if isOnMission then
local mission=cargo.opsgroup:GetMissionCurrent()
if mission and mission.opstransport and mission.opstransport.uid==self.cargoTransport.uid then
isOnMission=not cargo.opsgroup:IsHolding()
end
end
-- TODO: Need a better :IsBusy() function or :IsReadyForMission() :IsReadyForBoarding() :IsReadyForTransport() -- TODO: Need a better :IsBusy() function or :IsReadyForMission() :IsReadyForBoarding() :IsReadyForTransport()
if self:CanCargo(cargo.opsgroup) and inzone and cargo.opsgroup:IsNotCargo(true) and (not (cargo.delivered or cargo.opsgroup:IsDead() or isCarrier or isOnMission)) then if canCargo and inZone and isNotCargo and isHolding and (not (cargo.delivered or cargo.opsgroup:IsDead() or isCarrier or isOnMission)) then
table.insert(cargos, cargo) table.insert(cargos, cargo)
end end
end end
@ -8482,6 +8839,10 @@ function OPSGROUP:onafterUnloaded(From, Event, To, OpsGroupCargo)
OpsGroupCargo:Returned() OpsGroupCargo:Returned()
end end
if OpsGroupCargo.missionpaused then
OpsGroupCargo:UnpauseMission()
end
end end
@ -9037,6 +9398,11 @@ function OPSGROUP:_CheckGroupDone(delay)
return return
end end
if self:IsBoarding() then
self:T(self.lid.."Boarding! Group NOT done...")
return
end
-- Group is waiting. We deny all updates. -- Group is waiting. We deny all updates.
if self:IsWaiting() then if self:IsWaiting() then
-- If group is waiting, we assume that is the way it is meant to be. -- If group is waiting, we assume that is the way it is meant to be.
@ -11740,6 +12106,7 @@ function OPSGROUP:_AddElementByName(unitname)
element.gid=element.DCSunit:getNumber() element.gid=element.DCSunit:getNumber()
element.uid=element.DCSunit:getID() element.uid=element.DCSunit:getID()
--element.group=unit:GetGroup() --element.group=unit:GetGroup()
element.controller=element.DCSunit:getController()
element.opsgroup=self element.opsgroup=self
-- Skill etc. -- Skill etc.

View File

@ -656,58 +656,6 @@ function OPSTRANSPORT:GetEmbarkZone(TransportZoneCombo)
return TransportZoneCombo.EmbarkZone return TransportZoneCombo.EmbarkZone
end end
--[[
--- Set transfer carrier(s). These are carrier groups, where the cargo is directly loaded into when disembarked.
-- @param #OPSTRANSPORT self
-- @param Core.Set#SET_GROUP Carriers Carrier set. Can also be passed as a #GROUP, #OPSGROUP or #SET_OPSGROUP object.
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:SetEmbarkCarriers(Carriers, TransportZoneCombo)
-- Debug info.
self:T(self.lid.."Setting embark carriers!")
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
if Carriers:IsInstanceOf("GROUP") or Carriers:IsInstanceOf("OPSGROUP") then
local carrier=self:_GetOpsGroupFromObject(Carriers)
if carrier then
table.insert(TransportZoneCombo.EmbarkCarriers, carrier)
end
elseif Carriers:IsInstanceOf("SET_GROUP") or Carriers:IsInstanceOf("SET_OPSGROUP") then
for _,object in pairs(Carriers:GetSet()) do
local carrier=self:_GetOpsGroupFromObject(object)
if carrier then
table.insert(TransportZoneCombo.EmbarkCarriers, carrier)
end
end
else
self:E(self.lid.."ERROR: Carriers must be a GROUP, OPSGROUP, SET_GROUP or SET_OPSGROUP object!")
end
return self
end
--- Get embark transfer carrier(s). These are carrier groups, where the cargo is directly loaded into when disembarked.
-- @param #OPSTRANSPORT self
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
-- @return #table Table of carrier OPS groups.
function OPSTRANSPORT:GetEmbarkCarriers(TransportZoneCombo)
-- Use default TZC if no transport zone combo is provided.
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
return TransportZoneCombo.EmbarkCarriers
end
]]
--- Set disembark zone. --- Set disembark zone.
-- @param #OPSTRANSPORT self -- @param #OPSTRANSPORT self
-- @param Core.Zone#ZONE DisembarkZone Zone where the troops are disembarked. -- @param Core.Zone#ZONE DisembarkZone Zone where the troops are disembarked.
@ -1366,6 +1314,25 @@ function OPSTRANSPORT:AddAssetCargo(Asset, TransportZoneCombo)
return self return self
end end
--- Get transport zone combo of cargo group.
-- @param #OPSTRANSPORT self
-- @param #string GroupName Group name of cargo.
-- @return #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
function OPSTRANSPORT:GetTZCofCargo(GroupName)
for _,_tzc in pairs(self.tzCombos) do
local tzc=_tzc --#OPSTRANSPORT.TransportZoneCombo
for _,_cargo in pairs(tzc.Cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if cargo.opsgroup:GetName()==GroupName then
return tzc
end
end
end
return nil
end
--- Add LEGION to the transport. --- Add LEGION to the transport.
-- @param #OPSTRANSPORT self -- @param #OPSTRANSPORT self
-- @param Ops.Legion#LEGION Legion The legion. -- @param Ops.Legion#LEGION Legion The legion.
@ -1638,6 +1605,24 @@ function OPSTRANSPORT:onafterStatusUpdate(From, Event, To)
end end
end end
--- Check if a cargo group was delivered.
-- @param #OPSTRANSPORT self
-- @param #string GroupName Name of the group.
-- @return #boolean If `true`, cargo was delivered.
function OPSTRANSPORT:IsCargoDelivered(GroupName)
for _,_cargo in pairs(self:GetCargos()) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
if cargo.opsgroup:GetName()==GroupName then
return cargo.delivered
end
end
return nil
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Event Functions -- FSM Event Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -428,6 +428,21 @@ function OPSZONE:GetCoordinate()
return coordinate return coordinate
end end
--- Returns a random coordinate in the zone.
-- @param #OPSZONE self
-- @param #number inner (Optional) Minimal distance from the center of the zone in meters. Default is 0 m.
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone in meters. Default is the radius of the zone.
-- @param #table surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type!
-- @return Core.Point#COORDINATE The random coordinate.
function OPSZONE:GetRandomCoordinate(inner, outer, surfacetypes)
local zone=self:GetZone()
local coord=zone:GetRandomCoordinate(inner, outer, surfacetypes)
return coord
end
--- Get zone name. --- Get zone name.
-- @param #OPSZONE self -- @param #OPSZONE self
-- @return #string Name of the zone. -- @return #string Name of the zone.

View File

@ -31,7 +31,7 @@
-- @field #string tankergroupname Name of the late activated tanker template group. -- @field #string tankergroupname Name of the late activated tanker template group.
-- @field Wrapper.Group#GROUP tanker Tanker group. -- @field Wrapper.Group#GROUP tanker Tanker group.
-- @field Wrapper.Airbase#AIRBASE airbase The home airbase object of the tanker. Normally the aircraft carrier. -- @field Wrapper.Airbase#AIRBASE airbase The home airbase object of the tanker. Normally the aircraft carrier.
-- @field Core.Radio#BEACON beacon Tanker TACAN beacon. -- @field Core.Beacon#BEACON beacon Tanker TACAN beacon.
-- @field #number TACANchannel TACAN channel. Default 1. -- @field #number TACANchannel TACAN channel. Default 1.
-- @field #string TACANmode TACAN mode, i.e. "X" or "Y". Default "Y". Use only "Y" for AA TACAN stations! -- @field #string TACANmode TACAN mode, i.e. "X" or "Y". Default "Y". Use only "Y" for AA TACAN stations!
-- @field #string TACANmorse TACAN morse code. Three letters identifying the TACAN station. Default "TKR". -- @field #string TACANmorse TACAN morse code. Three letters identifying the TACAN station. Default "TKR".
@ -784,10 +784,11 @@ end
-- @param #RECOVERYTANKER self -- @param #RECOVERYTANKER self
-- @param #number channel TACAN channel. Default 1. -- @param #number channel TACAN channel. Default 1.
-- @param #string morse TACAN morse code identifier. Three letters. Default "TKR". -- @param #string morse TACAN morse code identifier. Three letters. Default "TKR".
-- @param #string mode TACAN mode, which can be either "Y" (default) or "X".
-- @return #RECOVERYTANKER self -- @return #RECOVERYTANKER self
function RECOVERYTANKER:SetTACAN(channel, morse) function RECOVERYTANKER:SetTACAN(channel, morse, mode)
self.TACANchannel=channel or 1 self.TACANchannel=channel or 1
self.TACANmode="Y" self.TACANmode=mode or "Y"
self.TACANmorse=morse or "TKR" self.TACANmorse=morse or "TKR"
self.TACANon=true self.TACANon=true
return self return self
@ -1625,7 +1626,6 @@ function RECOVERYTANKER:_ActivateTACAN(delay)
if delay and delay>0 then if delay and delay>0 then
-- Schedule TACAN activation. -- Schedule TACAN activation.
--SCHEDULER:New(nil, self._ActivateTACAN, {self}, delay)
self:ScheduleOnce(delay, RECOVERYTANKER._ActivateTACAN, self) self:ScheduleOnce(delay, RECOVERYTANKER._ActivateTACAN, self)
else else

View File

@ -529,6 +529,8 @@ function GROUP:HasAttribute(attribute, all)
-- Get all units of the group. -- Get all units of the group.
local _units=self:GetUnits() local _units=self:GetUnits()
if _units then
local _allhave=true local _allhave=true
local _onehas=false local _onehas=false
@ -549,6 +551,10 @@ function GROUP:HasAttribute(attribute, all)
else else
return _onehas return _onehas
end end
end
return nil
end end
--- Returns the maximum speed of the group. --- Returns the maximum speed of the group.
@ -563,16 +569,19 @@ function GROUP:GetSpeedMax()
local Units=self:GetUnits() local Units=self:GetUnits()
local speedmax=0 local speedmax=nil
for _,unit in pairs(Units) do for _,unit in pairs(Units) do
local unit=unit --Wrapper.Unit#UNIT local unit=unit --Wrapper.Unit#UNIT
local speed=unit:GetSpeedMax() local speed=unit:GetSpeedMax()
if speedmax==0 then
speedmax=speed if speedmax==nil or speed<speedmax then
elseif speed<speedmax then
speedmax=speed speedmax=speed
end end
--env.info(string.format("FF unit %s: speed=%.1f, speedmax=%.1f", unit:GetName(), speed, speedmax))
end end
return speedmax return speedmax