OPS Cargo

This commit is contained in:
Frank
2021-02-03 22:51:18 +01:00
parent ee3ead9aac
commit 7d83c251a8
3 changed files with 241 additions and 146 deletions
+15 -16
View File
@@ -57,7 +57,6 @@
-- @field #number Tparking Abs. mission time stamp when the group was spawned uncontrolled and is parking. -- @field #number Tparking Abs. mission time stamp when the group was spawned uncontrolled and is parking.
-- @field #table menu F10 radio menu. -- @field #table menu F10 radio menu.
-- @field #string controlstatus Flight control status. -- @field #string controlstatus Flight control status.
-- @field #boolean ishelo If true, the is a helicopter group.
-- @field #number callsignName Callsign name. -- @field #number callsignName Callsign name.
-- @field #number callsignNumber Callsign number. -- @field #number callsignNumber Callsign number.
-- @field #boolean despawnAfterLanding If true, group is despawned after landed at an airbase. -- @field #boolean despawnAfterLanding If true, group is despawned after landed at an airbase.
@@ -146,7 +145,7 @@ FLIGHTGROUP = {
Tholding = nil, Tholding = nil,
Tparking = nil, Tparking = nil,
menu = nil, menu = nil,
ishelo = nil, isHelo = nil,
} }
@@ -1004,7 +1003,7 @@ function FLIGHTGROUP:onafterStatus(From, Event, To)
--- ---
-- Airboss Helo -- Airboss Helo
--- ---
if self.ishelo and self.airboss and self:IsHolding() then if self.isHelo and self.airboss and self:IsHolding() then
if self.airboss:IsRecovering() or self:IsFuelCritical() then if self.airboss:IsRecovering() or self:IsFuelCritical() then
self:ClearToLand() self:ClearToLand()
end end
@@ -1445,7 +1444,7 @@ function FLIGHTGROUP:onafterElementLanded(From, Event, To, Element, airbase)
else else
-- Helos with skids land directly on parking spots. -- Helos with skids land directly on parking spots.
if self.ishelo then if self.isHelo then
local Spot=self:GetParkingSpot(Element, 10, airbase) local Spot=self:GetParkingSpot(Element, 10, airbase)
@@ -2204,8 +2203,8 @@ function FLIGHTGROUP:_LandAtAirbase(airbase, SpeedTo, SpeedHold, SpeedLand)
-- Defaults: -- Defaults:
SpeedTo=SpeedTo or UTILS.KmphToKnots(self.speedCruise) SpeedTo=SpeedTo or UTILS.KmphToKnots(self.speedCruise)
SpeedHold=SpeedHold or (self.ishelo and 80 or 250) SpeedHold=SpeedHold or (self.isHelo and 80 or 250)
SpeedLand=SpeedLand or (self.ishelo and 40 or 170) SpeedLand=SpeedLand or (self.isHelo and 40 or 170)
-- Clear holding time in any case. -- Clear holding time in any case.
self.Tholding=nil self.Tholding=nil
@@ -2214,7 +2213,7 @@ function FLIGHTGROUP:_LandAtAirbase(airbase, SpeedTo, SpeedHold, SpeedLand)
local text=string.format("Flight group set to hold at airbase %s. SpeedTo=%d, SpeedHold=%d, SpeedLand=%d", airbase:GetName(), SpeedTo, SpeedHold, SpeedLand) local text=string.format("Flight group set to hold at airbase %s. SpeedTo=%d, SpeedHold=%d, SpeedLand=%d", airbase:GetName(), SpeedTo, SpeedHold, SpeedLand)
self:T(self.lid..text) self:T(self.lid..text)
local althold=self.ishelo and 1000+math.random(10)*100 or math.random(4,10)*1000 local althold=self.isHelo and 1000+math.random(10)*100 or math.random(4,10)*1000
-- Holding points. -- Holding points.
local c0=self.group:GetCoordinate() local c0=self.group:GetCoordinate()
@@ -2244,8 +2243,8 @@ function FLIGHTGROUP:_LandAtAirbase(airbase, SpeedTo, SpeedHold, SpeedLand)
end end
-- Altitude above ground for a glide slope of 3 degrees. -- Altitude above ground for a glide slope of 3 degrees.
local x1=self.ishelo and UTILS.NMToMeters(5.0) or UTILS.NMToMeters(10) local x1=self.isHelo and UTILS.NMToMeters(5.0) or UTILS.NMToMeters(10)
local x2=self.ishelo and UTILS.NMToMeters(2.5) or UTILS.NMToMeters(5) local x2=self.isHelo and UTILS.NMToMeters(2.5) or UTILS.NMToMeters(5)
local alpha=math.rad(3) local alpha=math.rad(3)
local h1=x1*math.tan(alpha) local h1=x1*math.tan(alpha)
local h2=x2*math.tan(alpha) local h2=x2*math.tan(alpha)
@@ -2365,8 +2364,8 @@ end
function FLIGHTGROUP:onafterWait(From, Event, To, Coord, Altitude, Speed) function FLIGHTGROUP:onafterWait(From, Event, To, Coord, Altitude, Speed)
Coord=Coord or self.group:GetCoordinate() Coord=Coord or self.group:GetCoordinate()
Altitude=Altitude or (self.ishelo and 1000 or 10000) Altitude=Altitude or (self.isHelo and 1000 or 10000)
Speed=Speed or (self.ishelo and 80 or 250) Speed=Speed or (self.isHelo and 80 or 250)
-- Debug message. -- Debug message.
local text=string.format("Flight group set to wait/orbit at altitude %d m and speed %.1f km/h", Altitude, Speed) local text=string.format("Flight group set to wait/orbit at altitude %d m and speed %.1f km/h", Altitude, Speed)
@@ -2464,7 +2463,7 @@ function FLIGHTGROUP:onafterHolding(From, Event, To)
elseif self.airboss then elseif self.airboss then
if self.ishelo then if self.isHelo then
local carrierpos=self.airboss:GetCoordinate() local carrierpos=self.airboss:GetCoordinate()
local carrierheading=self.airboss:GetHeading() local carrierheading=self.airboss:GetHeading()
@@ -2578,7 +2577,7 @@ end
-- @param Core.Point#COORDINATE Coordinate The coordinate where to land. Default is current position. -- @param Core.Point#COORDINATE Coordinate The coordinate where to land. Default is current position.
-- @param #number Duration The duration in seconds to remain on ground. Default 600 sec (10 min). -- @param #number Duration The duration in seconds to remain on ground. Default 600 sec (10 min).
function FLIGHTGROUP:onbeforeLandAt(From, Event, To, Coordinate, Duration) function FLIGHTGROUP:onbeforeLandAt(From, Event, To, Coordinate, Duration)
return self.ishelo return self.isHelo
end end
--- On after "LandAt" event. Order helicopter to land at a specific point. --- On after "LandAt" event. Order helicopter to land at a specific point.
@@ -2804,7 +2803,7 @@ function FLIGHTGROUP:_InitGroup()
self.isGround=false self.isGround=false
-- Helo group. -- Helo group.
self.ishelo=group:IsHelicopter() self.isHelo=group:IsHelicopter()
-- Is (template) group uncontrolled. -- Is (template) group uncontrolled.
self.isUncontrolled=self.template.uncontrolled self.isUncontrolled=self.template.uncontrolled
@@ -2816,7 +2815,7 @@ function FLIGHTGROUP:_InitGroup()
self.speedMax=group:GetSpeedMax() self.speedMax=group:GetSpeedMax()
-- Cruise speed limit 350 kts for fixed and 80 knots for rotary wings. -- Cruise speed limit 350 kts for fixed and 80 knots for rotary wings.
local speedCruiseLimit=self.ishelo and UTILS.KnotsToKmph(80) or UTILS.KnotsToKmph(350) local speedCruiseLimit=self.isHelo and UTILS.KnotsToKmph(80) or UTILS.KnotsToKmph(350)
-- Cruise speed: 70% of max speed but within limit. -- Cruise speed: 70% of max speed but within limit.
self.speedCruise=math.min(self.speedMax*0.7, speedCruiseLimit) self.speedCruise=math.min(self.speedMax*0.7, speedCruiseLimit)
@@ -2844,7 +2843,7 @@ function FLIGHTGROUP:_InitGroup()
self.callsign.NameSquad=UTILS.GetCallsignName(self.callsign.NumberSquad) self.callsign.NameSquad=UTILS.GetCallsignName(self.callsign.NumberSquad)
-- Set default formation. -- Set default formation.
if self.ishelo then if self.isHelo then
self.optionDefault.Formation=ENUMS.Formation.RotaryWing.EchelonLeft.D300 self.optionDefault.Formation=ENUMS.Formation.RotaryWing.EchelonLeft.D300
else else
self.optionDefault.Formation=ENUMS.Formation.FixedWing.EchelonLeft.Group self.optionDefault.Formation=ENUMS.Formation.FixedWing.EchelonLeft.Group
+14 -40
View File
@@ -609,6 +609,11 @@ function NAVYGROUP:onafterStatus(From, Event, To)
end end
---
-- Cargo
---
self:_CheckCargoTransport()
--- ---
-- Tasks & Missions -- Tasks & Missions
@@ -1164,50 +1169,19 @@ function NAVYGROUP:_InitGroup()
-- Get all units of the group. -- Get all units of the group.
local units=self.group:GetUnits() local units=self.group:GetUnits()
for _,_unit in pairs(units) do -- Add elemets.
local unit=_unit --Wrapper.Unit#UNIT for _,unit in pairs(units) do
self:_AddElementByName(unit:GetName())
-- Get unit template.
local unittemplate=unit:GetTemplate()
local element={} --#NAVYGROUP.Element
element.name=unit:GetName()
element.unit=unit
element.status=OPSGROUP.ElementStatus.INUTERO
element.typename=unit:GetTypeName()
element.skill=unittemplate.skill or "Unknown"
element.ai=true
element.category=element.unit:GetUnitCategory()
element.categoryname=element.unit:GetCategoryName()
element.size, element.length, element.height, element.width=unit:GetObjectSize()
element.ammo0=self:GetAmmoUnit(unit, false)
-- Debug text.
if self.verbose>=2 then
local text=string.format("Adding element %s: status=%s, skill=%s, category=%s (%d), size: %.1f (L=%.1f H=%.1f W=%.1f)",
element.name, element.status, element.skill, element.categoryname, element.category, element.size, element.length, element.height, element.width)
self:I(self.lid..text)
end
-- Add element to table.
table.insert(self.elements, element)
-- Get Descriptors.
self.descriptors=self.descriptors or unit:GetDesc()
-- Set type name.
self.actype=self.actype or unit:GetTypeName()
if unit:IsAlive() then
-- Trigger spawned event.
self:ElementSpawned(element)
end
end end
-- Get Descriptors.
self.descriptors=units[1]:GetDesc()
-- Set type name.
self.actype=units[1]:GetTypeName()
-- Debug info. -- Debug info.
if self.verbose>=1 then if self.verbose>=0 then
local text=string.format("Initialized Navy Group %s:\n", self.groupname) local text=string.format("Initialized Navy Group %s:\n", self.groupname)
text=text..string.format("Unit type = %s\n", self.actype) text=text..string.format("Unit type = %s\n", self.actype)
text=text..string.format("Speed max = %.1f Knots\n", UTILS.KmphToKnots(self.speedMax)) text=text..string.format("Speed max = %.1f Knots\n", UTILS.KmphToKnots(self.speedMax))
+204 -82
View File
@@ -25,6 +25,7 @@
-- @field #boolean isFlightgroup Is a FLIGHTGROUP. -- @field #boolean isFlightgroup Is a FLIGHTGROUP.
-- @field #boolean isArmygroup Is an ARMYGROUP. -- @field #boolean isArmygroup Is an ARMYGROUP.
-- @field #boolean isNavygroup Is a NAVYGROUP. -- @field #boolean isNavygroup Is a NAVYGROUP.
-- @field #boolean isHelo If true, the is a helicopter group.
-- @field #table elements Table of elements, i.e. units of the group. -- @field #table elements Table of elements, i.e. units of the group.
-- @field #boolean isAI If true, group is purely AI. -- @field #boolean isAI If true, group is purely AI.
-- @field #boolean isAircraft If true, group is airplane or helicopter. -- @field #boolean isAircraft If true, group is airplane or helicopter.
@@ -97,7 +98,6 @@
-- --
-- @field #OPSGROUP.Element carrier Carrier the group is loaded into as cargo. -- @field #OPSGROUP.Element carrier Carrier the group is loaded into as cargo.
-- @field #OPSGROUP carrierGroup Carrier group transporting this group as cargo. -- @field #OPSGROUP carrierGroup Carrier group transporting this group as cargo.
-- @field #table cargo Table containing all cargo of the carrier.
-- @field #table cargoqueue Table containing cargo groups to be transported. -- @field #table cargoqueue Table containing cargo groups to be transported.
-- @field #OPSGROUP.CargoTransport cargoTransport Current cargo transport assignment. -- @field #OPSGROUP.CargoTransport cargoTransport Current cargo transport assignment.
-- @field #string cargoStatus Cargo status of this group acting as cargo. -- @field #string cargoStatus Cargo status of this group acting as cargo.
@@ -157,7 +157,6 @@ OPSGROUP = {
Ndestroyed = 0, Ndestroyed = 0,
Nkills = 0, Nkills = 0,
weaponData = {}, weaponData = {},
cargo = {},
cargoqueue = {}, cargoqueue = {},
} }
@@ -402,8 +401,13 @@ OPSGROUP.CargoStatus={
-- @type OPSGROUP.CargoTransport -- @type OPSGROUP.CargoTransport
-- @field #table cargos Cargos. Each element is a @{#OPSGROUP.Cargo}. -- @field #table cargos Cargos. Each element is a @{#OPSGROUP.Cargo}.
-- @field #string status Status of the carrier. See @{#OPSGROUP.CarrierStatus}. -- @field #string status Status of the carrier. See @{#OPSGROUP.CarrierStatus}.
-- @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 pickupzone Zone where the cargo is picked up.
-- @field Core.Zone#ZONE deployzone Zone where the cargo is dropped off. -- @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.
--- Cargo group data. --- Cargo group data.
-- @type OPSGROUP.CargoGroup -- @type OPSGROUP.CargoGroup
@@ -3514,7 +3518,6 @@ function OPSGROUP:onafterPassingWaypoint(From, Event, To, Waypoint)
NAVYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Altitude) NAVYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Altitude)
end end
else else
-- Apply tasks of this waypoint. -- Apply tasks of this waypoint.
@@ -4298,7 +4301,7 @@ function OPSGROUP:onafterRespawn(From, Event, To, Template)
--self.respawning=true --self.respawning=true
self:_Respawn(0, template, Reset) self:_Respawn(0, template)
end end
@@ -4314,7 +4317,7 @@ function OPSGROUP:_Respawn(Delay, Template, Reset)
self:ScheduleOnce(Delay, OPSGROUP._Respawn, self, 0, Template, Reset) self:ScheduleOnce(Delay, OPSGROUP._Respawn, self, 0, Template, Reset)
else else
env.info("FF _Respawn") self:I(self.lid.."FF _Respawn")
-- Given template or get old. -- Given template or get old.
Template=Template or UTILS.DeepCopy(self.template) Template=Template or UTILS.DeepCopy(self.template)
@@ -4390,9 +4393,7 @@ function OPSGROUP:_Respawn(Delay, Template, Reset)
end end
-- Currently respawning. -- Debug output.
--self.respawning=true
self:I({Template=Template}) self:I({Template=Template})
-- Spawn new group. -- Spawn new group.
@@ -4481,26 +4482,93 @@ end
-- @return #OPSGROUP self -- @return #OPSGROUP self
function OPSGROUP:_CheckCargoTransport() function OPSGROUP:_CheckCargoTransport()
if self.cargoTransport then -- Abs. missin time in seconds.
local Time=timer.getAbsTime()
if self.cargoTransport then
-- TODO: Check if this group can actually transport any cargo. -- TODO: Check if this group can actually transport any cargo.
-- Debug info. local done=true
local text=string.format("Carrier [%s]: %s --> %s", self.carrierStatus, self.cargoTransport.pickupzone:GetName(), self.cargoTransport.deployzone:GetName())
for _,_cargo in pairs(self.cargoTransport.cargos) do for _,_cargo in pairs(self.cargoTransport.cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
local name=cargo.opsgroup:GetName()
local gstatus=cargo.opsgroup:GetState() if cargo.delivered then
local cstatus=cargo.opsgroup.cargoStatus -- This one is delivered.
local weight=cargo.opsgroup:GetWeightTotal() elseif cargo.opsgroup==nil or cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped() then
text=text..string.format("\n- %s [%s]: %s (weight %.1f kg)", name, gstatus, cstatus, weight) -- This one is dead.
else
done=false --Someone is not done!
end
--TODO: check if cargo is too heavy for this carrier group ==> elseif
end
if done then
self.cargoTransport.status="Delivered"
end
end
-- Check if there is anything in the queue.
if not self.cargoTransport then
-- Current position.
local coord=self:GetCoordinate()
-- Sort results table wrt prio and distance to pickup zone.
local function _sort(a, b)
local transportA=a --#OPSGROUP.CargoTransport
local transportB=b --#OPSGROUP.CargoTransport
local distA=transportA.pickupzone:GetCoordinate():Get2DDistance(coord)
local distB=transportB.pickupzone:GetCoordinate():Get2DDistance(coord)
return (transportA.prio<transportB.prio) or (transportA.prio==transportB.prio and distA<distB)
end
table.sort(self.cargoqueue, _sort)
-- Look for first mission that is SCHEDULED.
local vip=math.huge
for _,_cargotransport in pairs(self.cargoqueue) do
local cargotransport=_cargotransport --#OPSGROUP.CargoTransport
if cargotransport.importance and cargotransport.importance<vip then
vip=cargotransport.importance
end
end
-- Find next transport assignment.
for _,_cargotransport in pairs(self.cargoqueue) do
local cargotransport=_cargotransport --#OPSGROUP.CargoTransport
if Time>=cargotransport.Tstart and cargotransport.status~="Delivered" and (cargotransport.importance==nil or cargotransport.importance<=vip) then
self.cargoTransport=cargotransport
break
end
end
end
-- Now handle the transport.
if self.cargoTransport then
-- Debug info.
if self.verbose>=0 then
local text=string.format("Carrier [%s]: %s --> %s", self.carrierStatus, self.cargoTransport.pickupzone:GetName(), self.cargoTransport.deployzone:GetName())
for _,_cargo in pairs(self.cargoTransport.cargos) do
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
local name=cargo.opsgroup:GetName()
local gstatus=cargo.opsgroup:GetState()
local cstatus=cargo.opsgroup.cargoStatus
local weight=cargo.opsgroup:GetWeightTotal()
text=text..string.format("\n- %s (%.1f kg) [%s]: %s delivered=%s", name, weight, gstatus, cstatus, tostring(cargo.delivered))
end
self:I(self.lid..text)
end end
self:I(self.lid..text)
if self:IsNotCarrier() then if self:IsNotCarrier() then
env.info("FF not carrier ==> pickup") self:I(self.lid.."Not carrier ==> pickup")
--TODO: Check if there is still cargo left. Maybe someone else already picked it up or it got destroyed. --TODO: Check if there is still cargo left. Maybe someone else already picked it up or it got destroyed.
@@ -4509,13 +4577,13 @@ function OPSGROUP:_CheckCargoTransport()
elseif self:IsPickingup() then elseif self:IsPickingup() then
env.info("FF picking up") self:I(self.lid.."Picking up...")
--TODO: Check if there is still cargo left. Maybe someone else already picked it up or it got destroyed. --TODO: Check if there is still cargo left. Maybe someone else already picked it up or it got destroyed.
elseif self:IsLoading() then elseif self:IsLoading() then
env.info("FF loading") self:I(self.lid.."Loading...")
local boarding=false local boarding=false
local gotcargo=false local gotcargo=false
@@ -4536,7 +4604,7 @@ function OPSGROUP:_CheckCargoTransport()
-- Boarding finished ==> Transport cargo. -- Boarding finished ==> Transport cargo.
if gotcargo and not boarding then if gotcargo and not boarding then
env.info("FF boarding finished ==> Loaded") self:I(self.lid.."Boarding finished ==> Loaded")
self:Loaded() self:Loaded()
end end
@@ -4545,17 +4613,13 @@ function OPSGROUP:_CheckCargoTransport()
self:Loading() self:Loading()
end end
elseif self:IsLoaded() then
env.info("FF loaded (nothing to do?)")
elseif self:IsTransporting() then elseif self:IsTransporting() then
env.info("FF transporting (nothing to do)") self:I(self.lid.."Transporting (nothing to do)")
elseif self:IsUnloading() then elseif self:IsUnloading() then
env.info("FF unloading ==> Checking if all cargo was delivered") self:I(self.lid.."Unloading ==> Checking if all cargo was delivered")
local delivered=true local delivered=true
for _,_cargo in pairs(self.cargoTransport.cargos) do for _,_cargo in pairs(self.cargoTransport.cargos) do
@@ -4570,7 +4634,7 @@ function OPSGROUP:_CheckCargoTransport()
-- Boarding finished ==> Transport cargo. -- Boarding finished ==> Transport cargo.
if delivered then if delivered then
env.info("FF unloading finished ==> Unloaded") self:I(self.lid.."Unloading finished ==> Unloaded")
self:Unloaded() self:Unloaded()
end end
@@ -4584,12 +4648,17 @@ end
--- Create a cargo transport assignment. --- Create a cargo transport assignment.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param Core.Set#SET_GROUP GroupSet Set of groups to be transported. Can also be a single @{Wrapper.Group#GROUP} object. -- @param Core.Set#SET_GROUP GroupSet Set of groups to be transported. Can also be a single @{Wrapper.Group#GROUP} object.
-- @param Core.Zone#ZONE Pickupzone Pickup zone. -- @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. -- @param Core.Zone#ZONE Deployzone Deploy zone. This is the zone, where the carrier is going to drop off the cargo.
-- @param #number Prio Priority of this transport assignment. Should be a number between 1 (high prio) and 100 (low prio).
-- @param #number Importance Importance of this transport assignment (lower=more important). A transport is only considered, if all more important (if any) transports are done. Default `nil`.
-- @param #string ClockStart Start time in format "HH:MM(:SS)(+D)", e.g. "13:05:30" or "08:30+1". Can also be given as a `#number`, in which case it is interpreted as relative amount in seconds from now on.
-- @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.
-- @return #OPSGROUP.CargoTransport Cargo transport. -- @return #OPSGROUP.CargoTransport Cargo transport.
function OPSGROUP:AddCargoTransport(GroupSet, Pickupzone, Deployzone) function OPSGROUP:AddCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, Importance, ClockStart, Embarkzone, Disembarkzone)
local cargotransport=self:CreateCargoTransport(GroupSet, Pickupzone, Deployzone) local cargotransport=self:CreateCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, Importance, ClockStart, Embarkzone, Disembarkzone)
table.insert(self.cargoqueue, cargotransport) table.insert(self.cargoqueue, cargotransport)
@@ -4599,40 +4668,72 @@ end
--- Create a cargo transport assignment. --- Create a cargo transport assignment.
-- @param #OPSGROUP self -- @param #OPSGROUP 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.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. -- @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. -- @param Core.Zone#ZONE Deployzone Deploy zone. This is the zone, where the carrier is going to drop off the cargo.
-- @param #number Prio Priority of this transport assignment. Should be a number between 1 (high prio) and 100 (low prio).
-- @param #number Importance Importance of this transport assignment (lower=more important). A transport is only considered, if all more important (if any) transports are done. Default `nil`.
-- @param #string ClockStart Start time in format "HH:MM:SS+D", e.g. "13:05:30" or "08:30+1". Can also be passed as a `#number` in which case it is interpreted as relative amount in seconds from now on.
-- @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.
-- @return #OPSGROUP.CargoTransport Cargo transport. -- @return #OPSGROUP.CargoTransport Cargo transport.
function OPSGROUP:CreateCargoTransport(GroupSet, Pickupzone, Deployzone) function OPSGROUP:CreateCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, Importance, ClockStart, Embarkzone, Disembarkzone)
-- 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
-- Data structure.
local transport={} --#OPSGROUP.CargoTransport local transport={} --#OPSGROUP.CargoTransport
transport.pickupzone=Pickupzone transport.pickupzone=Pickupzone
transport.deployzone=Deployzone transport.deployzone=Deployzone
transport.uid=1 transport.uid=1
transport.status="Planning" transport.status="Planning"
transport.embarkzone=Embarkzone or Pickupzone
transport.disembarkzone=Disembarkzone or Deployzone
transport.prio=Prio or 50
transport.importance=Importance
transport.Tstart=Tstart
transport.cargos={} transport.cargos={}
-- Check type of GroupSet provided.
if GroupSet:IsInstanceOf("GROUP") or GroupSet:IsInstanceOf("OPSGROUP") then if GroupSet:IsInstanceOf("GROUP") or GroupSet:IsInstanceOf("OPSGROUP") then
-- We got a single GROUP or OPSGROUP objectg.
local cargo=self:CreateCargoGroupData(GroupSet, Pickupzone, Deployzone) local cargo=self:CreateCargoGroupData(GroupSet, Pickupzone, Deployzone)
env.info("FF adding cargo group "..cargo.opsgroup:GetName())
table.insert(transport.cargos, cargo) table.insert(transport.cargos, cargo)
else else
-- We got a SET_GROUP object.
for _,group in pairs(GroupSet.Set) do for _,group in pairs(GroupSet.Set) do
local cargo=self:CreateCargoGroupData(group, Pickupzone, Deployzone) local cargo=self:CreateCargoGroupData(group, Pickupzone, Deployzone)
table.insert(transport.cargos, cargo) table.insert(transport.cargos, cargo)
end end
end end
local text=string.format("Created Cargo Transport (UID=%d) from %s -->%s", transport.uid, transport.pickupzone:GetName(), transport.deployzone:GetName()) -- Debug info.
for _,_cargo in pairs(transport.cargos) do if self.verbose>=0 then
local cargo=_cargo --#OPSGROUP.CargoGroup local text=string.format("Created Cargo Transport (UID=%d) from %s(%s) --> %s(%s)",
text=text..string.format("\n- %s [%s] weight=%.1f kg", cargo.opsgroup:GetName(), cargo.opsgroup:GetState(), cargo.opsgroup:GetWeightTotal()) transport.uid, transport.pickupzone:GetName(), transport.embarkzone:GetName(), transport.deployzone:GetName(), transport.disembarkzone:GetName())
local Weight=0
for _,_cargo in pairs(transport.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", #transport.cargos, Weight)
self:I(self.lid..text)
end end
return transport return transport
end end
--- Create a --- Create a cargo group data structure.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param Wrapper.Group#GROUP group The GROUP object. -- @param Wrapper.Group#GROUP group The GROUP object.
-- @param Core.Zone#ZONE Pickupzone Pickup zone. -- @param Core.Zone#ZONE Pickupzone Pickup zone.
@@ -4665,6 +4766,7 @@ function OPSGROUP:CreateCargoGroupData(group, Pickupzone, Deployzone)
local cargo={} --#OPSGROUP.CargoGroup local cargo={} --#OPSGROUP.CargoGroup
cargo.opsgroup=opsgroup cargo.opsgroup=opsgroup
cargo.delivered=false
cargo.status="Unknown" cargo.status="Unknown"
cargo.pickupzone=Pickupzone cargo.pickupzone=Pickupzone
cargo.deployzone=Deployzone cargo.deployzone=Deployzone
@@ -4743,26 +4845,12 @@ end
-- @param #number Weight Cargo weight to be reduced in kg. -- @param #number Weight Cargo weight to be reduced in kg.
function OPSGROUP:RedWeightCargo(UnitName, Weight) function OPSGROUP:RedWeightCargo(UnitName, Weight)
-- Reduce weight. -- Reduce weight by adding negative weight.
self:AddWeightCargo(UnitName, -Weight) self:AddWeightCargo(UnitName, -Weight)
return self return self
end end
--- Create a cargo transport assignment.
-- @param #OPSGROUP self
-- @param #OPSGROUP.CargoGroup CargoGroup Cargo group object.
-- @return #OPSGROUP self
function OPSGROUP:_AddCargoGroup(CargoGroup)
--CargoGroup.status=OPSGROUP.CargoStatus.
table.insert(self.cargo, CargoGroup)
return self
end
--- On after "Pickup" event. --- On after "Pickup" event.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #string From From state. -- @param #string From From state.
@@ -4789,17 +4877,23 @@ function OPSGROUP:onafterPickup(From, Event, To, Zone)
-- Get a random coordinate in the pickup zone and let the carrier go there. -- Get a random coordinate in the pickup zone and let the carrier go there.
local Coordinate=Zone:GetRandomCoordinate() local Coordinate=Zone:GetRandomCoordinate()
--TODO: Add NAVYGROUP and FLIGHTGROUP waypoint -- Add waypoint.
if self.isFlightgroup then if self.isFlightgroup then
Coordinate:SetAltitude(200) if self.isHelo then
local waypoint=FLIGHTGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Altitude, Updateroute) Coordinate:SetAltitude(200)
local waypoint=FLIGHTGROUP.AddWaypoint(self, Coordinate)
waypoint.detour=true
else
--TODO: airplane! pickup at airbase. check if already at airbase or make plane go there.
end
elseif self.isNavygroup then
local waypoint=NAVYGROUP.AddWaypoint(self, Coordinate)
waypoint.detour=true waypoint.detour=true
else elseif self.isArmygroup then
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute) local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate)
waypoint.detour=true waypoint.detour=true
end end
end end
end end
@@ -4840,20 +4934,26 @@ function OPSGROUP:onafterLoading(From, Event, To)
for _,_cargo in pairs(self.cargoTransport.cargos) do for _,_cargo in pairs(self.cargoTransport.cargos) do
local cargo=_cargo --#OPSGROUP.CargoGroup local cargo=_cargo --#OPSGROUP.CargoGroup
env.info("FF trying cargo!")
if cargo.opsgroup:IsNotCargo() and not cargo.delivered then if cargo.opsgroup:IsNotCargo() and not cargo.delivered then
-- Check if cargo is in pickup zone. -- Check if cargo is in pickup zone.
local inzone=self.cargoTransport.pickupzone:IsCoordinateInZone(cargo.opsgroup:GetCoordinate()) local inzone=self.cargoTransport.embarkzone:IsCoordinateInZone(cargo.opsgroup:GetCoordinate())
-- First check if cargo is not delivered yet. -- First check if cargo is not delivered yet.
if inzone then if inzone then
env.info("FF trying cargo 2!")
local weight=cargo.opsgroup:GetWeightTotal() local weight=cargo.opsgroup:GetWeightTotal()
local carrier=_findCarrier(weight) local carrier=_findCarrier(weight)
if carrier then if carrier then
env.info("FF trying cargo3!")
-- Decrease free cargo bay. -- Decrease free cargo bay.
cargobay[carrier.name]=cargobay[carrier.name]-weight cargobay[carrier.name]=cargobay[carrier.name]-weight
@@ -4870,8 +4970,14 @@ function OPSGROUP:onafterLoading(From, Event, To)
end end
else
env.info("FF cargo NOT in embark zone "..self.cargoTransport.embarkzone:GetName())
end end
else
env.info("FF cargo already cargo or delivered")
end end
end end
end end
@@ -4949,16 +5055,24 @@ function OPSGROUP:onafterTransport(From, Event, To, Zone)
-- Get a random coordinate in the pickup zone and let the carrier go there. -- Get a random coordinate in the pickup zone and let the carrier go there.
local Coordinate=Zone:GetRandomCoordinate() local Coordinate=Zone:GetRandomCoordinate()
--TODO: Add NAVYGROUP and FLIGHTGROUP waypoint -- Set waypoint.
if self.isFlightgroup then if self.isFlightgroup then
Coordinate:SetAltitude(200) -- FLIGHTGROUP
local waypoint=FLIGHTGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Altitude, Updateroute) if self.isHelo then
waypoint.detour=true Coordinate:SetAltitude(200)
local dist=self:GetCoordinate():Get2DDistance(waypoint.coordinate) local waypoint=FLIGHTGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Altitude, Updateroute)
env.info(string.format("FF adding transport detour wp with uid=%d at dist=%d m", waypoint.uid, dist)) waypoint.detour=true
else else
-- TODO: airplane! let plane fly to airbase.
end
elseif self.isArmygroup then
-- ARMYGROUP
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute) local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute)
waypoint.detour=true waypoint.detour=true
elseif self.isNavygroup then
-- NAVYGROUP
local waypoint=NAVYGROUP.AddWaypoint(self, Coordinate)
waypoint.detour=true
end end
end end
@@ -4986,7 +5100,7 @@ function OPSGROUP:onafterDeploy(From, Event, To, Zone)
env.info("FF deploy cargo "..cargo.opsgroup:GetName()) env.info("FF deploy cargo "..cargo.opsgroup:GetName())
local zone=Zone or cargo.deployzone --Core.Zone#ZONE local zone=Zone or self.cargoTransport.disembarkzone --Core.Zone#ZONE
--if zone:IsCoordinateInZone(self:GetCoordinate()) then --if zone:IsCoordinateInZone(self:GetCoordinate()) then
@@ -5093,20 +5207,21 @@ function OPSGROUP:onafterBoard(From, Event, To, CarrierGroup, Carrier)
self.carrier=Carrier self.carrier=Carrier
self.carrierGroup=CarrierGroup self.carrierGroup=CarrierGroup
-- Add to current cargo of carrier. -- Board if group is mobile, not late activated and army or navy. Everything else is loaded directly.
--CarrierGroup:_AddCargoGroup(self) local board=self.speedMax>0 and self:IsLateActivated()==false and (self.isArmygroup or self.isNavygroup)
--TODO: make cargo run to carrier if board then
--TODO: check if cargo is mobile. if not ==> load
--TODO: check if cargo is alive=true. if only exists ==> load.
if self.speedMax>0 then
-- TODO: Implement embarkzone.
local Coordinate=Carrier.unit:GetCoordinate() local Coordinate=Carrier.unit:GetCoordinate()
--TODO: NAVYGROUP and FLIGHTGROUP if self.isArmygroup then
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute) local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute)
waypoint.detour=true waypoint.detour=true
else
local waypoint=NAVYGROUP.AddWaypoint(self, Coordinate)
waypoint.detour=true
end
else else
@@ -5131,9 +5246,16 @@ function OPSGROUP:onafterEmbark(From, Event, To, Carrier)
-- Set cargo status. -- Set cargo status.
self.cargoStatus=OPSGROUP.CargoStatus.LOADED self.cargoStatus=OPSGROUP.CargoStatus.LOADED
-- Clear all waypoints.
for i=1,#self.waypoints do
table.remove(self.waypoints, i)
end
self.waypoints={}
-- Despawn this group. -- Despawn this group.
self:Despawn(0, true) self:Despawn(0, true)
-- Set carrier (again).
self.carrier=Carrier self.carrier=Carrier
end end