OPSTRANSPORT

- New class.
This commit is contained in:
Frank 2021-02-15 23:19:35 +01:00
parent 084499fa0e
commit 5990ab1cc9
4 changed files with 273 additions and 51 deletions

View File

@ -83,6 +83,7 @@ __Moose.Include( 'Scripts/Moose/Ops/ArmyGroup.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Squadron.lua' )
__Moose.Include( 'Scripts/Moose/Ops/AirWing.lua' )
__Moose.Include( 'Scripts/Moose/Ops/Intelligence.lua' )
__Moose.Include( 'Scripts/Moose/Ops/OpsTransport.lua' )
__Moose.Include( 'Scripts/Moose/AI/AI_Balancer.lua' )
__Moose.Include( 'Scripts/Moose/AI/AI_Air.lua' )

View File

@ -582,7 +582,7 @@ function NAVYGROUP:onafterStatus(From, Event, To)
-- Recovery Windows
---
if self.verbose>=2 then
if self.verbose>=2 and #self.Qintowind>0 then
-- Debug output:
local text=string.format(self.lid.."Turn into wind time windows:")

View File

@ -375,7 +375,6 @@ OPSGROUP.TaskType={
--- Cargo Carrier status.
-- @type OPSGROUP.CarrierStatus
-- @field #string NOTCARRIER This group is not a carrier yet.
-- @field #string EMPTY Carrier is empty and ready for cargo transport.
-- @field #string PICKUP Carrier is on its way to pickup cargo.
-- @field #string LOADING Carrier is loading cargo.
-- @field #string LOADED Carrier has loaded cargo.
@ -383,7 +382,6 @@ OPSGROUP.TaskType={
-- @field #string UNLOADING Carrier is unloading cargo.
OPSGROUP.CarrierStatus={
NOTCARRIER="not carrier",
EMPTY="empty",
PICKUP="pickup",
LOADING="loading",
LOADED="loaded",
@ -394,18 +392,14 @@ OPSGROUP.CarrierStatus={
--- Cargo status.
-- @type OPSGROUP.CargoStatus
-- @field #string NOTCARGO This group is no cargo yet.
-- @field #string WAITING Cargo is awaiting transporter.
-- @field #string ASSIGNED Cargo is assigned to a carrier.
-- @field #string BOARDING Cargo is boarding a carrier.
-- @field #string LOADED Cargo is loaded into a carrier.
-- @field #string DELIVERED Cargo was delivered at its destination.
OPSGROUP.CargoStatus={
NOTCARGO="not cargo",
WAITING="waiting for carrier",
ASSIGNED="assigned to carrier",
BOARDING="boarding",
LOADED="loaded",
DELIVERED="delivered",
}
--- Cargo transport status.
@ -1023,6 +1017,17 @@ end
-- @return DCS#Vec3 Vector with x,y,z components.
function OPSGROUP:GetVec3(UnitName)
local vec3=nil --DCS#Vec3
-- First check if this group is loaded into a carrier
if self.carrier and self.carrier.status~=OPSGROUP.ElementStatus.DEAD and self:IsLoaded() then
local unit=self.carrier.unit
if unit and unit:IsAlive()~=nil then
vec3=unit:GetVec3()
return vec3
end
end
if self:IsExist() then
local unit=nil --DCS#Unit
@ -1049,18 +1054,8 @@ end
-- @return Core.Point#COORDINATE The coordinate (of the first unit) of the group.
function OPSGROUP:GetCoordinate(NewObject)
local vec3=nil --DCS#Vec3
local vec3=self:GetVec3() or self.position --DCS#Vec3
-- TODO: get vec3 of carrier group. move this stuff to GetVec3
if self.carrier and self.carrier.status~=OPSGROUP.ElementStatus.DEAD then
-- Get the carrier position.
vec3=self.carrier.unit:GetVec3()
else
self:GetVec3()
end
vec3=vec3 or self.position
if vec3 then
self.coordinate=self.coordinate or COORDINATE:New(0,0,0)
@ -4646,16 +4641,7 @@ function OPSGROUP:_CheckCargoTransport()
self:I(self.lid.."Cargo queue:"..text)
end
end
-- Loop over cargo queue and check if everything was delivered.
for i=#self.cargoqueue,1,-1 do
local transport=self.cargoqueue[i] --#OPSGROUP.CargoTransport
local delivered=self:_CheckDelivered(transport)
if delivered then
self:Delivered(transport)
end
end
-- Check if there is anything in the queue.
if not self.cargoTransport then
self.cargoTransport=self:_GetNextCargoTransport()
@ -4696,12 +4682,12 @@ function OPSGROUP:_CheckCargoTransport()
elseif self:IsLoading() then
-- Debug info.
self:I(self.lid.."Loading...")
-- Set loading time stamp.
--TODO: Check max loading time. If exceeded ==> abort transport.
self.Tloading=self.Tloading or Time
self.Tloading=self.Tloading or Time
-- Debug info.
self:I(self.lid.."Loading...")
local boarding=false
local gotcargo=false
@ -4763,6 +4749,15 @@ function OPSGROUP:_CheckCargoTransport()
end
end
-- Loop over cargo queue and check if everything was delivered.
for i=#self.cargoqueue,1,-1 do
local transport=self.cargoqueue[i] --#OPSGROUP.CargoTransport
local delivered=self:_CheckDelivered(transport)
if delivered then
self:Delivered(transport)
end
end
return self
end
@ -4773,6 +4768,8 @@ end
-- @param #OPSGROUP.Element CarrierElement The element of the carrier.
function OPSGROUP:_AddCargobay(CargoGroup, CarrierElement)
--TODO: Check group is not already in cargobay of this carrier or any other carrier.
-- Cargo weight.
local weight=CargoGroup:GetWeightTotal()
@ -4789,6 +4786,7 @@ end
-- @param #OPSGROUP self
-- @param #OPSGROUP CargoGroup Cargo group.
-- @param #OPSGROUP.Element CarrierElement The element of the carrier.
-- @return #boolean If `true`, cargo could be removed.
function OPSGROUP:_DelCargobay(CargoGroup, CarrierElement)
if self.cargoBay[CargoGroup.groupname] then
@ -4799,11 +4797,12 @@ function OPSGROUP:_DelCargobay(CargoGroup, CarrierElement)
-- Reduce carrier weight.
local weight=CargoGroup:GetWeightTotal()
self:RedWeightCargo(CargoGroup.carrier.name, weight)
else
env.error("ERROR: Group is not in cargo bay. Cannot remove it!")
return true
end
env.error(self.lid.."ERROR: Group is not in cargo bay. Cannot remove it!")
return false
end
--- Get cargo transport from cargo queue.
@ -4840,7 +4839,7 @@ function OPSGROUP:_GetNextCargoTransport()
for _,_cargotransport in pairs(self.cargoqueue) do
local cargotransport=_cargotransport --#OPSGROUP.CargoTransport
if Time>=cargotransport.Tstart and cargotransport.status==OPSGROUP.TransportStatus.SCHEDULED and (cargotransport.importance==nil or cargotransport.importance<=vip) then
if Time>=cargotransport.Tstart and cargotransport.status==OPSGROUP.TransportStatus.SCHEDULED and (cargotransport.importance==nil or cargotransport.importance<=vip) and not self:_CheckDelivered(cargotransport) then
cargotransport.status=OPSGROUP.TransportStatus.EXECUTING
return cargotransport
end
@ -4887,11 +4886,11 @@ end
-- @param Core.Zone#ZONE Embarkzone (Optional) Zone where the cargo is going to be embarked into the transport. By default is goes to the assigned carrier unit.
-- @param Core.Zone#ZONE Disembarkzone (Optional) Zone where the cargo disembarks to (is spawned after unloaded). Default is anywhere in the deploy zone.
-- @param #OPSGROUP DisembarkCarrierGroup (Optional) The OPSGROUP where the cargo is directly loaded into.
-- @return #OPSGROUP.CargoTransport Cargo transport.
-- @return Ops.OpsTransport#OPSTRANSPORT Cargo transport.
function OPSGROUP:AddCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, Importance, ClockStart, Embarkzone, Disembarkzone, DisembarkCarrierGroup)
-- Create a new cargo transport assignment.
local cargotransport=self:CreateCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, Importance, ClockStart, Embarkzone, Disembarkzone, DisembarkCarrierGroup)
local cargotransport=OPSTRANSPORT:New(GroupSet, Pickupzone, Deployzone)
if cargotransport then
@ -4906,6 +4905,19 @@ function OPSGROUP:AddCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, Impo
return cargotransport
end
--- Create a cargo transport assignment.
-- @param #OPSGROUP self
-- @param Ops.OpsTransport#OPSTRANSPORT OpsTransport The troop transport assignment.
function OPSGROUP:AddOpsTransport(OpsTransport)
-- Set state to SCHEDULED.
OpsTransport.status=OPSTRANSPORT.Status.SCHEDULED
--Add to cargo queue
table.insert(self.cargoqueue, OpsTransport)
end
--- Delete a cargo transport assignment from the cargo queue
-- @param #OPSGROUP self
-- @param #OPSGROUP.CargoTransport CargoTransport Cargo transport do be deleted.
@ -5468,7 +5480,7 @@ function OPSGROUP:onafterLoaded(From, Event, To)
env.info("FF loaded")
-- Cancel landedAt task.
if self.isFlightgroup and self:IsLandedAt() then
if self:IsFlightgroup() and self:IsLandedAt() then
local Task=self:GetTaskCurrent()
self:TaskCancel(Task)
end
@ -5661,12 +5673,12 @@ function OPSGROUP:onafterUnloading(From, Event, To)
local zoneCarrier=ZONE_RADIUS:New("Carrier", self:GetVec2(), 100)
-- Random coordinate/heading in the zone.
local Coordinate=zoneCarrier:GetRandomCoordinate(20)
local Coordinate=zoneCarrier:GetRandomCoordinate(50)
local Heading=math.random(0,359)
-- Unload.
env.info("FF unload cargo "..cargo.opsgroup:GetName())
self:Unload(cargo.opsgroup, Coordinate, Heading)
self:Unload(cargo.opsgroup, Coordinate, nil, Heading)
else
env.info("FF unload cargo Inactive "..cargo.opsgroup:GetName())
self:Unload(cargo.opsgroup)
@ -5700,9 +5712,9 @@ end
-- @param #string To To state.
-- @param #OPSGROUP OpsGroup The OPSGROUP loaded as cargo.
-- @param Core.Point#COORDINATE Coordinate Coordinate were the group is unloaded to.
-- @param #number Heading Heading of group.
-- @param #boolean Activated If `true`, group is active. If `false`, group is spawned in late activated state.
function OPSGROUP:onafterUnload(From, Event, To, OpsGroup, Coordinate, Heading, Activated)
-- @param #number Heading (Optional) Heading of group in degrees. Default is random heading for each unit.
function OPSGROUP:onafterUnload(From, Event, To, OpsGroup, Coordinate, Activated, Heading)
-- Remove group from carrier bay.
self:_DelCargobay(OpsGroup)
@ -5713,10 +5725,6 @@ function OPSGROUP:onafterUnload(From, Event, To, OpsGroup, Coordinate, Heading,
-- Set cargo status.
OpsGroup.cargoStatus=OPSGROUP.CargoStatus.NOTCARGO
-- No carrier.
OpsGroup.carrier=nil
OpsGroup.carrierGroup=nil
if Coordinate then
---
@ -5776,7 +5784,11 @@ function OPSGROUP:onafterUnload(From, Event, To, OpsGroup, Coordinate, Heading,
end
-- Trigger "Disembarked" event.
OpsGroup:Disembarked()
OpsGroup:Disembarked(OpsGroup.carrierGroup, OpsGroup.carrier)
-- No carrier any more.
OpsGroup.carrier=nil
OpsGroup.carrierGroup=nil
end
@ -5790,7 +5802,7 @@ function OPSGROUP:onafterUnloaded(From, Event, To)
self:I(self.lid.."Cargo unloaded..")
-- Cancel landedAt task.
if self.isFlightgroup and self:IsLandedAt() then
if self:IsFlightgroup() and self:IsLandedAt() then
local Task=self:GetTaskCurrent()
self:TaskCancel(Task)
end
@ -5801,13 +5813,13 @@ function OPSGROUP:onafterUnloaded(From, Event, To)
if not delivered then
-- Pickup the next batch.
self:I(self.lid.."Still cargo left ==> pickup")
self:I(self.lid.."Unloaded: Still cargo left ==> Pickup")
self:Pickup(self.cargoTransport.pickupzone)
else
-- Everything delivered.
self:I(self.lid.."Still ALL unloaded ==> delivered")
self:I(self.lid.."Unloaded: ALL cargo unloaded ==> Delivered (current)")
self:Delivered(self.cargoTransport)
end

View File

@ -0,0 +1,209 @@
--- **Ops** - Troop transport assignment of OPS groups.
--
-- ## Main Features:
--
-- * Patrol waypoints *ad infinitum*
--
-- ===
--
-- ## Example Missions:
--
-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/OPS%20-%20Armygroup).
--
-- ===
--
-- ### Author: **funkyfranky**
--
-- ==
--
-- @module Ops.OpsTransport
-- @image OPS_OpsTransport.png
--- OPSTRANSPORT class.
-- @type OPSTRANSPORT
-- @field #string ClassName Name of the class.
-- @field #table cargos Cargos. Each element is a @{#OPSGROUP.Cargo}.
-- @field #string status Status of the transport. See @{#OPSTRANSPORT.Status}.
-- @field #number prio Priority of this transport. Should be a number between 0 (high prio) and 100 (low prio).
-- @field #number importance Importance of this transport. Smaller=higher.
-- @field #number Tstart Start time in *abs.* seconds.
-- @field Core.Zone#ZONE pickupzone Zone where the cargo is picked up.
-- @field Core.Zone#ZONE deployzone Zone where the cargo is dropped off.
-- @field Core.Zone#ZONE embarkzone (Optional) Zone where the cargo is supposed to embark. Default is the pickup zone.
-- @field Core.Zone#ZONE disembarkzone (Optional) Zone where the cargo is disembarked. Default is the deploy zone.
-- @field Ops.OpsGroup#OPSGROUP carrierGroup The new carrier group.
-- @extends Core.Fsm#FSM
--- *Your soul may belong to Jesus, but your ass belongs to the marines.* -- Eugene B. Sledge
--
-- ===
--
-- ![Banner Image](..\Presentations\OPS\ArmyGroup\_Main.png)
--
-- # The OPSTRANSPORT Concept
--
-- This class enhances naval groups.
--
-- @field #OPSTRANSPORT
OPSTRANSPORT = {
ClassName = "OPSTRANSPORT",
verbose = 1,
cargos = {},
}
--- Cargo transport status.
-- @type OPSTRANSPORT.Status
-- @field #string PLANNING Planning state.
-- @field #string SCHEDULED Transport is scheduled in the cargo queue.
-- @field #string EXECUTING Transport is being executed.
-- @field #string DELIVERED Transport was delivered.
OPSTRANSPORT.Status={
PLANNING="planning",
SCHEDULED="scheduled",
EXECUTING="executing",
DELIVERED="delivered",
}
_OPSTRANSPORTID=0
--- Army Group version.
-- @field #string version
OPSTRANSPORT.version="0.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: A lot.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 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 GroupSet Set of groups to be transported. 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(GroupSet, Pickupzone, Deployzone)
-- Inherit everything from FSM class.
local self=BASE:Inherit(self, FSM:New()) -- #OPSTRANSPORT
-- Set some string id for output to DCS.log file.
self.lid=string.format("OPSTRANSPORT %s --> %s | ", Pickupzone:GetName(), Deployzone:GetName())
_OPSTRANSPORTID=_OPSTRANSPORTID+1
self.uid=_OPSTRANSPORTID
self.status=OPSTRANSPORT.Status.PLANNING
self.pickupzone=Pickupzone
self.deployzone=Deployzone
self.embarkzone=Pickupzone
self.disembarkzone=Deployzone
self.prio=50
self.importance=nil
self.Tstart=timer.getAbsTime()
self.carrierGroup=nil
self.cargos={}
-- Check type of GroupSet provided.
if GroupSet:IsInstanceOf("GROUP") or GroupSet:IsInstanceOf("OPSGROUP") then
-- We got a single GROUP or OPSGROUP objectg.
local cargo=self:CreateCargoGroupData(GroupSet, Pickupzone, Deployzone)
if cargo then --and self:CanCargo(cargo.opsgroup)
table.insert(self.cargos, cargo)
end
else
-- We got a SET_GROUP object.
for _,group in pairs(GroupSet.Set) do
local cargo=self:_CreateCargoGroupData(group, Pickupzone, Deployzone)
if cargo then --and self:CanCargo(cargo.opsgroup) then
table.insert(self.cargos, cargo)
end
end
end
-- Debug info.
if self.verbose>=0 then
local text=string.format("Created Cargo Transport (UID=%d) from %s(%s) --> %s(%s)",
self.uid, self.pickupzone:GetName(), self.embarkzone:GetName(), self.deployzone:GetName(), self.disembarkzone:GetName())
local Weight=0
for _,_cargo in pairs(self.cargos) do
local cargo=_cargo --#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.cargos, Weight)
self:I(self.lid..text)
end
return self
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- User Functions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create a new OPSTRANSPORT class object.
-- @param #OPSTRANSPORT self
-- @param Core.Zone#ZONE EmbarkZone Zone where the troops are embarked.
-- @return #OPSTRANSPORT self
function OPSTRANSPORT:SetEmbarkZone(EmbarkZone)
self.embarkzone=EmbarkZone or self.pickupzone
return self
end
--- Create a cargo group data structure.
-- @param #OPSTRANSPORT self
-- @param Wrapper.Group#GROUP group The GROUP object.
-- @param Core.Zone#ZONE Pickupzone Pickup zone.
-- @param Core.Zone#ZONE Deployzone Deploy zone.
-- @return #OPSGROUP.CargoGroup Cargo group data.
function OPSTRANSPORT:_CreateCargoGroupData(group, Pickupzone, Deployzone)
local opsgroup=nil
if group:IsInstanceOf("OPSGROUP") then
opsgroup=group
else
opsgroup=_DATABASE:GetOpsGroup(group)
if not opsgroup then
if group:IsAir() then
opsgroup=FLIGHTGROUP:New(group)
elseif group:IsShip() then
opsgroup=NAVYGROUP:New(group)
else
opsgroup=ARMYGROUP:New(group)
end
else
--env.info("FF found opsgroup in createcargo")
end
end
local cargo={} --#OPSGROUP.CargoGroup
cargo.opsgroup=opsgroup
cargo.delivered=false
cargo.status="Unknown"
cargo.pickupzone=Pickupzone
cargo.deployzone=Deployzone
return cargo
end