OPS Transport

- Improved cargo bay weight calculation.
This commit is contained in:
Frank 2021-06-28 13:17:55 +02:00
parent a861f8d9d4
commit b012c5b2aa
2 changed files with 234 additions and 61 deletions

View File

@ -219,6 +219,7 @@ OPSGROUP = {
-- @field #number weightMaxCargo Max. cargo weight in kg. -- @field #number weightMaxCargo Max. cargo weight in kg.
-- @field #number weightCargo Current cargo weight in kg. -- @field #number weightCargo Current cargo weight in kg.
-- @field #number weight Current weight including cargo in kg. -- @field #number weight Current weight including cargo in kg.
-- @field #table cargoBay Cargo bay.
--- Status of group element. --- Status of group element.
-- @type OPSGROUP.ElementStatus -- @type OPSGROUP.ElementStatus
@ -420,12 +421,17 @@ OPSGROUP.CargoStatus={
-- @field #number length Length of (un-)loading zone in meters. -- @field #number length Length of (un-)loading zone in meters.
-- @field #number width Width of (un-)loading zone in meters. -- @field #number width Width of (un-)loading zone in meters.
--- Cargo transport data. --- Data of the carrier that has loaded this group.
-- @type OPSGROUP.MyCarrier -- @type OPSGROUP.MyCarrier
-- @field #OPSGROUP group The carrier group. -- @field #OPSGROUP group The carrier group.
-- @field #OPSGROUP.Element element The carrier element. -- @field #OPSGROUP.Element element The carrier element.
-- @field #boolean reserved If `true`, the carrier has caro space reserved for me. -- @field #boolean reserved If `true`, the carrier has caro space reserved for me.
--- Element cargo bay data.
-- @type OPSGROUP.MyCargo
-- @field #OPSGROUP group The cargo group.
-- @field #boolean reserved If `true`, the cargo bay space is reserved but cargo has not actually been loaded yet.
--- Cargo group data. --- Cargo group data.
-- @type OPSGROUP.CargoGroup -- @type OPSGROUP.CargoGroup
-- @field #OPSGROUP opsgroup The cargo opsgroup. -- @field #OPSGROUP opsgroup The cargo opsgroup.
@ -4562,6 +4568,7 @@ function OPSGROUP:onafterElementDead(From, Event, To, Element)
end end
-- Check cargo bay and declare cargo groups dead. -- Check cargo bay and declare cargo groups dead.
--[[
for groupname, carriername in pairs(self.cargoBay or {}) do for groupname, carriername in pairs(self.cargoBay or {}) do
if Element.name==carriername then if Element.name==carriername then
local opsgroup=_DATABASE:GetOpsGroup(groupname) local opsgroup=_DATABASE:GetOpsGroup(groupname)
@ -4578,6 +4585,26 @@ function OPSGROUP:onafterElementDead(From, Event, To, Element)
end end
end end
end end
]]
-- Check cargo bay and declare cargo groups dead.
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
for _,_cargo in pairs(element.cargoBay) do
local cargo=_cargo --#OPSGROUP.MyCargo
if cargo.group and not (cargo.group:IsDead() or cargo.group:IsStopped()) then
for _,cargoelement in pairs(cargo.group.elements) do
-- Debug info.
self:T2(self.lid.."Cargo element dead "..cargoelement.name)
-- Trigger dead event.
cargo.group:ElementDead(cargoelement)
end
end
end
end
if self:IsCarrier() then if self:IsCarrier() then
if self.cargoTransport then if self.cargoTransport then
@ -4800,6 +4827,7 @@ function OPSGROUP:_CheckCargoTransport()
local Time=timer.getAbsTime() local Time=timer.getAbsTime()
-- Cargo bay debug info. -- Cargo bay debug info.
--[[
if self.verbose>=3 then if self.verbose>=3 then
local text="" local text=""
for cargogroupname, carriername in pairs(self.cargoBay) do for cargogroupname, carriername in pairs(self.cargoBay) do
@ -4809,6 +4837,22 @@ function OPSGROUP:_CheckCargoTransport()
self:I(self.lid.."Cargo bay:"..text) self:I(self.lid.."Cargo bay:"..text)
end end
end end
]]
-- Check cargo bay and declare cargo groups dead.
if self.verbose>=0 then
local text=""
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
for _,_cargo in pairs(element.cargoBay) do
local cargo=_cargo --#OPSGROUP.MyCargo
text=text..string.format("\n- %s in carrier %s, reserved=%s", tostring(cargo.group:GetName()), tostring(element.name), tostring(cargo.reserved))
end
end
if text~="" then
self:I(self.lid.."Cargo bay:"..text)
end
end
-- Cargo queue debug info. -- Cargo queue debug info.
if self.verbose>=3 then if self.verbose>=3 then
@ -4958,49 +5002,157 @@ function OPSGROUP:_CheckCargoTransport()
return self return self
end end
--- Check if a group is in the cargo bay.
-- @param #OPSGROUP self
-- @param #OPSGROUP OpsGroup Group to check.
-- @return #boolean If `true`, group is in the cargo bay.
function OPSGROUP:_IsInCargobay(OpsGroup)
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
for _,_cargo in pairs(element.cargoBay) do
local cargo=_cargo --#OPSGROUP.MyCargo
if cargo.group.groupname==OpsGroup.groupname then
return true
end
end
end
return false
end
--- Add OPSGROUP to cargo bay of a carrier. --- Add OPSGROUP to cargo bay of a carrier.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #OPSGROUP CargoGroup Cargo group. -- @param #OPSGROUP CargoGroup Cargo group.
-- @param #OPSGROUP.Element CarrierElement The element of the carrier. -- @param #OPSGROUP.Element CarrierElement The element of the carrier.
function OPSGROUP:_AddCargobay(CargoGroup, CarrierElement) -- @param #boolean Reserved Only reserve the cargo bay space.
function OPSGROUP:_AddCargobay(CargoGroup, CarrierElement, Reserved)
--TODO: Check group is not already in cargobay of this carrier or any other carrier. --TODO: Check group is not already in cargobay of this carrier or any other carrier.
local cargo=self:_GetCargobay(CargoGroup)
if cargo then
cargo.reserved=Reserved
else
cargo={} --#OPSGROUP.MyCargo
cargo.group=CargoGroup
cargo.reserved=Reserved
table.insert(CarrierElement.cargoBay, cargo)
end
-- Set my carrier.
CargoGroup:_SetMyCarrier(self, CarrierElement, Reserved)
-- Fill cargo bay (obsolete).
self.cargoBay[CargoGroup.groupname]=CarrierElement.name
if not Reserved then
-- Cargo weight. -- Cargo weight.
local weight=CargoGroup:GetWeightTotal() local weight=CargoGroup:GetWeightTotal()
-- Add weight to carrier. -- Add weight to carrier.
self:AddWeightCargo(CarrierElement.name, weight) self:AddWeightCargo(CarrierElement.name, weight)
-- Fill cargo bay. end
self.cargoBay[CargoGroup.groupname]=CarrierElement.name
return self return self
end end
--- Get cargo bay item.
-- @param #OPSGROUP self
-- @param #OPSGROUP CargoGroup Cargo group.
-- @return #OPSGROUP.MyCargo Cargo bay item or `nil` if the group is not in the carrier.
-- @return #number CargoBayIndex Index of item in the cargo bay table.
-- @return #OPSGROUP.Element Carrier element.
function OPSGROUP:_GetCargobay(CargoGroup)
-- Loop over elements and their cargo bay items.
local CarrierElement=nil --#OPSGROUP.Element
local cargobayIndex=nil
local reserved=nil
for i,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
for j,_cargo in pairs(element.cargoBay) do
local cargo=_cargo --#OPSGROUP.MyCargo
if cargo.group and cargo.group.groupname==CargoGroup.groupname then
return cargo, j, element
end
end
end
return nil, nil, nil
end
--- Remove OPSGROUP from cargo bay of a carrier. --- Remove OPSGROUP from cargo bay of a carrier.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #OPSGROUP CargoGroup Cargo group. -- @param #OPSGROUP CargoGroup Cargo group.
-- @param #OPSGROUP.Element CarrierElement The element of the carrier.
-- @return #boolean If `true`, cargo could be removed. -- @return #boolean If `true`, cargo could be removed.
function OPSGROUP:_DelCargobay(CargoGroup, CarrierElement) function OPSGROUP:_DelCargobay(CargoGroup)
if self.cargoBay[CargoGroup.groupname] then if self.cargoBay[CargoGroup.groupname] then
-- Not in cargo bay any more. -- Not in cargo bay any more.
self.cargoBay[CargoGroup.groupname]=nil self.cargoBay[CargoGroup.groupname]=nil
-- Reduce carrier weight. end
local weight=CargoGroup:GetWeightTotal()
-- Get carrier of group. --[[
local carrier=CargoGroup:_GetMyCarrierElement() local MyCarrierGroup, MyCarrierElement, MyIsReserved=CargoGroup:_GetMyCarrier()
if carrier then if MyCarrierGroup and MyCarrierGroup.groupname==self.groupname then
self:RedWeightCargo(carrier.name, weight) if not IsReserved then
-- Reduce carrier weight.
local weight=CargoGroup:GetWeightTotal()
self:RedWeightCargo(CarrierElement.name, weight)
end
end
]]
-- Loop over elements and their cargo bay items.
--[[
local CarrierElement=nil --#OPSGROUP.Element
local cargobayIndex=nil
local reserved=nil
for i,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element
for j,_cargo in pairs(element.cargoBay) do
local cargo=_cargo --#OPSGROUP.MyCargo
if cargo.group and cargo.group.groupname==CargoGroup.groupname then
CarrierElement=element
cargobayIndex=j
reserved=cargo.reserved
end
end
end
]]
local cargoBayItem, cargoBayIndex, CarrierElement=self:_GetCargobay(CargoGroup)
if cargoBayItem and cargoBayIndex then
-- Remove
table.remove(CarrierElement.cargoBay, cargoBayIndex)
-- Reduce weight (if cargo space was not just reserved).
if not cargoBayItem.reserved then
local weight=CargoGroup:GetWeightTotal()
self:RedWeightCargo(CarrierElement.name, weight)
end end
return true return true
end end
env.error(self.lid.."ERROR: Group is not in cargo bay. Cannot remove it!") env.error(self.lid.."ERROR: Group is not in cargo bay. Cannot remove it!")
@ -5117,11 +5269,12 @@ function OPSGROUP:DelCargoTransport(CargoTransport)
end end
--- Get total weight of the group including cargo. --- Get total weight of the group including cargo. Optionally, the total weight of a specific unit can be requested.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #string UnitName Name of the unit. Default is of the whole group. -- @param #string UnitName Name of the unit. Default is of the whole group.
-- @param #boolean IncludeReserved If `false`, cargo weight that is only *reserved* is **not** counted. By default (`true` or `nil`), the reserved cargo is included.
-- @return #number Total weight in kg. -- @return #number Total weight in kg.
function OPSGROUP:GetWeightTotal(UnitName) function OPSGROUP:GetWeightTotal(UnitName, IncludeReserved)
local weight=0 local weight=0
for _,_element in pairs(self.elements) do for _,_element in pairs(self.elements) do
@ -5129,7 +5282,21 @@ function OPSGROUP:GetWeightTotal(UnitName)
if (UnitName==nil or UnitName==element.name) and element.status~=OPSGROUP.ElementStatus.DEAD then if (UnitName==nil or UnitName==element.name) and element.status~=OPSGROUP.ElementStatus.DEAD then
weight=weight+element.weight weight=weight+element.weightEmpty
for _,_cargo in pairs(element.cargoBay) do
local cargo=_cargo --#OPSGROUP.MyCargo
local wcargo=0
-- Count cargo that is not reserved or if reserved cargo should be included.
if (not cargo.reserved) or (cargo.reserved==true and (IncludeReserved==true or IncludeReserved==nil)) then
wcargo=cargo.group:GetWeightTotal(element.name)
end
weight=weight+wcargo
end
end end
@ -5141,24 +5308,15 @@ end
--- Get free cargo bay weight. --- Get free cargo bay weight.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #string UnitName Name of the unit. Default is of the whole group. -- @param #string UnitName Name of the unit. Default is of the whole group.
-- @param #boolean IncludeReserved If `false`, cargo weight that is only *reserved* is **not** counted. By default (`true` or `nil`), the reserved cargo is included.
-- @return #number Free cargo bay in kg. -- @return #number Free cargo bay in kg.
function OPSGROUP:GetFreeCargobay(UnitName) function OPSGROUP:GetFreeCargobay(UnitName, IncludeReserved)
local Free=0 local weightCargoMax=self:GetWeightCargoMax(UnitName)
for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element local weightCargo=self:GetWeightCargo(UnitName, IncludeReserved)
if (UnitName==nil or UnitName==element.name) and element.status~=OPSGROUP.ElementStatus.DEAD then local Free=weightCargoMax-weightCargo
local free=element.weightMaxCargo-element.weightCargo
--[[
for _,_opsgroup in pairs(element.reservedCargos or {}) do
local opsgroup=_opsgroup --#OPSGROUP
free=free-opsgroup:GetWeightTotal()
end
]]
Free=Free+free
end
end
self:I(self.lid..string.format("Free cargo bay=%d kg (unit=%s)", Free, (UnitName or "whole group"))) self:I(self.lid..string.format("Free cargo bay=%d kg (unit=%s)", Free, (UnitName or "whole group")))
return Free return Free
@ -5198,8 +5356,9 @@ end
--- Get weight of the internal cargo the group is carriing right now. --- Get weight of the internal cargo the group is carriing right now.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #string UnitName Name of the unit. Default is of the whole group. -- @param #string UnitName Name of the unit. Default is of the whole group.
-- @param #boolean IncludeReserved If `false`, cargo weight that is only *reserved* is **not** counted. By default (`true` or `nil`), the reserved cargo is included.
-- @return #number Cargo weight in kg. -- @return #number Cargo weight in kg.
function OPSGROUP:GetWeightCargo(UnitName) function OPSGROUP:GetWeightCargo(UnitName, IncludeReserved)
local weight=0 local weight=0
for _,_element in pairs(self.elements) do for _,_element in pairs(self.elements) do
@ -5213,34 +5372,36 @@ function OPSGROUP:GetWeightCargo(UnitName)
end end
local gewicht=0 local gewicht=0
for groupname, carriername in pairs(self.cargoBay) do for _,_element in pairs(self.elements) do
local element=self:GetElementByName(carriername) local element=_element --#OPSGROUP.Element
if (UnitName==nil or UnitName==carriername) and (element and element.status~=OPSGROUP.ElementStatus.DEAD) then if (UnitName==nil or UnitName==element.name) and (element and element.status~=OPSGROUP.ElementStatus.DEAD) then
local opsgroup=_DATABASE:FindOpsGroup(groupname) for _,_cargo in pairs(element.cargoBay) do
if opsgroup then local cargo=_cargo --#OPSGROUP.MyCargo
gewicht=gewicht+opsgroup:GetWeightTotal() if (not cargo.reserved) or (cargo.reserved==true and (IncludeReserved==true or IncludeReserved==nil)) then
gewicht=gewicht+cargo.group:GetWeightTotal()
end
end end
end end
end end
if IncludeReserved==false and gewicht~=weight then
if gewicht~=weight then
self:I(self.lid..string.format("ERROR: FF weight!=gewicht: weight=%.1f, gewicht=%.1f", weight, gewicht)) self:I(self.lid..string.format("ERROR: FF weight!=gewicht: weight=%.1f, gewicht=%.1f", weight, gewicht))
end end
return weight return gewicht
end end
--- Get max weight of the internal cargo the group can carry. --- Get max weight of the internal cargo the group can carry. Optionally, the max cargo weight of a specific unit can be requested.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @return #number Cargo weight in kg. -- @param #string UnitName Name of the unit. Default is of the whole group.
function OPSGROUP:GetWeightCargoMax() -- @return #number Max cargo weight in kg. This does **not** include any cargo loaded or reserved currently.
function OPSGROUP:GetWeightCargoMax(UnitName)
local weight=0 local weight=0
for _,_element in pairs(self.elements) do for _,_element in pairs(self.elements) do
local element=_element --#OPSGROUP.Element local element=_element --#OPSGROUP.Element
if element.status~=OPSGROUP.ElementStatus.DEAD then if (UnitName==nil or UnitName==element.name) and element.status~=OPSGROUP.ElementStatus.DEAD then
weight=weight+element.weightMaxCargo weight=weight+element.weightMaxCargo
@ -5263,6 +5424,9 @@ function OPSGROUP:AddWeightCargo(UnitName, Weight)
-- Add weight. -- Add weight.
element.weightCargo=element.weightCargo+Weight element.weightCargo=element.weightCargo+Weight
-- Debug info.
self:I(self.lid..string.format("FF %s: Adding %.1f kg cargo weight. New cargo weight=%.1f kg", UnitName, Weight, element.weightCargo))
-- For airborne units, we set the weight in game. -- For airborne units, we set the weight in game.
if self.isFlightgroup then if self.isFlightgroup then
@ -5613,6 +5777,8 @@ function OPSGROUP:onafterLoading(From, Event, To)
-- Find a carrier that has enough free cargo bay for this group. -- Find a carrier that has enough free cargo bay for this group.
local carrier=_findCarrier(weight) local carrier=_findCarrier(weight)
local carrier=self:FindCarrierForCargo(cargo.opsgroup)
if carrier then if carrier then
@ -5694,9 +5860,6 @@ function OPSGROUP:onafterLoad(From, Event, To, CargoGroup, Carrier)
if carrier then if carrier then
-- Add into carrier bay.
self:_AddCargobay(CargoGroup, carrier)
--- ---
-- Embark Cargo -- Embark Cargo
--- ---
@ -5710,8 +5873,8 @@ function OPSGROUP:onafterLoad(From, Event, To, CargoGroup, Carrier)
-- Clear all waypoints. -- Clear all waypoints.
CargoGroup:ClearWaypoints() CargoGroup:ClearWaypoints()
-- Set carrier (again). -- Add into carrier bay.
CargoGroup:_SetMyCarrier(self, carrier, false) self:_AddCargobay(CargoGroup, carrier, false)
-- Despawn this group. -- Despawn this group.
if CargoGroup:IsAlive() then if CargoGroup:IsAlive() then
@ -6308,7 +6471,7 @@ function OPSGROUP:onafterBoard(From, Event, To, CarrierGroup, Carrier)
end end
-- Set carrier. As long as the group is not loaded, we only reserve the cargo space. -- Set carrier. As long as the group is not loaded, we only reserve the cargo space.
self:_SetMyCarrier(CarrierGroup, Carrier, true) CarrierGroup:_AddCargobay(self, Carrier, true)
else else
@ -6337,8 +6500,9 @@ function OPSGROUP:onafterBoard(From, Event, To, CarrierGroup, Carrier)
self:T(self.lid.."Carrier not ready for boarding yet ==> repeating boarding call in 10 sec") self:T(self.lid.."Carrier not ready for boarding yet ==> repeating boarding call in 10 sec")
self:__Board(-10, CarrierGroup, Carrier) self:__Board(-10, CarrierGroup, Carrier)
-- Set carrier. As long as the group is not loaded, we only reserve the cargo space. -- Set carrier. As long as the group is not loaded, we only reserve the cargo space.´
self:_SetMyCarrier(CarrierGroup, Carrier, true) CarrierGroup:_AddCargobay(self, Carrier, true)
--self:_SetMyCarrier(CarrierGroup, Carrier, true)
end end
@ -8750,6 +8914,8 @@ function OPSGROUP:_AddElementByName(unitname)
-- Max cargo weight: -- Max cargo weight:
unit:SetCargoBayWeightLimit() unit:SetCargoBayWeightLimit()
element.weightMaxCargo=unit.__.CargoBayWeightLimit element.weightMaxCargo=unit.__.CargoBayWeightLimit
element.cargoBay={}
-- FLIGHTGROUP specific. -- FLIGHTGROUP specific.
if self.isFlightgroup then if self.isFlightgroup then

View File

@ -59,7 +59,12 @@
-- --
-- # The OPSTRANSPORT Concept -- # 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 classed). -- 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.
-- --
-- --
-- @field #OPSTRANSPORT -- @field #OPSTRANSPORT
@ -714,8 +719,10 @@ function OPSTRANSPORT:onafterStatus(From, Event, To)
text=text..string.format("\nCarriers:") text=text..string.format("\nCarriers:")
for _,_carrier in pairs(self.carriers) do for _,_carrier in pairs(self.carriers) do
local carrier=_carrier --Ops.OpsGroup#OPSGROUP local carrier=_carrier --Ops.OpsGroup#OPSGROUP
text=text..string.format("\n- %s: %s [%s], cargo=%d/%d kg, free cargo bay %d/%d kg", 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(), carrier:GetWeightCargoMax(), carrier:GetFreeCargobayMax(true), carrier:GetFreeCargobayMax()) 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) self:I(self.lid..text)