mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
- Changed mission, legion in MissionAssign functions (LEGION, COMMANDER, CHIEF) - OPSTRANSPORT: improved TZC selection - ARMYGROUP needs to
2223 lines
76 KiB
Lua
2223 lines
76 KiB
Lua
--- **Ops** - Troop transport assignment for OPS groups.
|
|
--
|
|
-- ## Main Features:
|
|
--
|
|
-- * Transport troops from A to B
|
|
-- * Supports ground, naval and airborne (airplanes and helicopters) units as carriers
|
|
-- * Use combined forces (ground, naval, air) to transport the troops
|
|
-- * Additional FSM events to hook into and customize your mission design
|
|
--
|
|
-- ===
|
|
--
|
|
-- ## Example Missions:
|
|
--
|
|
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Transport).
|
|
--
|
|
-- ===
|
|
--
|
|
-- ### Author: **funkyfranky**
|
|
--
|
|
-- ==
|
|
--
|
|
-- @module Ops.OpsTransport
|
|
-- @image OPS_OpsTransport.png
|
|
|
|
|
|
--- OPSTRANSPORT class.
|
|
-- @type OPSTRANSPORT
|
|
-- @field #string ClassName Name of the class.
|
|
-- @field #string lid Log ID.
|
|
-- @field #number uid Unique ID of the transport.
|
|
-- @field #number verbose Verbosity level.
|
|
--
|
|
-- @field #number prio Priority of this transport. Should be a number between 0 (high prio) and 100 (low prio).
|
|
-- @field #boolean urgent If true, transport is urgent.
|
|
-- @field #number importance Importance of this transport. Smaller=higher.
|
|
-- @field #number Tstart Start time in *abs.* seconds.
|
|
-- @field #number Tstop Stop time in *abs.* seconds. Default `#nil` (never stops).
|
|
-- @field #number duration Duration (`Tstop-Tstart`) of the transport in seconds.
|
|
-- @field #table conditionStart Start conditions.
|
|
--
|
|
-- @field #table carriers Carriers assigned for this transport.
|
|
-- @field #table carrierTransportStatus Status of each carrier.
|
|
--
|
|
-- @field #table tzCombos Table of transport zone combos. Each element of the table is of type `#OPSTRANSPORT.TransportZoneCombo`.
|
|
-- @field #number tzcCounter Running number of added transport zone combos.
|
|
-- @field #OPSTRANSPORT.TransportZoneCombo tzcDefault Default transport zone combo.
|
|
--
|
|
-- @field #number Ncargo Total number of cargo groups.
|
|
-- @field #number Ncarrier Total number of assigned carriers.
|
|
-- @field #number Ndelivered Total number of cargo groups delivered.
|
|
-- @field #number NcarrierDead Total number of dead carrier groups
|
|
-- @field #number NcargoDead Totalnumber of dead cargo groups.
|
|
--
|
|
-- @field Ops.Auftrag#AUFTRAG mission The mission attached to this transport.
|
|
-- @field #table assets Warehouse assets assigned for this transport.
|
|
-- @field #table legions Assigned legions.
|
|
-- @field #table statusLegion Transport status of all assigned LEGIONs.
|
|
-- @field #string statusCommander Staus of the COMMANDER.
|
|
-- @field Ops.Commander#COMMANDER commander Commander of the transport.
|
|
-- @field #table requestID The ID of the queued warehouse request. Necessary to cancel the request if the transport was cancelled before the request is processed.
|
|
--
|
|
-- @extends Core.Fsm#FSM
|
|
|
|
--- *Victory is the beautiful, bright-colored flower. Transport is the stem without which it could never have blossomed.* -- Winston Churchill
|
|
--
|
|
-- ===
|
|
--
|
|
-- # The OPSTRANSPORT Concept
|
|
--
|
|
-- This class simulates troop transport using carriers such as APCs, ships, helicopters or airplanes. The carriers and transported groups need to be OPSGROUPS (see ARMYGROUP, NAVYGROUP and FLIGHTGROUP classes).
|
|
--
|
|
-- **IMPORTANT NOTES**
|
|
--
|
|
-- * Cargo groups are **not** split and distributed into different carrier *units*. That means that the whole cargo group **must fit** into one of the carrier units.
|
|
-- * Cargo groups must be inside the pickup zones to be considered for loading. Groups not inside the pickup zone will not get the command to board.
|
|
--
|
|
-- # Constructor
|
|
--
|
|
-- A new cargo transport assignment is created with the @{#OPSTRANSPORT.New}() function
|
|
--
|
|
-- local opstransport=OPSTRANSPORT:New(Cargo, PickupZone, DeployZone)
|
|
--
|
|
-- Here `Cargo` is an object of the troops to be transported. This can be a GROUP, OPSGROUP, SET_GROUP or SET_OPSGROUP object.
|
|
--
|
|
-- `PickupZone` is the zone where the troops are picked up by the transport carriers. **Note** that troops *must* be inside this zone to be considered for loading!
|
|
--
|
|
-- `DeployZone` is the zone where the troops are transported to.
|
|
--
|
|
-- ## Assign to Carrier(s)
|
|
--
|
|
-- A transport can be assigned to one or multiple carrier OPSGROUPS with this @{Ops.OpsGroup#OPSGROUP.AddOpsTransport}() function
|
|
--
|
|
-- myopsgroup:AddOpsTransport(opstransport)
|
|
--
|
|
-- There is no restriction to the type of the carrier. It can be a ground group (e.g. an APC), a helicopter, an airplane or even a ship.
|
|
--
|
|
-- You can also mix carrier types. For instance, you can assign the same transport to APCs and helicopters. Or to helicopters and airplanes.
|
|
--
|
|
-- # Examples
|
|
--
|
|
-- A carrier group is assigned to transport infantry troops from zone "Zone Kobuleti X" to zone "Zone Alpha".
|
|
--
|
|
-- -- Carrier group.
|
|
-- local carrier=ARMYGROUP:New("TPz Fuchs Group")
|
|
--
|
|
-- -- Set of groups to transport.
|
|
-- local infantryset=SET_GROUP:New():FilterPrefixes("Infantry Platoon Alpha"):FilterOnce()
|
|
--
|
|
-- -- Cargo transport assignment.
|
|
-- local opstransport=OPSTRANSPORT:New(infantryset, ZONE:New("Zone Kobuleti X"), ZONE:New("Zone Alpha"))
|
|
--
|
|
-- -- Assign transport to carrier.
|
|
-- carrier:AddOpsTransport(opstransport)
|
|
--
|
|
--
|
|
-- @field #OPSTRANSPORT
|
|
OPSTRANSPORT = {
|
|
ClassName = "OPSTRANSPORT",
|
|
verbose = 0,
|
|
carriers = {},
|
|
carrierTransportStatus = {},
|
|
tzCombos = {},
|
|
tzcCounter = 0,
|
|
conditionStart = {},
|
|
assets = {},
|
|
legions = {},
|
|
statusLegion = {},
|
|
requestID = {},
|
|
}
|
|
|
|
--- Cargo transport status.
|
|
-- @type OPSTRANSPORT.Status
|
|
-- @field #string PLANNED Planning state.
|
|
-- @field #string QUEUED Queued state.
|
|
-- @field #string REQUESTED Requested state.
|
|
-- @field #string SCHEDULED Transport is scheduled in the cargo queue.
|
|
-- @field #string EXECUTING Transport is being executed.
|
|
-- @field #string DELIVERED Transport was delivered.
|
|
-- @field #string CANCELLED Transport was cancelled.
|
|
-- @field #string SUCCESS Transport was a success.
|
|
-- @field #string FAILED Transport failed.
|
|
OPSTRANSPORT.Status={
|
|
PLANNED="planned",
|
|
QUEUED="queued",
|
|
REQUESTED="requested",
|
|
SCHEDULED="scheduled",
|
|
EXECUTING="executing",
|
|
DELIVERED="delivered",
|
|
CANCELLED="cancelled",
|
|
SUCCESS="success",
|
|
FAILED="failed",
|
|
}
|
|
|
|
--- Transport zone combination.
|
|
-- @type OPSTRANSPORT.TransportZoneCombo
|
|
-- @field #number uid Unique ID of the TZ combo.
|
|
-- @field #number Ncarriers Number of carrier groups using this transport zone.
|
|
-- @field #number Ncargo Number of cargos assigned. This is a running number and *not* decreased if cargo is delivered or dead.
|
|
-- @field #table Cargos Cargo groups of the TZ combo. Each element is of type `Ops.OpsGroup#OPSGROUP.CargoGroup`.
|
|
-- @field Core.Zone#ZONE PickupZone Pickup zone.
|
|
-- @field Core.Zone#ZONE DeployZone Deploy zone.
|
|
-- @field Core.Zone#ZONE EmbarkZone Embark zone if different from pickup zone.
|
|
-- @field Core.Zone#ZONE DisembarkZone Zone where the troops are disembared to.
|
|
-- @field Wrapper.Airbase#AIRBASE PickupAirbase Airbase for pickup.
|
|
-- @field Wrapper.Airbase#AIRBASE DeployAirbase Airbase for deploy.
|
|
-- @field #table PickupPaths Paths for pickup.
|
|
-- @field #table TransportPaths Path for Transport. Each elment of the table is of type `#OPSTRANSPORT.Path`.
|
|
-- @field #table RequiredCargos Required cargos.
|
|
-- @field #table DisembarkCarriers Carriers where the cargo is directly disembarked to.
|
|
-- @field #boolean disembarkActivation If true, troops are spawned in late activated state when disembarked from carrier.
|
|
-- @field #boolean disembarkInUtero If true, troops are disembarked "in utero".
|
|
-- @field #boolean assets Cargo assets.
|
|
-- @field #number PickupFormation Formation used to pickup.
|
|
-- @field #number TransportFormation Formation used to transport.
|
|
|
|
--- Path used for pickup or transport.
|
|
-- @type OPSTRANSPORT.Path
|
|
-- @field #table coords Table of coordinates.
|
|
-- @field #number radius Radomization radius in meters. Default 0 m.
|
|
-- @field #number altitude Altitude in feet AGL. Only for aircraft.
|
|
|
|
--- Generic transport condition.
|
|
-- @type OPSTRANSPORT.Condition
|
|
-- @field #function func Callback function to check for a condition. Should return a #boolean.
|
|
-- @field #table arg Optional arguments passed to the condition callback function.
|
|
|
|
--- Transport ID.
|
|
_OPSTRANSPORTID=0
|
|
|
|
--- Army Group version.
|
|
-- @field #string version
|
|
OPSTRANSPORT.version="0.5.0"
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- TODO list
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
-- TODO: Trains.
|
|
-- TODO: Special transport cohorts/legions. Similar to mission.
|
|
-- TODO: Stop/abort transport.
|
|
-- DONE: Allow multiple pickup/depoly zones.
|
|
-- DONE: Add start conditions.
|
|
-- DONE: Check carrier(s) dead.
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Constructor
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Create a new OPSTRANSPORT class object. Essential input are the troops that should be transported and the zones where the troops are picked up and deployed.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Core.Set#SET_GROUP CargoGroups Groups to be transported as cargo. Can also be a single @{Wrapper.Group#GROUP} or @{Ops.OpsGroup#OPSGROUP} object.
|
|
-- @param Core.Zone#ZONE PickupZone Pickup zone. This is the zone, where the carrier is going to pickup the cargo. **Important**: only cargo is considered, if it is in this zone when the carrier starts loading!
|
|
-- @param Core.Zone#ZONE DeployZone Deploy zone. This is the zone, where the carrier is going to drop off the cargo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:New(CargoGroups, PickupZone, DeployZone)
|
|
|
|
-- Inherit everything from FSM class.
|
|
local self=BASE:Inherit(self, FSM:New()) -- #OPSTRANSPORT
|
|
|
|
-- Increase ID counter.
|
|
_OPSTRANSPORTID=_OPSTRANSPORTID+1
|
|
|
|
-- Set some string id for output to DCS.log file.
|
|
self.lid=string.format("OPSTRANSPORT [UID=%d] | ", _OPSTRANSPORTID)
|
|
|
|
-- UID of this transport.
|
|
self.uid=_OPSTRANSPORTID
|
|
|
|
-- Defaults.
|
|
self:SetPriority()
|
|
self:SetTime()
|
|
self:SetRequiredCarriers()
|
|
|
|
-- Init arrays and counters.
|
|
self.carriers={}
|
|
self.Ncargo=0
|
|
self.Ncarrier=0
|
|
self.Ndelivered=0
|
|
self.NcargoDead=0
|
|
self.NcarrierDead=0
|
|
|
|
-- Set default TZC.
|
|
self.tzcDefault=self:AddTransportZoneCombo(PickupZone, DeployZone, CargoGroups)
|
|
|
|
-- FMS start state is PLANNED.
|
|
self:SetStartState(OPSTRANSPORT.Status.PLANNED)
|
|
|
|
-- PLANNED --> SCHEDULED --> EXECUTING --> DELIVERED
|
|
self:AddTransition("*", "Planned", OPSTRANSPORT.Status.PLANNED) -- Cargo transport was planned.
|
|
self:AddTransition(OPSTRANSPORT.Status.PLANNED, "Queued", OPSTRANSPORT.Status.QUEUED) -- Cargo is queued at at least one carrier.
|
|
self:AddTransition(OPSTRANSPORT.Status.QUEUED, "Requested", OPSTRANSPORT.Status.REQUESTED) -- Transport assets have been requested from a warehouse.
|
|
self:AddTransition(OPSTRANSPORT.Status.REQUESTED, "Scheduled", OPSTRANSPORT.Status.SCHEDULED) -- Cargo is queued at at least one carrier.
|
|
self:AddTransition(OPSTRANSPORT.Status.PLANNED, "Scheduled", OPSTRANSPORT.Status.SCHEDULED) -- Cargo is queued at at least one carrier.
|
|
self:AddTransition(OPSTRANSPORT.Status.SCHEDULED, "Executing", OPSTRANSPORT.Status.EXECUTING) -- Cargo is being transported.
|
|
self:AddTransition("*", "Delivered", OPSTRANSPORT.Status.DELIVERED) -- Cargo was delivered.
|
|
|
|
self:AddTransition("*", "StatusUpdate", "*")
|
|
self:AddTransition("*", "Stop", "*")
|
|
|
|
self:AddTransition("*", "Cancel", OPSTRANSPORT.Status.CANCELLED) -- Command to cancel the transport.
|
|
|
|
self:AddTransition("*", "Loaded", "*")
|
|
self:AddTransition("*", "Unloaded", "*")
|
|
|
|
self:AddTransition("*", "DeadCarrierUnit", "*")
|
|
self:AddTransition("*", "DeadCarrierGroup", "*")
|
|
self:AddTransition("*", "DeadCarrierAll", "*")
|
|
|
|
------------------------
|
|
--- Pseudo Functions ---
|
|
------------------------
|
|
|
|
--- Triggers the FSM event "StatusUpdate".
|
|
-- @function [parent=#OPSTRANSPORT] StatusUpdate
|
|
-- @param #OPSTRANSPORT self
|
|
|
|
--- Triggers the FSM event "Status" after a delay.
|
|
-- @function [parent=#OPSTRANSPORT] __StatusUpdate
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number delay Delay in seconds.
|
|
|
|
|
|
--- Triggers the FSM event "Planned".
|
|
-- @function [parent=#OPSTRANSPORT] Planned
|
|
-- @param #OPSTRANSPORT self
|
|
|
|
--- Triggers the FSM event "Planned" after a delay.
|
|
-- @function [parent=#OPSTRANSPORT] __Planned
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number delay Delay in seconds.
|
|
|
|
--- On after "Planned" event.
|
|
-- @function [parent=#OPSTRANSPORT] OnAfterPlanned
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
|
|
|
|
--- Triggers the FSM event "Queued".
|
|
-- @function [parent=#OPSTRANSPORT] Queued
|
|
-- @param #OPSTRANSPORT self
|
|
|
|
--- Triggers the FSM event "Queued" after a delay.
|
|
-- @function [parent=#OPSTRANSPORT] __Queued
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number delay Delay in seconds.
|
|
|
|
--- On after "Queued" event.
|
|
-- @function [parent=#OPSTRANSPORT] OnAfterQueued
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
|
|
|
|
--- Triggers the FSM event "Requested".
|
|
-- @function [parent=#OPSTRANSPORT] Requested
|
|
-- @param #OPSTRANSPORT self
|
|
|
|
--- Triggers the FSM event "Requested" after a delay.
|
|
-- @function [parent=#OPSTRANSPORT] __Requested
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number delay Delay in seconds.
|
|
|
|
--- On after "Requested" event.
|
|
-- @function [parent=#OPSTRANSPORT] OnAfterRequested
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
|
|
|
|
--- Triggers the FSM event "Scheduled".
|
|
-- @function [parent=#OPSTRANSPORT] Scheduled
|
|
-- @param #OPSTRANSPORT self
|
|
|
|
--- Triggers the FSM event "Scheduled" after a delay.
|
|
-- @function [parent=#OPSTRANSPORT] __Scheduled
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number delay Delay in seconds.
|
|
|
|
--- On after "Scheduled" event.
|
|
-- @function [parent=#OPSTRANSPORT] OnAfterScheduled
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
|
|
|
|
--- Triggers the FSM event "Executing".
|
|
-- @function [parent=#OPSTRANSPORT] Executing
|
|
-- @param #OPSTRANSPORT self
|
|
|
|
--- Triggers the FSM event "Executing" after a delay.
|
|
-- @function [parent=#OPSTRANSPORT] __Executing
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number delay Delay in seconds.
|
|
|
|
--- On after "Executing" event.
|
|
-- @function [parent=#OPSTRANSPORT] OnAfterExecuting
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
|
|
|
|
--- Triggers the FSM event "Delivered".
|
|
-- @function [parent=#OPSTRANSPORT] Delivered
|
|
-- @param #OPSTRANSPORT self
|
|
|
|
--- Triggers the FSM event "Delivered" after a delay.
|
|
-- @function [parent=#OPSTRANSPORT] __Delivered
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number delay Delay in seconds.
|
|
|
|
--- On after "Delivered" event.
|
|
-- @function [parent=#OPSTRANSPORT] OnAfterDelivered
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
|
|
|
|
--- Triggers the FSM event "Cancel".
|
|
-- @function [parent=#OPSTRANSPORT] Cancel
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport.
|
|
|
|
--- Triggers the FSM event "Cancel" after a delay.
|
|
-- @function [parent=#OPSTRANSPORT] __Cancel
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number delay Delay in seconds.
|
|
-- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport.
|
|
|
|
--- On after "Cancel" event.
|
|
-- @function [parent=#OPSTRANSPORT] OnAfterCancel
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param Ops.OpsTransport#OPSTRANSPORT Transport The transport.
|
|
|
|
|
|
--- Triggers the FSM event "Loaded".
|
|
-- @function [parent=#OPSTRANSPORT] Loaded
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCargo OPSGROUP that was loaded into a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCarrier OPSGROUP that was loaded into a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP.Element CarrierElement Carrier element.
|
|
|
|
--- Triggers the FSM event "Loaded" after a delay.
|
|
-- @function [parent=#OPSTRANSPORT] __Loaded
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number delay Delay in seconds.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCargo OPSGROUP that was loaded into a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCarrier OPSGROUP that was loaded into a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP.Element CarrierElement Carrier element.
|
|
|
|
--- On after "Loaded" event.
|
|
-- @function [parent=#OPSTRANSPORT] OnAfterLoaded
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCargo OPSGROUP that was loaded into a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCarrier OPSGROUP that was loaded into a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP.Element CarrierElement Carrier element.
|
|
|
|
|
|
--- Triggers the FSM event "Unloaded".
|
|
-- @function [parent=#OPSTRANSPORT] Unloaded
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCargo Cargo OPSGROUP that was unloaded from a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCarrier Carrier OPSGROUP that unloaded the cargo.
|
|
|
|
--- Triggers the FSM event "Unloaded" after a delay.
|
|
-- @function [parent=#OPSTRANSPORT] __Unloaded
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number delay Delay in seconds.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCargo Cargo OPSGROUP that was unloaded from a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCarrier Carrier OPSGROUP that unloaded the cargo.
|
|
|
|
--- On after "Unloaded" event.
|
|
-- @function [parent=#OPSTRANSPORT] OnAfterUnloaded
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCargo Cargo OPSGROUP that was unloaded from a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCarrier Carrier OPSGROUP that unloaded the cargo.
|
|
|
|
|
|
--TODO: Psydofunctions
|
|
|
|
-- Call status update.
|
|
self:__StatusUpdate(-1)
|
|
|
|
return self
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- User Functions
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Add pickup and deploy zone combination.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Core.Zone#ZONE PickupZone Zone where the troops are picked up.
|
|
-- @param Core.Zone#ZONE DeployZone Zone where the troops are picked up.
|
|
-- @param Core.Set#SET_GROUP CargoGroups Groups to be transported as cargo. Can also be a single @{Wrapper.Group#GROUP} or @{Ops.OpsGroup#OPSGROUP} object.
|
|
-- @return #OPSTRANSPORT.TransportZoneCombo Transport zone table.
|
|
function OPSTRANSPORT:AddTransportZoneCombo(PickupZone, DeployZone, CargoGroups)
|
|
|
|
-- Increase counter.
|
|
self.tzcCounter=self.tzcCounter+1
|
|
|
|
local tzcombo={} --#OPSTRANSPORT.TransportZoneCombo
|
|
|
|
-- Init.
|
|
tzcombo.uid=self.tzcCounter
|
|
tzcombo.Ncarriers=0
|
|
tzcombo.Ncargo=0
|
|
tzcombo.Cargos={}
|
|
tzcombo.RequiredCargos={}
|
|
tzcombo.DisembarkCarriers={}
|
|
tzcombo.PickupPaths={}
|
|
tzcombo.TransportPaths={}
|
|
|
|
-- Set zones.
|
|
self:SetPickupZone(PickupZone, tzcombo)
|
|
self:SetDeployZone(DeployZone, tzcombo)
|
|
self:SetEmbarkZone(nil, tzcombo)
|
|
|
|
-- Add cargo groups (could also be added later).
|
|
if CargoGroups then
|
|
self:AddCargoGroups(CargoGroups, tzcombo)
|
|
end
|
|
|
|
-- Add to table.
|
|
table.insert(self.tzCombos, tzcombo)
|
|
|
|
return tzcombo
|
|
end
|
|
|
|
--- Add cargo groups to be transported.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Core.Set#SET_GROUP GroupSet Set of groups to be transported. Can also be passed as a single GROUP or OPSGROUP object.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:AddCargoGroups(GroupSet, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
-- Check type of GroupSet provided.
|
|
if GroupSet:IsInstanceOf("GROUP") or GroupSet:IsInstanceOf("OPSGROUP") then
|
|
|
|
-- We got a single GROUP or OPSGROUP object.
|
|
local cargo=self:_CreateCargoGroupData(GroupSet, TransportZoneCombo)
|
|
|
|
if cargo then
|
|
|
|
-- Add to main table.
|
|
--table.insert(self.cargos, cargo)
|
|
self.Ncargo=self.Ncargo+1
|
|
|
|
-- Add to TZC table.
|
|
table.insert(TransportZoneCombo.Cargos, cargo)
|
|
TransportZoneCombo.Ncargo=TransportZoneCombo.Ncargo+1
|
|
|
|
cargo.opsgroup:_AddMyLift(self)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
-- We got a SET_GROUP object.
|
|
|
|
for _,group in pairs(GroupSet.Set) do
|
|
|
|
-- Call iteravely for each group.
|
|
self:AddCargoGroups(group, TransportZoneCombo)
|
|
|
|
end
|
|
end
|
|
|
|
-- Debug info.
|
|
if self.verbose>=1 then
|
|
local text=string.format("Added cargo groups:")
|
|
local Weight=0
|
|
for _,_cargo in pairs(self:GetCargos()) do
|
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
|
local weight=cargo.opsgroup:GetWeightTotal()
|
|
Weight=Weight+weight
|
|
text=text..string.format("\n- %s [%s] weight=%.1f kg", cargo.opsgroup:GetName(), cargo.opsgroup:GetState(), weight)
|
|
end
|
|
text=text..string.format("\nTOTAL: Ncargo=%d, Weight=%.1f kg", self.Ncargo, Weight)
|
|
self:I(self.lid..text)
|
|
end
|
|
|
|
|
|
return self
|
|
end
|
|
|
|
|
|
--- Set pickup zone.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Core.Zone#ZONE PickupZone Zone where the troops are picked up.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetPickupZone(PickupZone, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
TransportZoneCombo.PickupZone=PickupZone
|
|
|
|
if PickupZone and PickupZone:IsInstanceOf("ZONE_AIRBASE") then
|
|
TransportZoneCombo.PickupAirbase=PickupZone._.ZoneAirbase
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get pickup zone.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return Core.Zone#ZONE Zone where the troops are picked up.
|
|
function OPSTRANSPORT:GetPickupZone(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
return TransportZoneCombo.PickupZone
|
|
end
|
|
|
|
--- Set deploy zone.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Core.Zone#ZONE DeployZone Zone where the troops are deployed.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetDeployZone(DeployZone, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
-- Set deploy zone.
|
|
TransportZoneCombo.DeployZone=DeployZone
|
|
|
|
-- Check if this is an airbase.
|
|
if DeployZone and DeployZone:IsInstanceOf("ZONE_AIRBASE") then
|
|
TransportZoneCombo.DeployAirbase=DeployZone._.ZoneAirbase
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get deploy zone.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return Core.Zone#ZONE Zone where the troops are deployed.
|
|
function OPSTRANSPORT:GetDeployZone(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
return TransportZoneCombo.DeployZone
|
|
end
|
|
|
|
--- Set embark zone.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Core.Zone#ZONE EmbarkZone Zone where the troops are embarked.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetEmbarkZone(EmbarkZone, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
TransportZoneCombo.EmbarkZone=EmbarkZone or TransportZoneCombo.PickupZone
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get embark zone.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return Core.Zone#ZONE Zone where the troops are embarked from.
|
|
function OPSTRANSPORT:GetEmbarkZone(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
return TransportZoneCombo.EmbarkZone
|
|
end
|
|
|
|
--- Set disembark zone.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Core.Zone#ZONE DisembarkZone Zone where the troops are disembarked.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetDisembarkZone(DisembarkZone, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
TransportZoneCombo.DisembarkZone=DisembarkZone
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get disembark zone.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return Core.Zone#ZONE Zone where the troops are disembarked to.
|
|
function OPSTRANSPORT:GetDisembarkZone(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
return TransportZoneCombo.DisembarkZone
|
|
end
|
|
|
|
--- Set activation status of group when disembarked from transport carrier.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #boolean Active If `true` or `nil`, group is activated when disembarked. If `false`, group is late activated and needs to be activated manually.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetDisembarkActivation(Active, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
if Active==true or Active==nil then
|
|
TransportZoneCombo.disembarkActivation=true
|
|
else
|
|
TransportZoneCombo.disembarkActivation=false
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get disembark activation.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #boolean If `true`, groups are spawned in late activated state.
|
|
function OPSTRANSPORT:GetDisembarkActivation(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
return TransportZoneCombo.disembarkActivation
|
|
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:SetDisembarkCarriers(Carriers, TransportZoneCombo)
|
|
|
|
-- Debug info.
|
|
self:T(self.lid.."Setting transfer 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.DisembarkCarriers, 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.DisembarkCarriers, 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 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:GetDisembarkCarriers(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
return TransportZoneCombo.DisembarkCarriers
|
|
end
|
|
|
|
|
|
--- Set if group remains *in utero* after disembarkment from carrier. Can be used to directly load the group into another carrier. Similar to disembark in late activated state.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #boolean InUtero If `true` or `nil`, group remains *in utero* after disembarkment.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetDisembarkInUtero(InUtero, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
if InUtero==true or InUtero==nil then
|
|
TransportZoneCombo.disembarkInUtero=true
|
|
else
|
|
TransportZoneCombo.disembarkInUtero=false
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get disembark in utero.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #boolean If `true`, groups stay in utero after disembarkment.
|
|
function OPSTRANSPORT:GetDisembarkInUtero(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
return TransportZoneCombo.disembarkInUtero
|
|
end
|
|
|
|
--- Set pickup formation.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number Formation Pickup formation.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetFormationPickup(Formation, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
TransportZoneCombo.PickupFormation=Formation
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get pickup formation.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #number Formation.
|
|
function OPSTRANSPORT:_GetFormationPickup(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
return TransportZoneCombo.PickupFormation
|
|
end
|
|
|
|
--- Set transport formation.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number Formation Pickup formation.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetFormationTransport(Formation, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
TransportZoneCombo.TransportFormation=Formation
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get transport formation.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #number Formation.
|
|
function OPSTRANSPORT:_GetFormationTransport(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
return TransportZoneCombo.TransportFormation
|
|
end
|
|
|
|
|
|
|
|
--- Set required cargo. This is a list of cargo groups that need to be loaded before the **first** transport will start.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Core.Set#SET_GROUP Cargos Required cargo 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:SetRequiredCargos(Cargos, TransportZoneCombo)
|
|
|
|
-- Debug info.
|
|
self:T(self.lid.."Setting required cargos!")
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
-- Create table.
|
|
TransportZoneCombo.RequiredCargos=TransportZoneCombo.RequiredCargos or {}
|
|
|
|
if Cargos:IsInstanceOf("GROUP") or Cargos:IsInstanceOf("OPSGROUP") then
|
|
|
|
local cargo=self:_GetOpsGroupFromObject(Cargos)
|
|
if cargo then
|
|
table.insert(TransportZoneCombo.RequiredCargos, cargo)
|
|
end
|
|
|
|
elseif Cargos:IsInstanceOf("SET_GROUP") or Cargos:IsInstanceOf("SET_OPSGROUP") then
|
|
|
|
for _,object in pairs(Cargos:GetSet()) do
|
|
local cargo=self:_GetOpsGroupFromObject(object)
|
|
if cargo then
|
|
table.insert(TransportZoneCombo.RequiredCargos, cargo)
|
|
end
|
|
end
|
|
|
|
else
|
|
self:E(self.lid.."ERROR: Required Cargos must be a GROUP, OPSGROUP, SET_GROUP or SET_OPSGROUP object!")
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get required cargos. This is a list of cargo groups that need to be loaded before the **first** transport will start.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #table Table of required cargo ops groups.
|
|
function OPSTRANSPORT:GetRequiredCargos(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
return TransportZoneCombo.RequiredCargos
|
|
end
|
|
|
|
--- Set number of required carrier groups for an OPSTRANSPORT assignment. Only used if transport is assigned at **LEGION** or higher level.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number NcarriersMin Number of carriers *at least* required. Default 1.
|
|
-- @param #number NcarriersMax Number of carriers *at most* used for transportation. Default is same as `NcarriersMin`.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetRequiredCarriers(NcarriersMin, NcarriersMax)
|
|
|
|
self.nCarriersMin=NcarriersMin or 1
|
|
|
|
self.nCarriersMax=NcarriersMax or self.nCarriersMin
|
|
|
|
-- Ensure that max is at least equal to min.
|
|
if self.nCarriersMax<self.nCarriersMin then
|
|
self.nCarriersMax=self.nCarriersMin
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get the number of required carrier groups for an OPSTRANSPORT assignment. Only used if transport is assigned at **LEGION** or higher level.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @return #number Number of carriers *at least* required.
|
|
-- @return #number Number of carriers *at most* used for transportation.
|
|
function OPSTRANSPORT:GetRequiredCarriers()
|
|
return self.nCarriersMin, self.nCarriersMax
|
|
end
|
|
|
|
|
|
--- Add a carrier assigned for this transport.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.OpsGroup#OPSGROUP CarrierGroup Carrier OPSGROUP.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:_AddCarrier(CarrierGroup)
|
|
|
|
-- Check that this is not already an assigned carrier.
|
|
if not self:IsCarrier(CarrierGroup) then
|
|
|
|
-- Increase carrier count.
|
|
self.Ncarrier=self.Ncarrier+1
|
|
|
|
-- Set transport status to SCHEDULED.
|
|
self:SetCarrierTransportStatus(CarrierGroup, OPSTRANSPORT.Status.SCHEDULED)
|
|
|
|
-- Call scheduled event.
|
|
self:Scheduled()
|
|
|
|
-- Add carrier to table.
|
|
table.insert(self.carriers, CarrierGroup)
|
|
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Remove group from the current carrier list/table.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.OpsGroup#OPSGROUP CarrierGroup Carrier OPSGROUP.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:_DelCarrier(CarrierGroup)
|
|
|
|
if self:IsCarrier(CarrierGroup) then
|
|
|
|
for i=#self.carriers,1,-1 do
|
|
local carrier=self.carriers[i] --Ops.OpsGroup#OPSGROUP
|
|
if carrier.groupname==CarrierGroup.groupname then
|
|
self:T(self.lid..string.format("Removing carrier %s", CarrierGroup.groupname))
|
|
table.remove(self.carriers, i)
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get a list of alive carriers.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @return #table Names of all carriers
|
|
function OPSTRANSPORT:_GetCarrierNames()
|
|
|
|
local names={}
|
|
for _,_carrier in pairs(self.carriers) do
|
|
local carrier=_carrier --Ops.OpsGroup#OPSGROUP
|
|
if carrier:IsAlive()~=nil then
|
|
table.insert(names, carrier.groupname)
|
|
end
|
|
end
|
|
|
|
return names
|
|
end
|
|
|
|
--- Get (all) cargo @{Ops.OpsGroup#OPSGROUP}s. Optionally, only delivered or undelivered groups can be returned.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #boolean Delivered If `true`, only delivered groups are returned. If `false` only undelivered groups are returned. If `nil`, all groups are returned.
|
|
-- @param Ops.OpsGroup#OPSGROUP Carrier (Optional) Only count cargo groups that fit into the given carrier group. Current cargo is not a factor.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #table Cargo Ops groups. Can be and empty table `{}`.
|
|
function OPSTRANSPORT:GetCargoOpsGroups(Delivered, Carrier, TransportZoneCombo)
|
|
|
|
local cargos=self:GetCargos(TransportZoneCombo)
|
|
|
|
local opsgroups={}
|
|
for _,_cargo in pairs(cargos) do
|
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
|
if Delivered==nil or cargo.delivered==Delivered then
|
|
if cargo.opsgroup and not (cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped()) then
|
|
if Carrier==nil or Carrier:CanCargo(cargo.opsgroup) then
|
|
table.insert(opsgroups, cargo.opsgroup)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return opsgroups
|
|
end
|
|
|
|
--- Get carriers.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @return #table Carrier Ops groups.
|
|
function OPSTRANSPORT:GetCarriers()
|
|
return self.carriers
|
|
end
|
|
|
|
--- Get cargos.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #table Cargos.
|
|
function OPSTRANSPORT:GetCargos(TransportZoneCombo)
|
|
|
|
if TransportZoneCombo then
|
|
return TransportZoneCombo.Cargos
|
|
else
|
|
local cargos={}
|
|
for _,_tzc in pairs(self.tzCombos) do
|
|
local tzc=_tzc --#OPSTRANSPORT.TransportZoneCombo
|
|
for _,cargo in pairs(tzc.Cargos) do
|
|
table.insert(cargos, cargo)
|
|
end
|
|
end
|
|
return cargos
|
|
end
|
|
|
|
end
|
|
|
|
--- Set transport start and stop time.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string ClockStart Time the transport is started, e.g. "05:00" for 5 am. If specified as a #number, it will be relative (in seconds) to the current mission time. Default is 5 seconds after mission was added.
|
|
-- @param #string ClockStop (Optional) Time the transport is stopped, e.g. "13:00" for 1 pm. If mission could not be started at that time, it will be removed from the queue. If specified as a #number it will be relative (in seconds) to the current mission time.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetTime(ClockStart, ClockStop)
|
|
|
|
-- Current mission time.
|
|
local Tnow=timer.getAbsTime()
|
|
|
|
-- Set start time. Default in 5 sec.
|
|
local Tstart=Tnow+5
|
|
if ClockStart and type(ClockStart)=="number" then
|
|
Tstart=Tnow+ClockStart
|
|
elseif ClockStart and type(ClockStart)=="string" then
|
|
Tstart=UTILS.ClockToSeconds(ClockStart)
|
|
end
|
|
|
|
-- Set stop time. Default nil.
|
|
local Tstop=nil
|
|
if ClockStop and type(ClockStop)=="number" then
|
|
Tstop=Tnow+ClockStop
|
|
elseif ClockStop and type(ClockStop)=="string" then
|
|
Tstop=UTILS.ClockToSeconds(ClockStop)
|
|
end
|
|
|
|
self.Tstart=Tstart
|
|
self.Tstop=Tstop
|
|
|
|
if Tstop then
|
|
self.duration=self.Tstop-self.Tstart
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Set mission priority and (optional) urgency. Urgent missions can cancel other running missions.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number Prio Priority 1=high, 100=low. Default 50.
|
|
-- @param #number Importance Number 1-10. If missions with lower value are in the queue, these have to be finished first. Default is `nil`.
|
|
-- @param #boolean Urgent If *true*, another running mission might be cancelled if it has a lower priority.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetPriority(Prio, Importance, Urgent)
|
|
self.prio=Prio or 50
|
|
self.urgent=Urgent
|
|
self.importance=Importance
|
|
return self
|
|
end
|
|
|
|
--- Set verbosity.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number Verbosity Be more verbose. Default 0
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetVerbosity(Verbosity)
|
|
self.verbose=Verbosity or 0
|
|
return self
|
|
end
|
|
|
|
--- Add start condition.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #function ConditionFunction Function that needs to be true before the transport can be started. Must return a #boolean.
|
|
-- @param ... Condition function arguments if any.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:AddConditionStart(ConditionFunction, ...)
|
|
|
|
if ConditionFunction then
|
|
|
|
local condition={} --#OPSTRANSPORT.Condition
|
|
|
|
condition.func=ConditionFunction
|
|
condition.arg={}
|
|
if arg then
|
|
condition.arg=arg
|
|
end
|
|
|
|
table.insert(self.conditionStart, condition)
|
|
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Add path used for transportation from the pickup to the deploy zone. If multiple paths are defined, a random one is chosen.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Wrapper.Group#GROUP PathGroup A (late activated) GROUP defining a transport path by their waypoints.
|
|
-- @param #boolean Reversed If `true`, add waypoints of group in reversed order.
|
|
-- @param #number Radius Randomization radius in meters. Default 0 m.
|
|
-- @param #number Altitude Altitude in feet AGL. Only for aircraft.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport Zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:AddPathTransport(PathGroup, Reversed, Radius, Altitude, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
local path={} --#OPSTRANSPORT.Path
|
|
path.coords={}
|
|
path.radius=Radius or 0
|
|
path.altitude=Altitude
|
|
|
|
-- Get route points.
|
|
local waypoints=PathGroup:GetTaskRoute()
|
|
|
|
if Reversed then
|
|
for i=#waypoints,1,-1 do
|
|
local wp=waypoints[i]
|
|
local coord=COORDINATE:New(wp.x, wp.alt, wp.y)
|
|
table.insert(path.coords, coord)
|
|
end
|
|
else
|
|
for i=1,#waypoints do
|
|
local wp=waypoints[i]
|
|
local coord=COORDINATE:New(wp.x, wp.alt, wp.y)
|
|
table.insert(path.coords, coord)
|
|
end
|
|
end
|
|
|
|
|
|
-- Add path.
|
|
table.insert(TransportZoneCombo.TransportPaths, path)
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get a path for transportation.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport Zone combo.
|
|
-- @return #table The path of COORDINATEs.
|
|
function OPSTRANSPORT:_GetPathTransport(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
local pathsTransport=TransportZoneCombo.TransportPaths
|
|
|
|
if pathsTransport and #pathsTransport>0 then
|
|
|
|
-- Get a random path for transport.
|
|
local path=pathsTransport[math.random(#pathsTransport)] --#OPSTRANSPORT.Path
|
|
|
|
|
|
local coordinates={}
|
|
for _,_coord in ipairs(path.coords) do
|
|
local coord=_coord --Core.Point#COORDINATE
|
|
|
|
-- Get random coordinate.
|
|
local c=coord:GetRandomCoordinateInRadius(path.radius)
|
|
|
|
table.insert(coordinates, c)
|
|
end
|
|
|
|
return coordinates
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
|
|
--- Add path used to go to the pickup zone. If multiple paths are defined, a random one is chosen.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Wrapper.Group#GROUP PathGroup A (late activated) GROUP defining a transport path by their waypoints.
|
|
-- @param #boolean Reversed If `true`, add waypoints of group in reversed order.
|
|
-- @param #number Radius Randomization radius in meters. Default 0 m.
|
|
-- @param #number Altitude Altitude in feet AGL. Only for aircraft.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport Zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:AddPathPickup(PathGroup, Reversed, Radius, Altitude, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
local path={} --#OPSTRANSPORT.Path
|
|
path.coords={}
|
|
path.radius=Radius or 0
|
|
path.altitude=Altitude
|
|
|
|
-- Get route points.
|
|
local waypoints=PathGroup:GetTaskRoute()
|
|
|
|
if Reversed then
|
|
for i=#waypoints,1,-1 do
|
|
local wp=waypoints[i]
|
|
local coord=COORDINATE:New(wp.x, wp.alt, wp.y)
|
|
table.insert(path.coords, coord)
|
|
end
|
|
else
|
|
for i=1,#waypoints do
|
|
local wp=waypoints[i]
|
|
local coord=COORDINATE:New(wp.x, wp.alt, wp.y)
|
|
table.insert(path.coords, coord)
|
|
end
|
|
end
|
|
|
|
-- Add path.
|
|
table.insert(TransportZoneCombo.PickupPaths, path)
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get a path for pickup.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport Zone combo.
|
|
-- @return #table The path of COORDINATEs.
|
|
function OPSTRANSPORT:_GetPathPickup(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
local paths=TransportZoneCombo.PickupPaths
|
|
|
|
if paths and #paths>0 then
|
|
|
|
-- Get a random path for transport.
|
|
local path=paths[math.random(#paths)] --#OPSTRANSPORT.Path
|
|
|
|
|
|
local coordinates={}
|
|
for _,_coord in ipairs(path.coords) do
|
|
local coord=_coord --Core.Point#COORDINATE
|
|
|
|
-- Get random coordinate.
|
|
local c=coord:GetRandomCoordinateInRadius(path.radius)
|
|
|
|
table.insert(coordinates, c)
|
|
end
|
|
|
|
return coordinates
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
|
|
--- Add a carrier assigned for this transport.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.OpsGroup#OPSGROUP CarrierGroup Carrier OPSGROUP.
|
|
-- @param #string Status Carrier Status.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetCarrierTransportStatus(CarrierGroup, Status)
|
|
|
|
self.carrierTransportStatus[CarrierGroup.groupname]=Status
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get carrier transport status.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.OpsGroup#OPSGROUP CarrierGroup Carrier OPSGROUP.
|
|
-- @return #string Carrier status.
|
|
function OPSTRANSPORT:GetCarrierTransportStatus(CarrierGroup)
|
|
return self.carrierTransportStatus[CarrierGroup.groupname]
|
|
end
|
|
|
|
--- Get unique ID of the transport assignment.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @return #number UID.
|
|
function OPSTRANSPORT:GetUID()
|
|
return self.uid
|
|
end
|
|
|
|
--- Get number of delivered cargo groups.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @return #number Total number of delivered cargo groups.
|
|
function OPSTRANSPORT:GetNcargoDelivered()
|
|
return self.Ndelivered
|
|
end
|
|
|
|
--- Get number of cargo groups.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @return #number Total number of cargo groups.
|
|
function OPSTRANSPORT:GetNcargoTotal()
|
|
return self.Ncargo
|
|
end
|
|
|
|
--- Get number of carrier groups assigned for this transport.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @return #number Total number of carrier groups.
|
|
function OPSTRANSPORT:GetNcarrier()
|
|
return self.Ncarrier
|
|
end
|
|
|
|
--- Add asset to transport.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset to be added.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:AddAsset(Asset, TransportZoneCombo)
|
|
|
|
-- Debug info
|
|
self:T(self.lid..string.format("Adding asset carrier \"%s\" to transport", tostring(Asset.spawngroupname)))
|
|
|
|
-- Add asset to table.
|
|
self.assets=self.assets or {}
|
|
|
|
table.insert(self.assets, Asset)
|
|
|
|
return self
|
|
end
|
|
|
|
--- Delete asset from mission.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset to be removed.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:DelAsset(Asset)
|
|
|
|
for i,_asset in pairs(self.assets or {}) do
|
|
local asset=_asset --Functional.Warehouse#WAREHOUSE.Assetitem
|
|
|
|
if asset.uid==Asset.uid then
|
|
self:T(self.lid..string.format("Removing asset \"%s\" from transport", tostring(Asset.spawngroupname)))
|
|
table.remove(self.assets, i)
|
|
return self
|
|
end
|
|
|
|
end
|
|
|
|
return self
|
|
end
|
|
|
|
--- Add cargo asset.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Functional.Warehouse#WAREHOUSE.Assetitem Asset The asset to be added.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:AddAssetCargo(Asset, TransportZoneCombo)
|
|
|
|
-- Debug info
|
|
self:T(self.lid..string.format("Adding asset cargo \"%s\" to transport and TZC=%s", tostring(Asset.spawngroupname), TransportZoneCombo and TransportZoneCombo.uid or "N/A"))
|
|
|
|
-- Add asset to table.
|
|
self.assetsCargo=self.assetsCargo or {}
|
|
|
|
table.insert(self.assetsCargo, Asset)
|
|
|
|
TransportZoneCombo.assetsCargo=TransportZoneCombo.assetsCargo or {}
|
|
|
|
TransportZoneCombo.assetsCargo[Asset.spawngroupname]=Asset
|
|
|
|
return self
|
|
end
|
|
|
|
--- Add LEGION to the transport.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.Legion#LEGION Legion The legion.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:AddLegion(Legion)
|
|
|
|
-- Debug info.
|
|
self:T(self.lid..string.format("Adding legion %s", Legion.alias))
|
|
|
|
-- Add legion to table.
|
|
table.insert(self.legions, Legion)
|
|
|
|
return self
|
|
end
|
|
|
|
--- Remove LEGION from transport.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.Legion#LEGION Legion The legion.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT: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)
|
|
return self
|
|
end
|
|
end
|
|
|
|
self:E(self.lid..string.format("ERROR: Legion %s not found and could not be removed!", Legion.alias))
|
|
return self
|
|
end
|
|
|
|
--- Check if an OPS group is assigned as carrier for this transport.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.OpsGroup#OPSGROUP CarrierGroup Potential carrier OPSGROUP.
|
|
-- @return #boolean If true, group is an assigned carrier.
|
|
function OPSTRANSPORT:IsCarrier(CarrierGroup)
|
|
|
|
for _,_carrier in pairs(self.carriers) do
|
|
local carrier=_carrier --Ops.OpsGroup#OPSGROUP
|
|
if carrier.groupname==CarrierGroup.groupname then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
--- Check if transport is ready to be started.
|
|
-- * Start time passed.
|
|
-- * Stop time did not pass already.
|
|
-- * All start conditions are true.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @return #boolean If true, mission can be started.
|
|
function OPSTRANSPORT:IsReadyToGo()
|
|
|
|
-- Debug text.
|
|
local text=self.lid.."Is ReadyToGo? "
|
|
|
|
-- Current abs time.
|
|
local Tnow=timer.getAbsTime()
|
|
|
|
-- Pickup AND deploy zones must be set.
|
|
local gotzones=false
|
|
for _,_tz in pairs(self.tzCombos) do
|
|
local tz=_tz --#OPSTRANSPORT.TransportZoneCombo
|
|
if tz.PickupZone and tz.DeployZone then
|
|
gotzones=true
|
|
break
|
|
end
|
|
end
|
|
if not gotzones then
|
|
text=text.."No, pickup/deploy zone combo not yet defined!"
|
|
return false
|
|
end
|
|
|
|
-- Start time did not pass yet.
|
|
if self.Tstart and Tnow<self.Tstart then
|
|
text=text.."No, start time not passed!"
|
|
return false
|
|
end
|
|
|
|
-- Stop time already passed.
|
|
if self.Tstop and Tnow>self.Tstop then
|
|
text=text.."Nope, stop time already passed!"
|
|
self:T(text)
|
|
return false
|
|
end
|
|
|
|
-- All start conditions true?
|
|
local startme=self:EvalConditionsAll(self.conditionStart)
|
|
|
|
-- Nope, not yet.
|
|
if not startme then
|
|
text=text..("No way, at least one start condition is not true!")
|
|
self:T(text)
|
|
return false
|
|
end
|
|
|
|
-- We're good to go!
|
|
text=text.."Yes!"
|
|
self:T(text)
|
|
return true
|
|
end
|
|
|
|
--- Set LEGION transport status.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.Legion#LEGION Legion The legion.
|
|
-- @param #string Status New status.
|
|
-- @return #OPSTRANSPORT self
|
|
function OPSTRANSPORT:SetLegionStatus(Legion, Status)
|
|
|
|
-- Old status
|
|
local status=self:GetLegionStatus(Legion)
|
|
|
|
-- Debug info.
|
|
self:T(self.lid..string.format("Setting LEGION %s to status %s-->%s", Legion.alias, tostring(status), tostring(Status)))
|
|
|
|
-- New status.
|
|
self.statusLegion[Legion.alias]=Status
|
|
|
|
return self
|
|
end
|
|
|
|
--- Get LEGION transport status.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.Legion#LEGION Legion The legion.
|
|
-- @return #string status Current status.
|
|
function OPSTRANSPORT:GetLegionStatus(Legion)
|
|
|
|
-- Current status.
|
|
local status=self.statusLegion[Legion.alias] or "unknown"
|
|
|
|
return status
|
|
end
|
|
|
|
--- Check if state is PLANNED.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @return #boolean If true, status is PLANNED.
|
|
function OPSTRANSPORT:IsPlanned()
|
|
local is=self:is(OPSTRANSPORT.Status.PLANNED)
|
|
return is
|
|
end
|
|
|
|
--- Check if state is QUEUED.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.Legion#LEGION Legion (Optional) Check if transport is queued at this legion.
|
|
-- @return #boolean If true, status is QUEUED.
|
|
function OPSTRANSPORT:IsQueued(Legion)
|
|
local is=self:is(OPSTRANSPORT.Status.QUEUED)
|
|
if Legion then
|
|
is=self:GetLegionStatus(Legion)==OPSTRANSPORT.Status.QUEUED
|
|
end
|
|
return is
|
|
end
|
|
|
|
--- Check if state is REQUESTED.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.Legion#LEGION Legion (Optional) Check if transport is queued at this legion.
|
|
-- @return #boolean If true, status is REQUESTED.
|
|
function OPSTRANSPORT:IsRequested(Legion)
|
|
local is=self:is(OPSTRANSPORT.Status.REQUESTED)
|
|
if Legion then
|
|
is=self:GetLegionStatus(Legion)==OPSTRANSPORT.Status.REQUESTED
|
|
end
|
|
return is
|
|
end
|
|
|
|
--- Check if state is SCHEDULED.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @return #boolean If true, status is SCHEDULED.
|
|
function OPSTRANSPORT:IsScheduled()
|
|
local is=self:is(OPSTRANSPORT.Status.SCHEDULED)
|
|
return is
|
|
end
|
|
|
|
--- Check if state is EXECUTING.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @return #boolean If true, status is EXECUTING.
|
|
function OPSTRANSPORT:IsExecuting()
|
|
local is=self:is(OPSTRANSPORT.Status.EXECUTING)
|
|
return is
|
|
end
|
|
|
|
--- Check if all cargo was delivered (or is dead).
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #number Nmin Number of groups that must be actually delivered (and are not dead). Default 0.
|
|
-- @return #boolean If true, all possible cargo was delivered.
|
|
function OPSTRANSPORT:IsDelivered(Nmin)
|
|
local is=self:is(OPSTRANSPORT.Status.DELIVERED)
|
|
Nmin=Nmin or 0
|
|
if Nmin>self.Ncargo then
|
|
Nmin=self.Ncargo
|
|
end
|
|
if self.Ndelivered<Nmin then
|
|
is=false
|
|
end
|
|
return is
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Status Update
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- On after "StatusUpdate" event.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function OPSTRANSPORT:onafterStatusUpdate(From, Event, To)
|
|
|
|
-- Current FSM state.
|
|
local fsmstate=self:GetState()
|
|
|
|
if self.verbose>=1 then
|
|
|
|
-- Info text.
|
|
local text=string.format("%s: Ncargo=%d/%d, Ncarrier=%d/%d, Nlegions=%d", fsmstate:upper(), self.Ncargo, self.Ndelivered, #self.carriers, self.Ncarrier, #self.legions)
|
|
|
|
-- Info about cargo and carrier.
|
|
if self.verbose>=2 then
|
|
|
|
for i,_tz in pairs(self.tzCombos) do
|
|
local tz=_tz --#OPSTRANSPORT.TransportZoneCombo
|
|
local pickupzone=tz.PickupZone and tz.PickupZone:GetName() or "Unknown"
|
|
local deployzone=tz.DeployZone and tz.DeployZone:GetName() or "Unknown"
|
|
text=text..string.format("\n[%d] %s --> %s: Ncarriers=%d, Ncargo=%d (%d)", i, pickupzone, deployzone, tz.Ncarriers, #tz.Cargos, tz.Ncargo)
|
|
end
|
|
|
|
end
|
|
|
|
-- Info about cargo and carrier.
|
|
if self.verbose>=3 then
|
|
|
|
text=text..string.format("\nCargos:")
|
|
for _,_cargo in pairs(self:GetCargos()) do
|
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
|
local carrier=cargo.opsgroup:_GetMyCarrierElement()
|
|
local name=carrier and carrier.name or "none"
|
|
local cstate=carrier and carrier.status or "N/A"
|
|
text=text..string.format("\n- %s: %s [%s], weight=%d kg, carrier=%s [%s], delivered=%s [UID=%s]",
|
|
cargo.opsgroup:GetName(), cargo.opsgroup.cargoStatus:upper(), cargo.opsgroup:GetState(), cargo.opsgroup:GetWeightTotal(), name, cstate, tostring(cargo.delivered), tostring(cargo.opsgroup.cargoTransportUID))
|
|
end
|
|
|
|
text=text..string.format("\nCarriers:")
|
|
for _,_carrier in pairs(self.carriers) do
|
|
local carrier=_carrier --Ops.OpsGroup#OPSGROUP
|
|
text=text..string.format("\n- %s: %s [%s], Cargo Bay [current/reserved/total]=%d/%d/%d kg [free %d/%d/%d kg]",
|
|
carrier:GetName(), carrier.carrierStatus:upper(), carrier:GetState(),
|
|
carrier:GetWeightCargo(nil, false), carrier:GetWeightCargo(), carrier:GetWeightCargoMax(),
|
|
carrier:GetFreeCargobay(nil, false), carrier:GetFreeCargobay(), carrier:GetFreeCargobayMax())
|
|
end
|
|
end
|
|
|
|
self:I(self.lid..text)
|
|
end
|
|
|
|
-- Check if all cargo was delivered (or is dead).
|
|
self:_CheckDelivered()
|
|
|
|
-- Update status again.
|
|
if not self:IsDelivered() then
|
|
self:__StatusUpdate(-30)
|
|
end
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- FSM Event Functions
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- On after "Planned" event.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function OPSTRANSPORT:onafterPlanned(From, Event, To)
|
|
self:T(self.lid..string.format("New status: %s-->%s", From, To))
|
|
end
|
|
|
|
--- On after "Scheduled" event.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function OPSTRANSPORT:onafterScheduled(From, Event, To)
|
|
self:T(self.lid..string.format("New status: %s-->%s", From, To))
|
|
end
|
|
|
|
--- On after "Executing" event.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function OPSTRANSPORT:onafterExecuting(From, Event, To)
|
|
self:T(self.lid..string.format("New status: %s-->%s", From, To))
|
|
end
|
|
|
|
--- On before "Delivered" event.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function OPSTRANSPORT:onbeforeDelivered(From, Event, To)
|
|
|
|
-- Check that we do not call delivered again.
|
|
if From==OPSTRANSPORT.Status.DELIVERED then
|
|
return false
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
--- On after "Delivered" event.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function OPSTRANSPORT:onafterDelivered(From, Event, To)
|
|
self:T(self.lid..string.format("New status: %s-->%s", From, To))
|
|
|
|
-- Inform all assigned carriers that cargo was delivered. They can have this in the queue or are currently processing this transport.
|
|
for i=#self.carriers, 1, -1 do
|
|
local carrier=self.carriers[i] --Ops.OpsGroup#OPSGROUP
|
|
if self:GetCarrierTransportStatus(carrier)~=OPSTRANSPORT.Status.DELIVERED then
|
|
carrier:Delivered(self)
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
--- On after "Loaded" event.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCargo OPSGROUP that was loaded into a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCarrier OPSGROUP that was loaded into a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP.Element CarrierElement Carrier element.
|
|
function OPSTRANSPORT:onafterLoaded(From, Event, To, OpsGroupCargo, OpsGroupCarrier, CarrierElement)
|
|
self:I(self.lid..string.format("Loaded OPSGROUP %s into carrier %s", OpsGroupCargo:GetName(), tostring(CarrierElement.name)))
|
|
end
|
|
|
|
--- On after "Unloaded" event.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCargo Cargo OPSGROUP that was unloaded from a carrier.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroupCarrier Carrier OPSGROUP that unloaded the cargo.
|
|
function OPSTRANSPORT:onafterUnloaded(From, Event, To, OpsGroupCargo, OpsGroupCarrier)
|
|
self:I(self.lid..string.format("Unloaded OPSGROUP %s", OpsGroupCargo:GetName()))
|
|
end
|
|
|
|
--- On after "DeadCarrierGroup" event.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
-- @param Ops.OpsGroup#OPSGROUP OpsGroup Carrier OPSGROUP that is dead.
|
|
function OPSTRANSPORT:onafterDeadCarrierGroup(From, Event, To, OpsGroup)
|
|
self:I(self.lid..string.format("Carrier OPSGROUP %s dead!", OpsGroup:GetName()))
|
|
|
|
-- Increase dead counter.
|
|
self.NcarrierDead=self.NcarrierDead+1
|
|
|
|
if #self.carriers==0 then
|
|
self:DeadCarrierAll()
|
|
end
|
|
|
|
-- Remove group from carrier list/table.
|
|
self:_DelCarrier(OpsGroup)
|
|
end
|
|
|
|
--- On after "DeadCarrierAll" event.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function OPSTRANSPORT:onafterDeadCarrierAll(From, Event, To)
|
|
self:I(self.lid..string.format("ALL Carrier OPSGROUPs are dead! Setting stage to PLANNED if not all cargo was delivered."))
|
|
|
|
-- Check if cargo was delivered.
|
|
self:_CheckDelivered()
|
|
|
|
-- Set state back to PLANNED if not delivered.
|
|
if not self:IsDelivered() then
|
|
self:Planned()
|
|
end
|
|
end
|
|
|
|
--- On after "Cancel" event.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #string From From state.
|
|
-- @param #string Event Event.
|
|
-- @param #string To To state.
|
|
function OPSTRANSPORT:onafterCancel(From, Event, To)
|
|
|
|
-- Number of OPSGROUPS assigned and alive.
|
|
local Ngroups = #self.carriers
|
|
|
|
-- Debug info.
|
|
self:I(self.lid..string.format("CANCELLING transport in status %s. Will wait for %d carrier groups to report DONE before evaluation", self.status, Ngroups))
|
|
|
|
-- Time stamp.
|
|
self.Tover=timer.getAbsTime()
|
|
|
|
|
|
if self.chief then
|
|
|
|
-- Debug info.
|
|
self:T(self.lid..string.format("CHIEF will cancel the transport. Will wait for mission DONE before evaluation!"))
|
|
|
|
-- CHIEF will cancel the transport.
|
|
self.chief:TransportCancel(self)
|
|
|
|
elseif self.commander then
|
|
|
|
-- Debug info.
|
|
self:T(self.lid..string.format("COMMANDER will cancel the transport. Will wait for transport DELIVERED before evaluation!"))
|
|
|
|
-- COMMANDER will cancel the transport.
|
|
self.commander:TransportCancel(self)
|
|
|
|
elseif self.legions and #self.legions>0 then
|
|
|
|
-- Loop over all LEGIONs.
|
|
for _,_legion in pairs(self.legions or {}) do
|
|
local legion=_legion --Ops.Legion#LEGION
|
|
|
|
-- Debug info.
|
|
self:T(self.lid..string.format("LEGION %s will cancel the transport. Will wait for transport DELIVERED before evaluation!", legion.alias))
|
|
|
|
-- Legion will cancel all flight missions and remove queued request from warehouse queue.
|
|
legion:TransportCancel(self)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
-- Debug info.
|
|
self:T(self.lid..string.format("No legion, commander or chief. Attached OPS groups will cancel the transport on their own. Will wait for transport DELIVERED before evaluation!"))
|
|
|
|
-- Loop over all carrier groups.
|
|
for _,_carrier in pairs(self:GetCarriers()) do
|
|
local carrier=_carrier --Ops.OpsGroup#OPSGROUP
|
|
carrier:TransportCancel(self)
|
|
end
|
|
|
|
-- Delete awaited transport.
|
|
local cargos=self:GetCargoOpsGroups(false)
|
|
for _,_cargo in pairs(cargos) do
|
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP
|
|
cargo:_DelMyLift(self)
|
|
end
|
|
|
|
|
|
end
|
|
|
|
-- Special mission states.
|
|
if self:IsPlanned() or self:IsQueued() or self:IsRequested() or Ngroups==0 then
|
|
self:T(self.lid..string.format("Cancelled transport was in %s stage with %d carrier groups assigned and alive. Call it DELIVERED!", self.status, Ngroups))
|
|
self:Delivered()
|
|
end
|
|
|
|
end
|
|
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Misc Functions
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Check if all cargo of this transport assignment was delivered.
|
|
-- @param #OPSTRANSPORT self
|
|
function OPSTRANSPORT:_CheckDelivered()
|
|
|
|
-- First check that at least one cargo was added (as we allow to do that later).
|
|
if self.Ncargo>0 then
|
|
|
|
local done=true
|
|
local dead=true
|
|
for _,_cargo in pairs(self:GetCargos()) do
|
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
|
|
|
if cargo.delivered then
|
|
-- This one is delivered.
|
|
dead=false
|
|
elseif cargo.opsgroup==nil then
|
|
-- This one is nil?!
|
|
dead=false
|
|
elseif cargo.opsgroup:IsDestroyed() then
|
|
-- This one was destroyed.
|
|
elseif cargo.opsgroup:IsDead() then
|
|
-- This one is dead.
|
|
elseif cargo.opsgroup:IsStopped() then
|
|
-- This one is stopped.
|
|
dead=false
|
|
else
|
|
done=false --Someone is not done!
|
|
dead=false
|
|
end
|
|
|
|
end
|
|
|
|
if dead then
|
|
self:I(self.lid.."All cargo DEAD ==> Delivered!")
|
|
self:Delivered()
|
|
elseif done then
|
|
self:I(self.lid.."All cargo DONE ==> Delivered!")
|
|
self:Delivered()
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--- Check if all required cargos are loaded.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #boolean If true, all required cargos are loaded or there is no required cargo.
|
|
function OPSTRANSPORT:_CheckRequiredCargos(TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
local requiredCargos=TransportZoneCombo.RequiredCargos
|
|
|
|
if requiredCargos==nil or #requiredCargos==0 then
|
|
return true
|
|
end
|
|
|
|
local carrierNames=self:_GetCarrierNames()
|
|
|
|
local gotit=true
|
|
for _,_cargo in pairs(requiredCargos) do
|
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP
|
|
|
|
|
|
if not cargo:IsLoaded(carrierNames) then
|
|
return false
|
|
end
|
|
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
--- Check if all given condition are true.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param #table Conditions Table of conditions.
|
|
-- @return #boolean If true, all conditions were true. Returns false if at least one condition returned false.
|
|
function OPSTRANSPORT:EvalConditionsAll(Conditions)
|
|
|
|
-- Any stop condition must be true.
|
|
for _,_condition in pairs(Conditions or {}) do
|
|
local condition=_condition --#OPSTRANSPORT.Condition
|
|
|
|
-- Call function.
|
|
local istrue=condition.func(unpack(condition.arg))
|
|
|
|
-- Any false will return false.
|
|
if not istrue then
|
|
return false
|
|
end
|
|
|
|
end
|
|
|
|
-- All conditions were true.
|
|
return true
|
|
end
|
|
|
|
|
|
|
|
--- Find transfer carrier element for cargo group.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.OpsGroup#OPSGROUP CargoGroup The cargo group that needs to be loaded into a carrier unit/element of the carrier group.
|
|
-- @param Core.Zone#ZONE Zone (Optional) Zone where the carrier must be in.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return Ops.OpsGroup#OPSGROUP.Element New carrier element for cargo or nil.
|
|
-- @return Ops.OpsGroup#OPSGROUP New carrier group for cargo or nil.
|
|
function OPSTRANSPORT:FindTransferCarrierForCargo(CargoGroup, Zone, TransportZoneCombo)
|
|
|
|
-- Use default TZC if no transport zone combo is provided.
|
|
TransportZoneCombo=TransportZoneCombo or self.tzcDefault
|
|
|
|
local carrier=nil --Ops.OpsGroup#OPSGROUP.Element
|
|
local carrierGroup=nil --Ops.OpsGroup#OPSGROUP
|
|
|
|
--TODO: maybe sort the carriers wrt to largest free cargo bay. Or better smallest free cargo bay that can take the cargo group weight.
|
|
|
|
for _,_carrier in pairs(TransportZoneCombo.DisembarkCarriers) do
|
|
local carrierGroup=_carrier --Ops.OpsGroup#OPSGROUP
|
|
|
|
-- First check if carrier is alive and loading cargo.
|
|
if carrierGroup and carrierGroup:IsAlive() and (carrierGroup:IsLoading() or TransportZoneCombo.DeployAirbase) then
|
|
|
|
-- Find an element of the group that has enough free space.
|
|
carrier=carrierGroup:FindCarrierForCargo(CargoGroup)
|
|
|
|
if carrier then
|
|
if Zone==nil or Zone:IsVec2InZone(carrier.unit:GetVec2()) then
|
|
return carrier, carrierGroup
|
|
else
|
|
self:T2(self.lid.."Got transfer carrier but carrier not in zone (yet)!")
|
|
end
|
|
else
|
|
self:T2(self.lid.."No transfer carrier available!")
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
return nil, nil
|
|
end
|
|
|
|
--- Create a cargo group data structure.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Wrapper.Group#GROUP group The GROUP or OPSGROUP object.
|
|
-- @return Ops.OpsGroup#OPSGROUP.CargoGroup Cargo group data.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
function OPSTRANSPORT:_CreateCargoGroupData(group, TransportZoneCombo)
|
|
|
|
-- Get ops group.
|
|
local opsgroup=self:_GetOpsGroupFromObject(group)
|
|
|
|
-- First check that this group is not already contained in this TZC.
|
|
for _,_cargo in pairs(TransportZoneCombo.Cargos or {}) do
|
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
|
if cargo.opsgroup.groupname==opsgroup.groupname then
|
|
-- Group is already contained.
|
|
return nil
|
|
end
|
|
end
|
|
|
|
|
|
-- Create a new data item.
|
|
local cargo={} --Ops.OpsGroup#OPSGROUP.CargoGroup
|
|
|
|
cargo.opsgroup=opsgroup
|
|
cargo.delivered=false
|
|
cargo.status="Unknown"
|
|
cargo.disembarkCarrierElement=nil
|
|
cargo.disembarkCarrierGroup=nil
|
|
cargo.tzcUID=TransportZoneCombo
|
|
|
|
return cargo
|
|
end
|
|
|
|
--- Count how many cargo groups are inside a zone.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Core.Zone#ZONE Zone The zone object.
|
|
-- @param #boolean Delivered If `true`, only delivered groups are returned. If `false` only undelivered groups are returned. If `nil`, all groups are returned.
|
|
-- @param Ops.OpsGroup#OPSGROUP Carrier (Optional) Only count cargo groups that fit into the given carrier group. Current cargo is not a factor.
|
|
-- @param #OPSTRANSPORT.TransportZoneCombo TransportZoneCombo Transport zone combo.
|
|
-- @return #number Number of cargo groups.
|
|
function OPSTRANSPORT:_CountCargosInZone(Zone, Delivered, Carrier, TransportZoneCombo)
|
|
|
|
-- Get cargo ops groups.
|
|
local cargos=self:GetCargoOpsGroups(Delivered, Carrier, TransportZoneCombo)
|
|
|
|
--- Function to check if carrier is supposed to be disembarked to.
|
|
local function iscarrier(_cargo)
|
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP
|
|
|
|
local mycarrier=cargo:_GetMyCarrierGroup()
|
|
|
|
if mycarrier and mycarrier:IsUnloading() then
|
|
|
|
local carriers=mycarrier.cargoTransport:GetDisembarkCarriers(mycarrier.cargoTZC)
|
|
|
|
for _,_carrier in pairs(carriers) do
|
|
local carrier=_carrier --Ops.OpsGroup#OPSGROUP
|
|
if Carrier:GetName()==carrier:GetName() then
|
|
return true
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
local N=0
|
|
for _,_cargo in pairs(cargos) do
|
|
local cargo=_cargo --Ops.OpsGroup#OPSGROUP
|
|
|
|
-- Is not cargo?
|
|
local isNotCargo=cargo:IsNotCargo(true)
|
|
if not isNotCargo then
|
|
isNotCargo=iscarrier(cargo)
|
|
end
|
|
|
|
-- Is in zone?
|
|
local isInZone=cargo:IsInZone(Zone)
|
|
|
|
-- Is in utero?
|
|
local isInUtero=cargo:IsInUtero()
|
|
|
|
-- Debug info.
|
|
self:T(self.lid..string.format("Cargo=%s: notcargo=%s, iscarrier=%s inzone=%s, inutero=%s", cargo:GetName(), tostring(cargo:IsNotCargo(true)), tostring(iscarrier(cargo)), tostring(isInZone), tostring(isInUtero)))
|
|
|
|
-- We look for groups that are not cargo, in the zone or in utero.
|
|
if isNotCargo and (isInZone or isInUtero) then
|
|
N=N+1
|
|
end
|
|
end
|
|
|
|
-- Debug info.
|
|
self:T(self.lid..string.format("Found %d units in zone %s", N, Zone:GetName()))
|
|
|
|
return N
|
|
end
|
|
|
|
--- Get a transport zone combination (TZC) for a carrier group. The pickup zone will be a zone, where the most cargo groups are located that fit into the carrier.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Ops.OpsGroup#OPSGROUP Carrier The carrier OPS group.
|
|
-- @return Core.Zone#ZONE Pickup zone or `#nil`.
|
|
function OPSTRANSPORT:_GetTransportZoneCombo(Carrier)
|
|
|
|
--- Selection criteria
|
|
-- * Distance: pickup zone should be as close as possible.
|
|
-- * Ncargo: Number of cargo groups. Pickup, where there is most cargo.
|
|
-- * Ncarrier: Number of carriers already "working" on this TZC. Would be better if not all carriers work on the same combo while others are ignored.
|
|
|
|
-- Get carrier position.
|
|
local vec2=Carrier:GetVec2()
|
|
|
|
--- Penalty function.
|
|
local function penalty(candidate)
|
|
local p=candidate.ncarriers*10-candidate.ncargo+candidate.distance/10
|
|
return p
|
|
end
|
|
|
|
-- TZC candidates.
|
|
local candidates={}
|
|
|
|
for i,_transportzone in pairs(self.tzCombos) do
|
|
local tz=_transportzone --#OPSTRANSPORT.TransportZoneCombo
|
|
|
|
-- Check that pickup and deploy zones were defined.
|
|
if tz.PickupZone and tz.DeployZone and tz.EmbarkZone then
|
|
|
|
--TODO: Check if Carrier is an aircraft and if so, check that pickup AND deploy zones are airbases (not ships, not farps).
|
|
|
|
-- Count undelivered cargos in embark(!) zone that fit into the carrier.
|
|
local ncargo=self:_CountCargosInZone(tz.EmbarkZone, false, Carrier, tz)
|
|
|
|
-- At least one group in the zone.
|
|
if ncargo>=1 then
|
|
|
|
-- Distance to the carrier in meters.
|
|
local dist=tz.PickupZone:Get2DDistance(vec2)
|
|
|
|
local ncarriers=0
|
|
for _,_carrier in pairs(self.carriers) do
|
|
local carrier=_carrier --Ops.OpsGroup#OPSGROUP
|
|
if carrier and carrier:IsAlive() and carrier.cargoTZC and carrier.cargoTZC.uid==tz.uid then
|
|
ncarriers=ncarriers+1
|
|
end
|
|
end
|
|
|
|
-- New candidate.
|
|
local candidate={tzc=tz, distance=dist/1000, ncargo=ncargo, ncarriers=ncarriers}
|
|
|
|
-- Calculdate penalty of candidate.
|
|
candidate.penalty=penalty(candidate)
|
|
|
|
-- Add candidate.
|
|
table.insert(candidates, candidate)
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
if #candidates>0 then
|
|
|
|
-- Minimize penalty.
|
|
local function optTZC(candA, candB)
|
|
return candA.penalty<candB.penalty
|
|
end
|
|
table.sort(candidates, optTZC)
|
|
|
|
-- Debug output.
|
|
if self.verbose>=3 then
|
|
local text="TZC optimized"
|
|
for i,candidate in pairs(candidates) do
|
|
text=text..string.format("\n[%d] TPZ=%d, Ncarriers=%d, Ncargo=%d, Distance=%.1f km, PENALTY=%d", i, candidate.tzc.uid, candidate.ncarriers, candidate.ncargo, candidate.distance, candidate.penalty)
|
|
end
|
|
self:I(self.lid..text)
|
|
end
|
|
|
|
-- Return best candidate.
|
|
return candidates[1].tzc
|
|
else
|
|
-- No candidates.
|
|
self:T(self.lid..string.format("Could NOT find a pickup zone (with cargo) for carrier group %s", Carrier:GetName()))
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--- Get an OPSGROUP from a given OPSGROUP or GROUP object. If the object is a GROUUP, an OPSGROUP is created automatically.
|
|
-- @param #OPSTRANSPORT self
|
|
-- @param Core.Base#BASE Object The object, which can be a GROUP or OPSGROUP.
|
|
-- @return Ops.OpsGroup#OPSGROUP Ops Group.
|
|
function OPSTRANSPORT:_GetOpsGroupFromObject(Object)
|
|
|
|
local opsgroup=nil
|
|
|
|
if Object:IsInstanceOf("OPSGROUP") then
|
|
-- We already have an OPSGROUP
|
|
opsgroup=Object
|
|
elseif Object:IsInstanceOf("GROUP") then
|
|
|
|
-- Look into DB and try to find an existing OPSGROUP.
|
|
opsgroup=_DATABASE:GetOpsGroup(Object)
|
|
|
|
if not opsgroup then
|
|
if Object:IsAir() then
|
|
opsgroup=FLIGHTGROUP:New(Object)
|
|
elseif Object:IsShip() then
|
|
opsgroup=NAVYGROUP:New(Object)
|
|
else
|
|
opsgroup=ARMYGROUP:New(Object)
|
|
end
|
|
end
|
|
|
|
else
|
|
self:E(self.lid.."ERROR: Object must be a GROUP or OPSGROUP object!")
|
|
return nil
|
|
end
|
|
|
|
return opsgroup
|
|
end
|