mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
OPS
**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:
parent
2d02f4f962
commit
ed0a3a22ab
@ -170,6 +170,8 @@ end
|
||||
function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
|
||||
self:T({channel=Channel, mode=Mode, callsign=Message, bearing=Bearing, duration=Duration})
|
||||
|
||||
Mode=Mode or "Y"
|
||||
|
||||
-- Get frequency.
|
||||
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.
|
||||
local AA=self.Positionable:IsAir()
|
||||
|
||||
|
||||
if AA then
|
||||
System=5 --NOTE: 5 is how you cat the correct tanker behaviour! --BEACON.System.TACAN_TANKER
|
||||
-- Check if "Y" mode is selected for aircraft.
|
||||
if Mode~="Y" 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})
|
||||
if Mode=="X" then
|
||||
--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
|
||||
|
||||
@ -267,13 +274,12 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||
IsValid = false
|
||||
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
|
||||
-- or 14 (TACAN_AA_MODE_Y) if it does not
|
||||
-- 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
|
||||
local System
|
||||
if Bearing then
|
||||
System = 5
|
||||
System = BEACON.System.TACAN_TANKER_Y
|
||||
else
|
||||
System = 14
|
||||
System = BEACON.System.TACAN_AA_MODE_Y
|
||||
end
|
||||
|
||||
if IsValid then -- Starts the BEACON
|
||||
@ -281,10 +287,13 @@ function BEACON:AATACAN(TACANChannel, Message, Bearing, BeaconDuration)
|
||||
self.Positionable:SetCommand({
|
||||
id = "ActivateBeacon",
|
||||
params = {
|
||||
type = 4,
|
||||
type = BEACON.Type.TACAN,
|
||||
system = System,
|
||||
callsign = Message,
|
||||
AA = true,
|
||||
frequency = Frequency,
|
||||
bearing = Bearing,
|
||||
modeChannel = "Y",
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@ -60,6 +60,7 @@
|
||||
-- @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 #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
|
||||
|
||||
|
||||
@ -111,6 +112,7 @@ ZONE_BASE = {
|
||||
DrawID=nil,
|
||||
Color={},
|
||||
ZoneID=nil,
|
||||
Sureface=nil,
|
||||
}
|
||||
|
||||
|
||||
@ -335,15 +337,22 @@ end
|
||||
-- @param #ZONE_BASE self
|
||||
-- @return #nil The bounding square.
|
||||
function ZONE_BASE:GetBoundingSquare()
|
||||
--return { x1 = 0, y1 = 0, x2 = 0, y2 = 0 }
|
||||
return nil
|
||||
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.
|
||||
-- @param #ZONE_BASE self
|
||||
function ZONE_BASE:BoundZone()
|
||||
self:F2()
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -1281,8 +1290,8 @@ end
|
||||
|
||||
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 3D location within the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0.
|
||||
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||
-- @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 ZONE_RADIUS:GetRandomCoordinate(inner, outer, surfacetypes)
|
||||
|
||||
@ -299,6 +299,9 @@ function AIRWING:AddSquadron(Squadron)
|
||||
elseif Squadron.attribute==GROUP.Attribute.AIR_TANKER then
|
||||
self:NewPayload(Squadron.templategroup, -1, AUFTRAG.Type.TANKER)
|
||||
end
|
||||
|
||||
-- Relocate mission.
|
||||
self:NewPayload(Squadron.templategroup, -1, AUFTRAG.Type.RELOCATECOHORT, 0)
|
||||
|
||||
-- Set airwing to squadron.
|
||||
Squadron:SetAirwing(self)
|
||||
|
||||
@ -33,7 +33,6 @@
|
||||
-- @field #boolean formationPerma Formation that is used permanently and overrules waypoint formations.
|
||||
-- @field #boolean isMobile If true, group is mobile.
|
||||
-- @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.
|
||||
-- @extends Ops.OpsGroup#OPSGROUP
|
||||
|
||||
@ -710,7 +709,7 @@ function ARMYGROUP:Status()
|
||||
local ammo=self:GetAmmoTot().Total
|
||||
|
||||
-- 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.
|
||||
local cargo=0
|
||||
|
||||
@ -71,6 +71,8 @@
|
||||
-- @field Core.Point#COORDINATE orbitRaceTrack Race-track orbit coordinate.
|
||||
--
|
||||
-- @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 #table engageTargetTypes Table of target types that are engaged in the engagement zone.
|
||||
@ -162,6 +164,7 @@
|
||||
-- @field #number optionRTBammo RTB on out-of-ammo.
|
||||
-- @field #number optionRTBfuel RTB on out-of-fuel.
|
||||
-- @field #number optionECM ECM.
|
||||
-- @field #boolean optionEmission Emission is on or off.
|
||||
--
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
@ -312,7 +315,16 @@
|
||||
--
|
||||
-- ## 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
|
||||
@ -393,6 +405,8 @@ _AUFTRAGSNR=0
|
||||
-- @field #string GROUNDATTACK Ground attack.
|
||||
-- @field #string CARGOTRANSPORT Cargo transport.
|
||||
-- @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.
|
||||
AUFTRAG.Type={
|
||||
ANTISHIP="Anti Ship",
|
||||
@ -430,8 +444,10 @@ AUFTRAG.Type={
|
||||
HOVER="Hover",
|
||||
GROUNDATTACK="Ground Attack",
|
||||
CARGOTRANSPORT="Cargo Transport",
|
||||
RELOCATECOHORT="Relocate Cohort",
|
||||
AIRDEFENSE="Air Defence",
|
||||
EWR="Early Warning Radar",
|
||||
NOTHING="Nothing",
|
||||
RELOCATECOHORT="Relocate Cohort",
|
||||
}
|
||||
|
||||
--- Special task description.
|
||||
@ -448,8 +464,9 @@ AUFTRAG.Type={
|
||||
-- @field #string HOVER Hover.
|
||||
-- @field #string GROUNDATTACK Ground attack.
|
||||
-- @field #string FERRY Ferry mission.
|
||||
-- @field #string NOTHING Nothing.
|
||||
-- @field #string RELOCATECOHORT Relocate cohort.
|
||||
-- @field #string AIRDEFENSE Air defense.
|
||||
-- @field #string NOTHING Nothing.
|
||||
AUFTRAG.SpecialTask={
|
||||
FORMATION="Formation",
|
||||
PATROLZONE="PatrolZone",
|
||||
@ -464,8 +481,10 @@ AUFTRAG.SpecialTask={
|
||||
HOVER="Hover",
|
||||
GROUNDATTACK="Ground Attack",
|
||||
FERRY="Ferry",
|
||||
RELOCATECOHORT="Relocate Cohort",
|
||||
AIRDEFENSE="Air Defense",
|
||||
EWR="Early Warning Radar",
|
||||
NOTHING="Nothing",
|
||||
RELOCATECOHORT="Relocate Cohort",
|
||||
}
|
||||
|
||||
--- Mission status.
|
||||
@ -586,7 +605,7 @@ AUFTRAG.Category={
|
||||
|
||||
--- AUFTRAG class version.
|
||||
-- @field #string version
|
||||
AUFTRAG.version="0.9.3"
|
||||
AUFTRAG.version="0.9.4"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -647,7 +666,6 @@ function AUFTRAG:New(Type)
|
||||
self:SetPriority()
|
||||
self:SetTime()
|
||||
self:SetRequiredAssets()
|
||||
--self:SetRequiredCarriers()
|
||||
self.engageAsGroup=true
|
||||
self.dTevaluate=5
|
||||
|
||||
@ -1341,7 +1359,7 @@ function AUFTRAG:NewBAI(Target, Altitude)
|
||||
mission:_TargetFromObject(Target)
|
||||
|
||||
-- DCS Task options:
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.AnyAG
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
||||
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
||||
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 5000)
|
||||
|
||||
@ -1362,7 +1380,7 @@ end
|
||||
--- **[AIR]** Create a SEAD mission.
|
||||
-- @param #AUFTRAG self
|
||||
-- @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
|
||||
function AUFTRAG:NewSEAD(Target, Altitude)
|
||||
|
||||
@ -1371,9 +1389,9 @@ function AUFTRAG:NewSEAD(Target, Altitude)
|
||||
mission:_TargetFromObject(Target)
|
||||
|
||||
-- DCS Task options:
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.AnyAG --ENUMS.WeaponFlag.Cannons
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
||||
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
||||
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 8000)
|
||||
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
|
||||
|
||||
-- Mission options:
|
||||
mission.missionTask=ENUMS.MissionTask.SEAD
|
||||
@ -1402,7 +1420,7 @@ function AUFTRAG:NewSTRIKE(Target, Altitude)
|
||||
mission:_TargetFromObject(Target)
|
||||
|
||||
-- DCS Task options:
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.AnyAG
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
||||
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
||||
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 2000)
|
||||
|
||||
@ -1432,7 +1450,7 @@ function AUFTRAG:NewBOMBING(Target, Altitude)
|
||||
mission:_TargetFromObject(Target)
|
||||
|
||||
-- DCS task options:
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.AnyBomb
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
||||
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
||||
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
|
||||
|
||||
@ -1470,7 +1488,7 @@ function AUFTRAG:NewBOMBRUNWAY(Airdrome, Altitude)
|
||||
mission:_TargetFromObject(Airdrome)
|
||||
|
||||
-- DCS task options:
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.AnyBomb
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
||||
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
||||
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
|
||||
|
||||
@ -1505,7 +1523,7 @@ function AUFTRAG:NewBOMBCARPET(Target, Altitude, CarpetLength)
|
||||
mission:_TargetFromObject(Target)
|
||||
|
||||
-- DCS task options:
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.AnyBomb
|
||||
mission.engageWeaponType=ENUMS.WeaponFlag.Auto
|
||||
mission.engageWeaponExpend=AI.Task.WeaponExpend.ALL
|
||||
mission.engageAltitude=UTILS.FeetToMeters(Altitude or 25000)
|
||||
mission.engageCarpetLength=CarpetLength or 500
|
||||
@ -1996,10 +2014,55 @@ function AUFTRAG:NewONGUARD(Coordinate)
|
||||
return mission
|
||||
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 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
|
||||
function AUFTRAG:_NewRELOCATECOHORT(Legion, Cohort)
|
||||
|
||||
@ -2312,6 +2375,14 @@ function AUFTRAG:SetDuration(Duration)
|
||||
return self
|
||||
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.
|
||||
-- @param #AUFTRAG self
|
||||
@ -2637,6 +2708,29 @@ function AUFTRAG:AddTransportCarriers(Carriers)
|
||||
|
||||
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.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number NcarriersMin Number of carriers *at least* required. Default 1.
|
||||
@ -2806,6 +2900,21 @@ function AUFTRAG:SetEPLRS(OnOffSwitch)
|
||||
return self
|
||||
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.
|
||||
-- @param #AUFTRAG self
|
||||
-- @param #number Formation Formation.
|
||||
@ -3765,12 +3874,19 @@ function AUFTRAG:RemoveLegion(Legion)
|
||||
-- Loop over legions
|
||||
for i=#self.legions,1,-1 do
|
||||
local legion=self.legions[i] --Ops.Legion#LEGION
|
||||
|
||||
if legion.alias==Legion.alias then
|
||||
|
||||
-- Debug info.
|
||||
self:T(self.lid..string.format("Removing legion %s", Legion.alias))
|
||||
table.remove(self.legions, i)
|
||||
|
||||
-- Set legion status to nil.
|
||||
self.statusLegion[Legion.alias]=nil
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
-- Set status for chief.
|
||||
self.statusChief=AUFTRAG.Status.PLANNED
|
||||
|
||||
-- Remove mission from wingcommander because Chief will assign it again.
|
||||
if self.commander then
|
||||
self.commander:RemoveMission(self)
|
||||
self.statusCommander=AUFTRAG.Status.PLANNED
|
||||
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
|
||||
local legion=_legion --Ops.Legion#LEGION
|
||||
legion:RemoveMission(self)
|
||||
@ -4408,9 +4524,10 @@ function AUFTRAG:onafterRepeat(From, Event, To)
|
||||
|
||||
elseif self.commander then
|
||||
|
||||
-- Set status for commander.
|
||||
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
|
||||
local legion=_legion --Ops.Legion#LEGION
|
||||
legion:RemoveMission(self)
|
||||
@ -5440,19 +5557,6 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
self:T(self.lid..string.format("ERROR: Unknown mission task!"))
|
||||
return nil
|
||||
|
||||
@ -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).
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- * @{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.
|
||||
-- These lists can than passed as additional parameters to the @{#CHIEF.AddStrategicZone} function.
|
||||
--
|
||||
-- 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.
|
||||
-- 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).
|
||||
@ -173,11 +168,8 @@
|
||||
-- -- Add at least one but at most two BOMBCARPET missions.
|
||||
-- myChief:AddToResource(ResourceOccupied, AUFTRAG.Type.BOMBCARPET, 1, 2)
|
||||
--
|
||||
-- -- Replace the default list with the customized one.
|
||||
-- myChief:SetStrategicZoneResourceOccupied(myStratZone, ResourceOccupied)
|
||||
--
|
||||
--
|
||||
-- -- Create a resource list of mission types and required assets for the case that the zone is empty.
|
||||
-- --- 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.
|
||||
-- local ResourceEmpty=myChief:CreateResource(AUFTRAG.Type.ONGUARD, 1, 5, GROUP.Attribute.GROUND_INFANTRY)
|
||||
-- -- Additionally, we send up to three tank groups.
|
||||
@ -185,10 +177,10 @@
|
||||
-- -- Finally, we send two groups that patrol the zone.
|
||||
-- myChief:AddToResource(ResourceEmpty, AUFTRAG.Type.PATROLZONE, 2)
|
||||
--
|
||||
-- -- Set this to be the resources employed when the zone is empty.
|
||||
-- myChief:SetStrategicZoneResourceEmpty(myStratZone, ResourceEmpty)
|
||||
-- -- Add stratetic zone with customized reaction.
|
||||
-- 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.ARTY`
|
||||
@ -284,7 +276,7 @@ CHIEF.Strategy = {
|
||||
|
||||
--- CHIEF class version.
|
||||
-- @field #string version
|
||||
CHIEF.version="0.3.0"
|
||||
CHIEF.version="0.3.1"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -1006,23 +998,28 @@ function CHIEF:RemoveTarget(Target)
|
||||
end
|
||||
|
||||
--- 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
|
||||
-- Empty:
|
||||
-- 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.
|
||||
--
|
||||
-- Occupied:
|
||||
--
|
||||
-- * `AUFTRAG.Type.ARTY` 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.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 Ops.OpsZone#OPSZONE OpsZone OPS zone object.
|
||||
-- @param #number Priority Priority.
|
||||
-- @param #number Importance Importance.
|
||||
-- @param #number Priority Priority. Default 50.
|
||||
-- @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.
|
||||
function CHIEF:AddStrategicZone(OpsZone, Priority, Importance)
|
||||
function CHIEF:AddStrategicZone(OpsZone, Priority, Importance, ResourceOccupied, ResourceEmpty)
|
||||
|
||||
local stratzone={} --#CHIEF.StrategicZone
|
||||
|
||||
@ -1038,12 +1035,20 @@ function CHIEF:AddStrategicZone(OpsZone, Priority, Importance)
|
||||
end
|
||||
|
||||
-- Add resources if zone is occupied.
|
||||
stratzone.resourceOccup=self:CreateResource(AUFTRAG.Type.ARTY, 1, 2)
|
||||
self:AddToResource(stratzone.resourceOccup, AUFTRAG.Type.CASENHANCED, 1, 2)
|
||||
if ResourceOccupied then
|
||||
stratzone.resourceOccup=UTILS.DeepCopy(ResourceOccupied)
|
||||
else
|
||||
stratzone.resourceOccup=self:CreateResource(AUFTRAG.Type.ARTY, 1, 2)
|
||||
self:AddToResource(stratzone.resourceOccup, AUFTRAG.Type.CASENHANCED, 1, 2)
|
||||
end
|
||||
|
||||
-- Add resources if zone is empty
|
||||
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)
|
||||
if ResourceEmpty then
|
||||
stratzone.resourceEmpty=UTILS.DeepCopy(ResourceEmpty)
|
||||
else
|
||||
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)
|
||||
end
|
||||
|
||||
-- Add to table.
|
||||
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.GROUNDATTACK, 50))
|
||||
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ARTY, 30))
|
||||
|
||||
elseif attribute==GROUP.Attribute.GROUND_EWR then
|
||||
|
||||
-- EWR
|
||||
|
||||
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.SEAD, 100))
|
||||
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.BAI, 90))
|
||||
|
||||
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.ARTY, 30))
|
||||
|
||||
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.GROUNDATTACK, 50))
|
||||
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ARMORATTACK, 40))
|
||||
table.insert(missionperf, self:_CreateMissionPerformance(AUFTRAG.Type.ARTY, 30))
|
||||
|
||||
else
|
||||
|
||||
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.ARTY, 30))
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -26,6 +26,9 @@
|
||||
-- @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 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 missiontypes Capabilities (mission types and performances) of the cohort.
|
||||
-- @field #number maintenancetime Time in seconds needed for maintenance of a returned flight.
|
||||
@ -83,7 +86,7 @@ COHORT = {
|
||||
|
||||
--- COHORT class version.
|
||||
-- @field #string version
|
||||
COHORT.version="0.3.2"
|
||||
COHORT.version="0.3.4"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -226,6 +229,74 @@ function COHORT:New(TemplateGroupName, Ngroups, CohortName)
|
||||
-- @param #COHORT self
|
||||
-- @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
|
||||
end
|
||||
|
||||
@ -905,9 +976,9 @@ end
|
||||
-- @return #table Assets that can do the required mission.
|
||||
-- @return #number Number of payloads still available after recruiting the assets.
|
||||
function COHORT:RecruitAssets(MissionType, Npayloads)
|
||||
self:T("RecruitAssets for " .. MissionType .. " with " ..Npayloads)
|
||||
|
||||
-- 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.
|
||||
local assets={}
|
||||
@ -916,32 +987,60 @@ function COHORT:RecruitAssets(MissionType, Npayloads)
|
||||
for _,_asset in pairs(self.assets) do
|
||||
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.
|
||||
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).
|
||||
if self.legion:IsAssetOnMission(asset) then
|
||||
if self.legion:IsAssetOnMission(asset) then
|
||||
---
|
||||
-- Asset is already on a mission.
|
||||
---
|
||||
|
||||
|
||||
-- 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.
|
||||
-- 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"))
|
||||
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
|
||||
|
||||
-- Check if the payload of this asset is compatible with the mission.
|
||||
self:T(self.lid..string.format("Adding asset on ALERT 5 mission for %s mission", MissionType))
|
||||
table.insert(assets, asset)
|
||||
|
||||
table.insert(assets, asset)
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
--
|
||||
-- **Main Features:**
|
||||
--
|
||||
-- * Manages AIRWINGS, BRIGADEs and FLOTILLAs
|
||||
-- * Manages AIRWINGS, BRIGADEs and FLEETs
|
||||
-- * Handles missions (AUFTRAG) and finds the best assets for the job
|
||||
--
|
||||
-- ===
|
||||
@ -95,7 +95,7 @@
|
||||
--
|
||||
-- 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.
|
||||
-- Mission designers can hook into the event with the @{#COMMANDER.OnAfterOpsOnMission}() function
|
||||
@ -104,7 +104,7 @@
|
||||
-- -- Your code
|
||||
-- end
|
||||
--
|
||||
-- # Canceling a Mission
|
||||
-- ## Canceling a Mission
|
||||
--
|
||||
-- A mission can be cancelled with the @{#COMMMANDER.MissionCancel}() function
|
||||
--
|
||||
@ -136,7 +136,7 @@ COMMANDER = {
|
||||
|
||||
--- COMMANDER class version.
|
||||
-- @field #string version
|
||||
COMMANDER.version="0.1.1"
|
||||
COMMANDER.version="0.1.2"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -398,7 +398,7 @@ function COMMANDER:AddAirwing(Airwing)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Add an BRIGADE to the commander.
|
||||
--- Add a BRIGADE to the commander.
|
||||
-- @param #COMMANDER self
|
||||
-- @param Ops.Brigade#BRIGADE Brigade The brigade to add.
|
||||
-- @return #COMMANDER self
|
||||
@ -410,6 +410,19 @@ function COMMANDER:AddBrigade(Brigade)
|
||||
return self
|
||||
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.
|
||||
-- @param #COMMANDER self
|
||||
-- @param Ops.Legion#LEGION Legion The legion to add.
|
||||
@ -653,6 +666,83 @@ function COMMANDER:IsMission(Mission)
|
||||
return false
|
||||
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
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
@ -974,7 +1064,7 @@ function COMMANDER:onafterMissionCancel(From, Event, To, Mission)
|
||||
|
||||
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 #string From From state.
|
||||
-- @param #string Event Event.
|
||||
@ -1215,7 +1305,8 @@ function COMMANDER:RecruitAssetsForMission(Mission)
|
||||
local Payloads=Mission.payloads
|
||||
|
||||
-- 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
|
||||
end
|
||||
|
||||
@ -867,7 +867,7 @@ function FLIGHTGROUP:Status()
|
||||
local ammo=self:GetAmmoTot().Total
|
||||
|
||||
-- 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.
|
||||
local cargo=0
|
||||
|
||||
@ -430,13 +430,16 @@ end
|
||||
-- Cohort assets will not be available until relocation is finished.
|
||||
-- @param #LEGION self
|
||||
-- @param Ops.Cohort#COHORT Cohort The cohort to be relocated.
|
||||
-- @param Ops.Legion#LEGION Legion.
|
||||
-- @param #number Delay Delay in seconds before relocation takes place. Default 0 sec.
|
||||
-- @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 that transport assets can only be recruited from this legion.
|
||||
-- @return #LEGION self
|
||||
function LEGION:RelocateCohort(Cohort, Legion, Delay)
|
||||
function LEGION:RelocateCohort(Cohort, Legion, Delay, NcarriersMin, NcarriersMax, TransportLegions)
|
||||
|
||||
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
|
||||
|
||||
-- Add cohort to legion.
|
||||
@ -465,17 +468,45 @@ function LEGION:RelocateCohort(Cohort, Legion, Delay)
|
||||
-- Create a relocation mission.
|
||||
local mission=AUFTRAG:_NewRELOCATECOHORT(Legion, Cohort)
|
||||
|
||||
-- Add assets to mission.
|
||||
mission:_AddAssets(Cohort.assets)
|
||||
|
||||
-- Debug info.
|
||||
self:I(self.lid..string.format("Relocating Cohort %s [nassets=%d] to legion %s", Cohort.name, #Cohort.assets, Legion.alias))
|
||||
if false then
|
||||
--- Disabled for now.
|
||||
|
||||
-- Assign mission to this legion.
|
||||
self:MissionAssign(mission, {self})
|
||||
-- Add assets to mission.
|
||||
mission:_AddAssets(Cohort.assets)
|
||||
|
||||
-- Debug info.
|
||||
self:I(self.lid..string.format("Relocating Cohort %s [nassets=%d] to legion %s", Cohort.name, #Cohort.assets, Legion.alias))
|
||||
|
||||
-- Assign mission to this legion.
|
||||
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
|
||||
|
||||
-- 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
|
||||
|
||||
--- Get cohort by name.
|
||||
@ -810,7 +841,7 @@ function LEGION:onafterMissionRequest(From, Event, To, Mission)
|
||||
---
|
||||
|
||||
if asset.flightgroup then
|
||||
|
||||
|
||||
-- Add new mission.
|
||||
asset.flightgroup:AddMission(Mission)
|
||||
|
||||
@ -822,27 +853,29 @@ function LEGION:onafterMissionRequest(From, Event, To, Mission)
|
||||
local currM=asset.flightgroup:GetMissionCurrent()
|
||||
|
||||
if currM then
|
||||
|
||||
-- Cancel?
|
||||
local cancel=false
|
||||
-- Pause?
|
||||
local pause=false
|
||||
|
||||
-- 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
|
||||
self:T(self.lid..string.format("Pausing %s mission %s to send flight on intercept mission %s", currM.type, currM.name, Mission.name))
|
||||
asset.flightgroup:PauseMission()
|
||||
pause=true
|
||||
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
|
||||
|
||||
-- Cancel current ALERT5 mission
|
||||
-- Cancel current ALERT5 mission.
|
||||
if currM.type==AUFTRAG.Type.ALERT5 then
|
||||
cancel=true
|
||||
end
|
||||
|
||||
-- Cancel the current mission.
|
||||
if currM.type==AUFTRAG.Type.ONGUARD or currM.type==AUFTRAG.Type.ARMOREDGUARD then
|
||||
cancel=true
|
||||
end
|
||||
|
||||
|
||||
-- Cancel current mission for relcation.
|
||||
if Mission.type==AUFTRAG.Type.RELOCATECOHORT then
|
||||
cancel=true
|
||||
|
||||
-- Get request ID.
|
||||
local requestID=currM.requestID[self.alias]
|
||||
|
||||
-- Get request.
|
||||
@ -853,18 +886,26 @@ function LEGION:onafterMissionRequest(From, Event, To, Mission)
|
||||
request.cargogroupset:Remove(asset.spawngroupname, true)
|
||||
else
|
||||
self:E(self.lid.."ERROR: no request for spawned asset!")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Cancel mission.
|
||||
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)
|
||||
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
|
||||
|
||||
-- Not reserved any more.
|
||||
asset.isReserved=false
|
||||
|
||||
end
|
||||
|
||||
-- Trigger event.
|
||||
self:__OpsOnMission(5, asset.flightgroup, Mission)
|
||||
self:__OpsOnMission(2, asset.flightgroup, Mission)
|
||||
|
||||
else
|
||||
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!
|
||||
asset.requested=true
|
||||
|
||||
-- Spawned asset are not requested.
|
||||
if asset.spawned then
|
||||
asset.requested=false
|
||||
end
|
||||
|
||||
-- Not reserved and more.
|
||||
asset.isReserved=false
|
||||
|
||||
-- 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()
|
||||
if Tacan then
|
||||
asset.tacan=Tacan
|
||||
--flightgroup:SetDefaultTACAN(Tacan,Morse,UnitName,Band,OffSwitch)
|
||||
flightgroup:SwitchTACAN(Tacan, Morse, UnitName, Band)
|
||||
end
|
||||
|
||||
@ -1400,6 +1447,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.
|
||||
flightgroup:AddMission(mission)
|
||||
|
||||
-- RTZ on out of ammo.
|
||||
if self:IsBrigade() or self:IsFleet() then
|
||||
flightgroup:SetReturnOnOutOfAmmo()
|
||||
end
|
||||
|
||||
-- Trigger event.
|
||||
self:__OpsOnMission(5, flightgroup, mission)
|
||||
@ -1669,26 +1721,7 @@ 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
|
||||
end
|
||||
|
||||
@ -1907,7 +1940,6 @@ function LEGION:CountAssetsOnMission(MissionTypes, Cohort)
|
||||
end
|
||||
end
|
||||
|
||||
--env.info(string.format("FF N=%d Np=%d, Nq=%d", Np+Nq, Np, Nq))
|
||||
return Np+Nq, Np, Nq
|
||||
end
|
||||
|
||||
@ -2043,11 +2075,11 @@ function LEGION:RecruitAssetsForMission(Mission)
|
||||
-- No escort cohorts/legions given ==> take own cohorts.
|
||||
if #Cohorts==0 then
|
||||
Cohorts=self.cohorts
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Recuit assets.
|
||||
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
|
||||
end
|
||||
@ -2226,10 +2258,14 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
|
||||
local cohort=_cohort --Ops.Cohort#COHORT
|
||||
if WeaponTypes and #WeaponTypes>0 then
|
||||
for _,WeaponType in pairs(WeaponTypes) do
|
||||
for _,_weaponData in pairs(cohort.weaponData or {}) do
|
||||
local weaponData=_weaponData --Ops.OpsGroup#OPSGROUP.WeaponData
|
||||
if weaponData.BitType==WeaponType then
|
||||
return true
|
||||
if WeaponType==ENUMS.WeaponFlag.Auto then
|
||||
return true
|
||||
else
|
||||
for _,_weaponData in pairs(cohort.weaponData or {}) do
|
||||
local weaponData=_weaponData --Ops.OpsGroup#OPSGROUP.WeaponData
|
||||
if weaponData.BitType==WeaponType then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -2262,9 +2298,7 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
|
||||
Refuel=false
|
||||
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?
|
||||
local Capable=AUFTRAG.CheckMissionCapability({MissionTypeRecruit}, cohort.missiontypes)
|
||||
|
||||
@ -2283,12 +2317,19 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
|
||||
-- Right weapon type.
|
||||
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.
|
||||
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)))
|
||||
|
||||
-- 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.
|
||||
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.
|
||||
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
|
||||
|
||||
-- Get current mission.
|
||||
local currmission=asset.flightgroup:GetMissionCurrent()
|
||||
|
||||
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
|
||||
-- Prefer assets that are on ALERT5 for this mission type.
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
@ -2742,6 +2787,10 @@ function LEGION.CalculateAssetMissionScore(asset, MissionType, TargetVec2, Inclu
|
||||
-- Max speed of assets.
|
||||
-- Fuel amount?
|
||||
-- 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
|
||||
end
|
||||
|
||||
@ -828,7 +828,7 @@ function NAVYGROUP:Status(From, Event, To)
|
||||
local ammo=self:GetAmmoTot().Total
|
||||
|
||||
-- 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.
|
||||
local cargo=0
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #string groupname Name of the group.
|
||||
-- @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#Template template Template table 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 speedCruise Cruising speed in km/h.
|
||||
-- @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 #number wpcounter Running number counting waypoints.
|
||||
-- @field Core.Set#SET_ZONE checkzones Set of zones.
|
||||
@ -200,6 +202,7 @@ OPSGROUP = {
|
||||
-- @field Wrapper.Unit#UNIT unit The UNIT object.
|
||||
-- @field Wrapper.Group#GROUP group The GROUP 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 #string skill Skill level.
|
||||
--
|
||||
@ -466,7 +469,7 @@ OPSGROUP.CargoStatus={
|
||||
|
||||
--- OpsGroup version.
|
||||
-- @field #string version
|
||||
OPSGROUP.version="0.7.7"
|
||||
OPSGROUP.version="0.7.8"
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TODO list
|
||||
@ -1045,6 +1048,108 @@ function OPSGROUP:SetDetection(Switch)
|
||||
return self
|
||||
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.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param #number Code Laser code. Default 1688.
|
||||
@ -1285,6 +1390,23 @@ function OPSGROUP:SetRearmOnOutOfAmmo()
|
||||
return self
|
||||
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.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param Core.Point#COORDINATE Coordinate The position to which we check the LoS.
|
||||
@ -3633,6 +3755,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
|
||||
end
|
||||
@ -3817,6 +3962,21 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
-- FLIGHTGROUP not implemented (intended!) for this AUFTRAG type.
|
||||
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
|
||||
|
||||
---
|
||||
@ -3903,20 +4063,67 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
|
||||
-- If task is scheduled (not waypoint) set task.
|
||||
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!
|
||||
if Task.dcstask.id==AUFTRAG.SpecialTask.BARRAGE then
|
||||
---
|
||||
-- BARRAGE
|
||||
|
||||
-- Current vec2.
|
||||
local vec2=self:GetVec2()
|
||||
|
||||
-- Task parameters.
|
||||
local param=Task.dcstask.params
|
||||
|
||||
-- Set heading and altitude.
|
||||
local heading=param.heading or math.random(1, 360)
|
||||
local Altitude=param.altitude or 500
|
||||
local Alpha=param.angle or math.random(45, 85)
|
||||
local distance=Altitude/math.tan(math.rad(Alpha))
|
||||
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))
|
||||
|
||||
-- Set fire at point task.
|
||||
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
|
||||
---
|
||||
-- Take DCS task
|
||||
---
|
||||
DCSTask=Task.dcstask
|
||||
end
|
||||
|
||||
@ -4126,12 +4333,12 @@ function OPSGROUP:onafterTaskDone(From, Event, To, Task)
|
||||
else
|
||||
|
||||
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()
|
||||
end
|
||||
|
||||
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()
|
||||
end
|
||||
|
||||
@ -4173,7 +4380,6 @@ function OPSGROUP:AddMission(Mission)
|
||||
table.insert(self.missionqueue, Mission)
|
||||
|
||||
-- ad infinitum?
|
||||
|
||||
self.adinfinitum = Mission.DCStask.params.adinfinitum and Mission.DCStask.params.adinfinitum or false
|
||||
|
||||
-- Info text.
|
||||
@ -4335,7 +4541,7 @@ function OPSGROUP:_GetNextMission()
|
||||
for _,_opsgroup in pairs(cargos) do
|
||||
local opscargo=_opsgroup --Ops.OpsGroup#OPSGROUP
|
||||
if opscargo.groupname==self.groupname then
|
||||
isTransport=false
|
||||
--isTransport=false
|
||||
break
|
||||
end
|
||||
end
|
||||
@ -4345,9 +4551,16 @@ function OPSGROUP:_GetNextMission()
|
||||
local isScheduled=mission:GetGroupStatus(self)==AUFTRAG.GroupStatus.SCHEDULED
|
||||
local isReadyToGo=(mission:IsReadyToGo() or self.legion)
|
||||
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.
|
||||
if isScheduled and isReadyToGo and isImportant and isTransport and isEscort then
|
||||
if go then
|
||||
return mission
|
||||
end
|
||||
|
||||
@ -4483,7 +4696,7 @@ function OPSGROUP:onafterMissionStart(From, Event, To, Mission)
|
||||
Mission:__Started(3)
|
||||
|
||||
-- Route group to mission zone.
|
||||
if self.speedMax>3.6 then
|
||||
if self.speedMax>3.6 or true then
|
||||
|
||||
self:RouteToMission(Mission, 3)
|
||||
|
||||
@ -4492,10 +4705,12 @@ function OPSGROUP:onafterMissionStart(From, Event, To, Mission)
|
||||
-- IMMOBILE Group
|
||||
---
|
||||
|
||||
--env.info("FF Immobile GROUP")
|
||||
env.info(self.lid.."FF Immobile GROUP")
|
||||
|
||||
-- Add waypoint task. UpdateRoute is called inside.
|
||||
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)
|
||||
Task.ismission=true
|
||||
|
||||
@ -4554,6 +4769,8 @@ function OPSGROUP:onafterPauseMission(From, Event, To)
|
||||
|
||||
-- Cancelling the mission is actually cancelling the current task.
|
||||
self:TaskCancel(Task)
|
||||
|
||||
self:_RemoveMissionWaypoints(Mission)
|
||||
|
||||
-- Set mission to pause so we can unpause it later.
|
||||
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.
|
||||
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)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
@ -4705,10 +4928,14 @@ function OPSGROUP:onafterMissionDone(From, Event, To, Mission)
|
||||
if Mission.optionAlarm then
|
||||
self:SwitchAlarmstate()
|
||||
end
|
||||
-- Alarm state to default.
|
||||
-- EPLRS to default.
|
||||
if Mission.optionEPLRS then
|
||||
self:SwitchEPLRS()
|
||||
end
|
||||
-- Emission to default.
|
||||
if Mission.optionEmission then
|
||||
self:SwitchEmission()
|
||||
end
|
||||
-- Formation to default.
|
||||
if Mission.optionFormation then
|
||||
self:SwitchFormation()
|
||||
@ -4821,7 +5048,10 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
|
||||
-- Ingress waypoint coordinate where the mission is executed.
|
||||
local waypointcoord=nil --Core.Point#COORDINATE
|
||||
|
||||
|
||||
-- Target zone.
|
||||
local targetzone=nil --Core.Zone#ZONE
|
||||
|
||||
-- Random radius of 1000 meters.
|
||||
local randomradius=mission.missionWaypointRadius or 1000
|
||||
|
||||
@ -4832,27 +5062,81 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
elseif self:IsNavygroup() then
|
||||
surfacetypes={land.SurfaceType.WATER, land.SurfaceType.SHALLOW_WATER}
|
||||
end
|
||||
|
||||
|
||||
-- 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
|
||||
local zone=mission.engageTarget:GetObject() --Core.Zone#ZONE
|
||||
waypointcoord=zone:GetRandomCoordinate(nil , nil, surfacetypes)
|
||||
-- Get ingress waypoint.
|
||||
if mission.opstransport and not mission.opstransport:IsCargoDelivered(self.groupname) then
|
||||
|
||||
--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
|
||||
---
|
||||
-- Guard
|
||||
---
|
||||
|
||||
-- Mission waypoint
|
||||
waypointcoord=mission:GetMissionWaypointCoord(self.group, nil, surfacetypes)
|
||||
elseif mission.type==AUFTRAG.Type.RELOCATECOHORT then
|
||||
|
||||
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
|
||||
---
|
||||
-- Relocation
|
||||
---
|
||||
|
||||
-- Roughly go to the new legion.
|
||||
local ToCoordinate=mission.DCStask.params.legion:GetCoordinate()
|
||||
|
||||
if self.isFlightgroup then
|
||||
waypointcoord=self:GetCoordinate():GetIntermediateCoordinate(ToCoordinate, 0.2):SetAltitude(self.altitudeCruise)
|
||||
else
|
||||
waypointcoord=self:GetCoordinate():GetIntermediateCoordinate(ToCoordinate, 0.05)
|
||||
end
|
||||
|
||||
else
|
||||
waypointcoord=mission:GetMissionWaypointCoord(self.group, randomradius, surfacetypes)
|
||||
end
|
||||
|
||||
if mission.type==AUFTRAG.Type.HOVER then
|
||||
local zone=mission.engageTarget:GetObject() --Core.Zone#ZONE
|
||||
waypointcoord=zone:GetCoordinate()
|
||||
---
|
||||
-- Default case
|
||||
---
|
||||
|
||||
waypointcoord=mission:GetMissionWaypointCoord(self.group, randomradius, surfacetypes)
|
||||
end
|
||||
|
||||
-- Add enroute tasks.
|
||||
@ -4962,6 +5246,7 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Add waypoint.
|
||||
local waypoint=nil --#OPSGROUP.Waypoint
|
||||
@ -5001,18 +5286,53 @@ function OPSGROUP:RouteToMission(mission, delay)
|
||||
mission:SetGroupEgressWaypointUID(self, Ewaypoint.uid)
|
||||
end
|
||||
|
||||
|
||||
-- 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
|
||||
self:Cruise(SpeedToMission)
|
||||
elseif self:IsNavygroup() then
|
||||
self:Cruise(SpeedToMission)
|
||||
elseif self:IsFlightgroup() then
|
||||
self:UpdateRoute()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---
|
||||
-- Mission Specific Settings
|
||||
---
|
||||
self:_SetMissionOptions(mission)
|
||||
|
||||
if self:IsArmygroup() then
|
||||
self:Cruise(SpeedToMission)
|
||||
elseif self:IsNavygroup() then
|
||||
self:Cruise(SpeedToMission)
|
||||
elseif self:IsFlightgroup() then
|
||||
self:UpdateRoute()
|
||||
end
|
||||
self:_SetMissionOptions(mission)
|
||||
|
||||
end
|
||||
end
|
||||
@ -5038,6 +5358,10 @@ function OPSGROUP:_SetMissionOptions(mission)
|
||||
if mission.optionEPLRS then
|
||||
self:SwitchEPLRS(mission.optionEPLRS)
|
||||
end
|
||||
-- Emission
|
||||
if mission.optionEPLRS then
|
||||
self:SwitchEmission(mission.optionEmission)
|
||||
end
|
||||
-- Formation
|
||||
if mission.optionFormation and self:IsFlightgroup() then
|
||||
self:SwitchFormation(mission.optionFormation)
|
||||
@ -5441,6 +5765,13 @@ function OPSGROUP:_SetWaypointTasks(Waypoint)
|
||||
-- Check if there is mission task
|
||||
if missiontask then
|
||||
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)
|
||||
return 1
|
||||
end
|
||||
@ -5497,8 +5828,6 @@ end
|
||||
-- @param #number Speed (Optional) Speed to waypoint in knots.
|
||||
function OPSGROUP:onafterGotoWaypoint(From, Event, To, UID, Speed)
|
||||
|
||||
--env.info("FF goto waypoint uid="..tostring(UID))
|
||||
|
||||
local n=self:GetWaypointIndex(UID)
|
||||
|
||||
if n then
|
||||
@ -6263,11 +6592,12 @@ end
|
||||
-- @param #OPSGROUP self
|
||||
-- @param Core.Point#COORDINATE Coordinate Coordinate where the group is teleported to.
|
||||
-- @param #number Delay Delay in seconds before respawn happens. Default 0.
|
||||
-- @param #boolean NoPauseMission If `true`, dont pause a running mission.
|
||||
-- @return #OPSGROUP self
|
||||
function OPSGROUP:Teleport(Coordinate, Delay)
|
||||
function OPSGROUP:Teleport(Coordinate, Delay, NoPauseMission)
|
||||
|
||||
if Delay and Delay>0 then
|
||||
self:ScheduleOnce(Delay, OPSGROUP.Teleport, self, Coordinate)
|
||||
self:ScheduleOnce(Delay, OPSGROUP.Teleport, self, Coordinate, 0, NoPauseMission)
|
||||
else
|
||||
|
||||
-- Debug message.
|
||||
@ -6275,8 +6605,8 @@ function OPSGROUP:Teleport(Coordinate, Delay)
|
||||
--Coordinate:MarkToAll("Teleport "..self.groupname)
|
||||
|
||||
-- Check if we have a mission running.
|
||||
if self:IsOnMission() then
|
||||
self:T(self.lid.."Pausing current mission")
|
||||
if self:IsOnMission() and not NoPauseMission then
|
||||
self:T(self.lid.."Pausing current mission for telport")
|
||||
self:PauseMission()
|
||||
end
|
||||
|
||||
@ -6285,6 +6615,14 @@ function OPSGROUP:Teleport(Coordinate, Delay)
|
||||
|
||||
-- Set late activation of template to current state.
|
||||
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.
|
||||
local units=Template.units
|
||||
@ -7840,17 +8178,36 @@ function OPSGROUP:onafterLoading(From, Event, To)
|
||||
local cargos={}
|
||||
for _,_cargo in pairs(self.cargoTZC.Cargos) do
|
||||
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 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.
|
||||
-- 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()
|
||||
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)
|
||||
end
|
||||
end
|
||||
@ -8482,6 +8839,10 @@ function OPSGROUP:onafterUnloaded(From, Event, To, OpsGroupCargo)
|
||||
OpsGroupCargo:Returned()
|
||||
end
|
||||
|
||||
if OpsGroupCargo.missionpaused then
|
||||
OpsGroupCargo:UnpauseMission()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -9037,6 +9398,11 @@ function OPSGROUP:_CheckGroupDone(delay)
|
||||
return
|
||||
end
|
||||
|
||||
if self:IsBoarding() then
|
||||
self:T(self.lid.."Boarding! Group NOT done...")
|
||||
return
|
||||
end
|
||||
|
||||
-- Group is waiting. We deny all updates.
|
||||
if self:IsWaiting() then
|
||||
-- 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.uid=element.DCSunit:getID()
|
||||
--element.group=unit:GetGroup()
|
||||
element.controller=element.DCSunit:getController()
|
||||
element.opsgroup=self
|
||||
|
||||
-- Skill etc.
|
||||
|
||||
@ -656,58 +656,6 @@ function OPSTRANSPORT:GetEmbarkZone(TransportZoneCombo)
|
||||
return TransportZoneCombo.EmbarkZone
|
||||
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.
|
||||
-- @param #OPSTRANSPORT self
|
||||
-- @param Core.Zone#ZONE DisembarkZone Zone where the troops are disembarked.
|
||||
@ -1366,6 +1314,25 @@ function OPSTRANSPORT:AddAssetCargo(Asset, TransportZoneCombo)
|
||||
return self
|
||||
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.
|
||||
-- @param #OPSTRANSPORT self
|
||||
-- @param Ops.Legion#LEGION Legion The legion.
|
||||
@ -1638,6 +1605,24 @@ function OPSTRANSPORT:onafterStatusUpdate(From, Event, To)
|
||||
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
|
||||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -428,6 +428,21 @@ function OPSZONE:GetCoordinate()
|
||||
return coordinate
|
||||
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.
|
||||
-- @param #OPSZONE self
|
||||
-- @return #string Name of the zone.
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
-- @field #string tankergroupname Name of the late activated tanker template 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 Core.Radio#BEACON beacon Tanker TACAN beacon.
|
||||
-- @field Core.Beacon#BEACON beacon Tanker TACAN beacon.
|
||||
-- @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 TACANmorse TACAN morse code. Three letters identifying the TACAN station. Default "TKR".
|
||||
@ -784,10 +784,11 @@ end
|
||||
-- @param #RECOVERYTANKER self
|
||||
-- @param #number channel TACAN channel. Default 1.
|
||||
-- @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
|
||||
function RECOVERYTANKER:SetTACAN(channel, morse)
|
||||
function RECOVERYTANKER:SetTACAN(channel, morse, mode)
|
||||
self.TACANchannel=channel or 1
|
||||
self.TACANmode="Y"
|
||||
self.TACANmode=mode or "Y"
|
||||
self.TACANmorse=morse or "TKR"
|
||||
self.TACANon=true
|
||||
return self
|
||||
@ -1625,7 +1626,6 @@ function RECOVERYTANKER:_ActivateTACAN(delay)
|
||||
if delay and delay>0 then
|
||||
|
||||
-- Schedule TACAN activation.
|
||||
--SCHEDULER:New(nil, self._ActivateTACAN, {self}, delay)
|
||||
self:ScheduleOnce(delay, RECOVERYTANKER._ActivateTACAN, self)
|
||||
|
||||
else
|
||||
|
||||
@ -529,26 +529,32 @@ function GROUP:HasAttribute(attribute, all)
|
||||
-- Get all units of the group.
|
||||
local _units=self:GetUnits()
|
||||
|
||||
local _allhave=true
|
||||
local _onehas=false
|
||||
if _units then
|
||||
|
||||
for _,_unit in pairs(_units) do
|
||||
local _unit=_unit --Wrapper.Unit#UNIT
|
||||
if _unit then
|
||||
local _hastit=_unit:HasAttribute(attribute)
|
||||
if _hastit==true then
|
||||
_onehas=true
|
||||
else
|
||||
_allhave=false
|
||||
end
|
||||
end
|
||||
local _allhave=true
|
||||
local _onehas=false
|
||||
|
||||
for _,_unit in pairs(_units) do
|
||||
local _unit=_unit --Wrapper.Unit#UNIT
|
||||
if _unit then
|
||||
local _hastit=_unit:HasAttribute(attribute)
|
||||
if _hastit==true then
|
||||
_onehas=true
|
||||
else
|
||||
_allhave=false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if all==true then
|
||||
return _allhave
|
||||
else
|
||||
return _onehas
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if all==true then
|
||||
return _allhave
|
||||
else
|
||||
return _onehas
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Returns the maximum speed of the group.
|
||||
@ -563,16 +569,19 @@ function GROUP:GetSpeedMax()
|
||||
|
||||
local Units=self:GetUnits()
|
||||
|
||||
local speedmax=0
|
||||
local speedmax=nil
|
||||
|
||||
for _,unit in pairs(Units) do
|
||||
local unit=unit --Wrapper.Unit#UNIT
|
||||
|
||||
local speed=unit:GetSpeedMax()
|
||||
if speedmax==0 then
|
||||
speedmax=speed
|
||||
elseif speed<speedmax then
|
||||
|
||||
if speedmax==nil or speed<speedmax then
|
||||
speedmax=speed
|
||||
end
|
||||
|
||||
--env.info(string.format("FF unit %s: speed=%.1f, speedmax=%.1f", unit:GetName(), speed, speedmax))
|
||||
|
||||
end
|
||||
|
||||
return speedmax
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user