mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
OPS Cargo
This commit is contained in:
parent
8bb9f0d7c0
commit
c5a4776b3a
@ -1057,24 +1057,48 @@ end
|
||||
|
||||
--- Returns a random Vec2 location within the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0.
|
||||
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||
-- @param #table surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type!
|
||||
-- @return DCS#Vec2 The random location within the zone.
|
||||
function ZONE_RADIUS:GetRandomVec2( inner, outer )
|
||||
self:F( self.ZoneName, inner, outer )
|
||||
function ZONE_RADIUS:GetRandomVec2(inner, outer, surfacetypes)
|
||||
|
||||
local Point = {}
|
||||
local Vec2 = self:GetVec2()
|
||||
local _inner = inner or 0
|
||||
local _outer = outer or self:GetRadius()
|
||||
|
||||
local angle = math.random() * math.pi * 2;
|
||||
Point.x = Vec2.x + math.cos( angle ) * math.random(_inner, _outer);
|
||||
Point.y = Vec2.y + math.sin( angle ) * math.random(_inner, _outer);
|
||||
if surfacetypes and type(surfacetypes)~="table" then
|
||||
surfacetypes={surfacetypes}
|
||||
end
|
||||
|
||||
self:T( { Point } )
|
||||
local function _getpoint()
|
||||
local point = {}
|
||||
local angle = math.random() * math.pi * 2
|
||||
point.x = Vec2.x + math.cos(angle) * math.random(_inner, _outer)
|
||||
point.y = Vec2.y + math.sin(angle) * math.random(_inner, _outer)
|
||||
return point
|
||||
end
|
||||
|
||||
return Point
|
||||
local function _checkSurface(point)
|
||||
for _,sf in pairs(surfacetypes) do
|
||||
if sf==land.getSurfaceType(point) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local point=_getpoint()
|
||||
|
||||
if surfacetypes then
|
||||
local N=1 ; local Nmax=1000
|
||||
while _checkSurface(point)==false and N<=Nmax do
|
||||
point=_getpoint()
|
||||
N=N+1
|
||||
end
|
||||
end
|
||||
|
||||
return point
|
||||
end
|
||||
|
||||
--- Returns a @{Core.Point#POINT_VEC2} object reflecting a random 2D location within the zone.
|
||||
@ -1126,15 +1150,15 @@ end
|
||||
|
||||
--- Returns a @{Core.Point#COORDINATE} object reflecting a random 3D location within the zone.
|
||||
-- @param #ZONE_RADIUS self
|
||||
-- @param #number inner (optional) Minimal distance from the center of the zone. Default is 0.
|
||||
-- @param #number outer (optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||
-- @return Core.Point#COORDINATE
|
||||
function ZONE_RADIUS:GetRandomCoordinate( inner, outer )
|
||||
self:F( self.ZoneName, inner, outer )
|
||||
-- @param #number inner (Optional) Minimal distance from the center of the zone. Default is 0.
|
||||
-- @param #number outer (Optional) Maximal distance from the outer edge of the zone. Default is the radius of the zone.
|
||||
-- @param #table surfacetypes (Optional) Table of surface types. Can also be a single surface type. We will try max 1000 times to find the right type!
|
||||
-- @return Core.Point#COORDINATE The random coordinate.
|
||||
function ZONE_RADIUS:GetRandomCoordinate(inner, outer, surfacetypes)
|
||||
|
||||
local Coordinate = COORDINATE:NewFromVec2( self:GetRandomVec2(inner, outer) )
|
||||
local vec2=self:GetRandomVec2(inner, outer, surfacetypes)
|
||||
|
||||
self:T3( { Coordinate = Coordinate } )
|
||||
local Coordinate = COORDINATE:NewFromVec2(vec2)
|
||||
|
||||
return Coordinate
|
||||
end
|
||||
|
||||
@ -1176,6 +1176,8 @@ function ARMYGROUP:_InitGroup()
|
||||
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 cruise = %.1f Knots\n", UTILS.KmphToKnots(self.speedCruise))
|
||||
text=text..string.format("Weight = %.1f kg\n", self:GetWeightTotal())
|
||||
text=text..string.format("Cargo bay = %.1f kg\n", self:GetFreeCargobay())
|
||||
text=text..string.format("Elements = %d\n", #self.elements)
|
||||
text=text..string.format("Waypoints = %d\n", #self.waypoints)
|
||||
text=text..string.format("Radio = %.1f MHz %s %s\n", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu), tostring(self.radio.On))
|
||||
|
||||
@ -358,6 +358,14 @@ function FLIGHTGROUP:SetAirwing(airwing)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Set if aircraft is VTOL capable. Unfortunately, there is no DCS way to determine this via scripting.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return #FLIGHTGROUP self
|
||||
function FLIGHTGROUP:SetVTOL()
|
||||
self.isVTOL=true
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get airwing the flight group belongs to.
|
||||
-- @param #FLIGHTGROUP self
|
||||
-- @return Ops.AirWing#AIRWING The AIRWING object.
|
||||
@ -1674,13 +1682,17 @@ function FLIGHTGROUP:onafterAirborne(From, Event, To)
|
||||
|
||||
if self.isAI then
|
||||
if self:IsTransporting() then
|
||||
if self.cargoTransport and self.cargoTransport.deployzone and self.cargoTransport.deployzone:IsInstanceOf("ZONE_AIRBASE") then
|
||||
env.info("FF transporting land at airbase ")
|
||||
local airbase=self.cargoTransport.deployzone:GetAirbase()
|
||||
self:LandAtAirbase(airbase)
|
||||
end
|
||||
elseif self:IsPickingup() then
|
||||
if self.cargoTransport and self.cargoTransport.pickupzone and self.cargoTransport.pickupzone:IsInstanceOf("ZONE_AIRBASE") then
|
||||
env.info("FF pickingup land at airbase ")
|
||||
local airbase=self.cargoTransport.pickupzone:GetAirbase()
|
||||
self:LandAtAirbase(airbase)
|
||||
end
|
||||
else
|
||||
self:_CheckGroupDone(1)
|
||||
end
|
||||
@ -2919,12 +2931,14 @@ function FLIGHTGROUP:_InitGroup()
|
||||
self.refueltype=select(2, unit:IsRefuelable())
|
||||
|
||||
-- Debug info.
|
||||
if self.verbose>=1 then
|
||||
if self.verbose>=0 then
|
||||
local text=string.format("Initialized Flight Group %s:\n", self.groupname)
|
||||
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("Range max = %.1f km\n", self.rangemax/1000)
|
||||
text=text..string.format("Ceiling = %.1f feet\n", UTILS.MetersToFeet(self.ceiling))
|
||||
text=text..string.format("Weight = %.1f kg\n", self:GetWeightTotal())
|
||||
text=text..string.format("Cargo bay = %.1f kg\n", self:GetFreeCargobay())
|
||||
text=text..string.format("Tanker type = %s\n", tostring(self.tankertype))
|
||||
text=text..string.format("Refuel type = %s\n", tostring(self.refueltype))
|
||||
text=text..string.format("AI = %s\n", tostring(self.isAI))
|
||||
@ -3295,6 +3309,7 @@ function FLIGHTGROUP:InitWaypoints()
|
||||
-- Get home and destination airbases from waypoints.
|
||||
self.homebase=self.homebase or self:GetHomebaseFromWaypoints()
|
||||
self.destbase=self.destbase or self:GetDestinationFromWaypoints()
|
||||
self.currbase=self:GetHomebaseFromWaypoints()
|
||||
|
||||
-- Remove the landing waypoint. We use RTB for that. It makes adding new waypoints easier as we do not have to check if the last waypoint is the landing waypoint.
|
||||
if self.destbase then
|
||||
|
||||
@ -677,7 +677,8 @@ function NAVYGROUP:onafterSpawned(From, Event, To)
|
||||
|
||||
-- Set radio.
|
||||
if self.radioDefault then
|
||||
self:SwitchRadio()
|
||||
-- CAREFUL: This makes DCS crash for some ships like speed boats or Higgins boats! (On a respawn for example). Looks like the command SetFrequency is causing this.
|
||||
--self:SwitchRadio()
|
||||
else
|
||||
self:SetDefaultRadio(self.radio.Freq, self.radio.Modu, false)
|
||||
end
|
||||
@ -1186,6 +1187,8 @@ function NAVYGROUP:_InitGroup()
|
||||
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 cruise = %.1f Knots\n", UTILS.KmphToKnots(self.speedCruise))
|
||||
text=text..string.format("Weight = %.1f kg\n", self:GetWeightTotal())
|
||||
text=text..string.format("Cargo bay = %.1f kg\n", self:GetFreeCargobay())
|
||||
text=text..string.format("Elements = %d\n", #self.elements)
|
||||
text=text..string.format("Waypoints = %d\n", #self.waypoints)
|
||||
text=text..string.format("Radio = %.1f MHz %s %s\n", self.radio.Freq, UTILS.GetModulationName(self.radio.Modu), tostring(self.radio.On))
|
||||
|
||||
@ -19,13 +19,14 @@
|
||||
-- @field #string lid Class id string for output to DCS log file.
|
||||
-- @field #string groupname Name of the group.
|
||||
-- @field Wrapper.Group#GROUP group Group object.
|
||||
-- @field #table template Template of the group.
|
||||
-- @field DCS#Template template Template table of the group.
|
||||
-- @field #boolean isLateActivated Is the group late activated.
|
||||
-- @field #boolean isUncontrolled Is the group uncontrolled.
|
||||
-- @field #boolean isFlightgroup Is a FLIGHTGROUP.
|
||||
-- @field #boolean isArmygroup Is an ARMYGROUP.
|
||||
-- @field #boolean isNavygroup Is a NAVYGROUP.
|
||||
-- @field #boolean isHelo If true, the is a helicopter group.
|
||||
-- @field #boolean isVTOL If true, the is capable of Vertical TakeOff and Landing (VTOL).
|
||||
-- @field #table elements Table of elements, i.e. units of the group.
|
||||
-- @field #boolean isAI If true, group is purely AI.
|
||||
-- @field #boolean isAircraft If true, group is airplane or helicopter.
|
||||
@ -108,6 +109,7 @@
|
||||
-- @field #OPSGROUP.CargoTransport cargoTransport Current cargo transport assignment.
|
||||
-- @field #string cargoStatus Cargo status of this group acting as cargo.
|
||||
-- @field #string carrierStatus Carrier status of this group acting as cargo carrier.
|
||||
-- @field #number cargocounter Running number of cargo UIDs.
|
||||
--
|
||||
-- @extends Core.Fsm#FSM
|
||||
|
||||
@ -165,6 +167,7 @@ OPSGROUP = {
|
||||
weaponData = {},
|
||||
cargoqueue = {},
|
||||
cargoBay = {},
|
||||
cargocounter = 1,
|
||||
}
|
||||
|
||||
|
||||
@ -499,6 +502,7 @@ function OPSGROUP:New(group)
|
||||
self:SetLaser(1688, true, false, 0.5)
|
||||
self.cargoStatus=OPSGROUP.CargoStatus.NOTCARGO
|
||||
self.carrierStatus=OPSGROUP.CarrierStatus.NOTCARRIER
|
||||
self.cargocounter=1
|
||||
|
||||
-- Init task counter.
|
||||
self.taskcurrent=0
|
||||
@ -582,7 +586,8 @@ function OPSGROUP:New(group)
|
||||
self:AddTransition("*", "Transport", "*") -- Carrier is transporting cargo.
|
||||
self:AddTransition("*", "Deploy", "*") -- Carrier is dropping off cargo.
|
||||
self:AddTransition("*", "Unload", "*") -- Carrier unload a cargo group.
|
||||
self:AddTransition("*", "Unloaded", "*") -- Carrier unloaded all its cargo.
|
||||
self:AddTransition("*", "Unloaded", "*") -- Carrier unloaded all its current cargo.
|
||||
self:AddTransition("*", "Delivered", "*") -- Carrier delivered ALL cargo of the transport assignment.
|
||||
|
||||
------------------------
|
||||
--- Pseudo Functions ---
|
||||
@ -1292,6 +1297,7 @@ function OPSGROUP:Despawn(Delay, NoEventRemoveUnit)
|
||||
if unit then
|
||||
local name=unit:getName()
|
||||
if name then
|
||||
-- Despawn the unit.
|
||||
self:DespawnUnit(name, 0, NoEventRemoveUnit)
|
||||
end
|
||||
end
|
||||
@ -3002,6 +3008,11 @@ end
|
||||
-- @return Ops.Auftrag#AUFTRAG Next mission or *nil*.
|
||||
function OPSGROUP:_GetNextMission()
|
||||
|
||||
-- Check if group is acting as carrier or cargo at the moment.
|
||||
if self:IsTransporting() or self:IsPickingup() or self:IsLoading() or self:IsLoaded() then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Number of missions.
|
||||
local Nmissions=#self.missionqueue
|
||||
|
||||
@ -4376,7 +4387,7 @@ end
|
||||
--- Respawn the group.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param #number Delay Delay in seconds before respawn happens. Default 0.
|
||||
-- @param #table Template (optional) The template of the Group retrieved with GROUP:GetTemplate(). If the template is not provided, the template will be retrieved of the group itself.
|
||||
-- @param DCS#Template Template (optional) The template of the Group retrieved with GROUP:GetTemplate(). If the template is not provided, the template will be retrieved of the group itself.
|
||||
-- @param #boolean Reset Reset positions if TRUE.
|
||||
-- @return #OPSGROUP self
|
||||
function OPSGROUP:_Respawn(Delay, Template, Reset)
|
||||
@ -4390,17 +4401,6 @@ function OPSGROUP:_Respawn(Delay, Template, Reset)
|
||||
-- Given template or get old.
|
||||
Template=Template or UTILS.DeepCopy(self.template)
|
||||
|
||||
-- Get correct heading.
|
||||
local function _Heading(course)
|
||||
local h
|
||||
if course<=180 then
|
||||
h=math.rad(course)
|
||||
else
|
||||
h=-math.rad(360-course)
|
||||
end
|
||||
return h
|
||||
end
|
||||
|
||||
if self:IsAlive() then
|
||||
|
||||
---
|
||||
@ -4467,6 +4467,10 @@ function OPSGROUP:_Respawn(Delay, Template, Reset)
|
||||
-- Spawn new group.
|
||||
_DATABASE:Spawn(Template)
|
||||
|
||||
-- Set activation and controlled state.
|
||||
self.isLateActivated=Template.lateActivation
|
||||
self.isUncontrolled=Template.uncontrolled
|
||||
|
||||
-- Reset events.
|
||||
--self:ResetEvents()
|
||||
|
||||
@ -4577,69 +4581,15 @@ function OPSGROUP:_CheckCargoTransport()
|
||||
end
|
||||
self:I(self.lid..text)
|
||||
|
||||
|
||||
if self.cargoTransport then
|
||||
-- TODO: Check if this group can actually transport any cargo.
|
||||
|
||||
local done=true
|
||||
for _,_cargo in pairs(self.cargoTransport.cargos) do
|
||||
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
||||
|
||||
if cargo.delivered then
|
||||
-- This one is delivered.
|
||||
elseif cargo.opsgroup==nil or cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped() then
|
||||
-- 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=OPSGROUP.TransportStatus.DELIVERED
|
||||
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
|
||||
self:_CheckDelivered(transport)
|
||||
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==OPSGROUP.TransportStatus.SCHEDULED and (cargotransport.importance==nil or cargotransport.importance<=vip) then
|
||||
cargotransport.status=OPSGROUP.TransportStatus.EXECUTING
|
||||
self.cargoTransport=cargotransport
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.cargoTransport=self:_GetNextCargoTransport()
|
||||
end
|
||||
|
||||
-- Now handle the transport.
|
||||
@ -4718,6 +4668,7 @@ function OPSGROUP:_CheckCargoTransport()
|
||||
|
||||
elseif self:IsUnloading() then
|
||||
|
||||
-- Debug info.
|
||||
self:I(self.lid.."Unloading ==> Checking if all cargo was delivered")
|
||||
|
||||
local delivered=true
|
||||
@ -4731,7 +4682,7 @@ function OPSGROUP:_CheckCargoTransport()
|
||||
|
||||
end
|
||||
|
||||
-- Boarding finished ==> Transport cargo.
|
||||
-- Unloading finished ==> pickup next batch or call it a day.
|
||||
if delivered then
|
||||
self:I(self.lid.."Unloading finished ==> Unloaded")
|
||||
self:Unloaded()
|
||||
@ -4746,6 +4697,83 @@ function OPSGROUP:_CheckCargoTransport()
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get cargo transport from cargo queue.
|
||||
-- @param #OPSGROUP self
|
||||
-- @return #OPSGROUP.CargoTransport The next due cargo transport or `nil`.
|
||||
function OPSGROUP:_GetNextCargoTransport()
|
||||
|
||||
-- Abs. mission time in seconds.
|
||||
local Time=timer.getAbsTime()
|
||||
|
||||
-- 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==OPSGROUP.TransportStatus.SCHEDULED and (cargotransport.importance==nil or cargotransport.importance<=vip) then
|
||||
return cargotransport
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Check if all cargo of this transport assignment was delivered.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param #OPSGROUP.CargoTransport The next due cargo transport or `nil`.
|
||||
-- @return #boolean If true, all cargo was delivered.
|
||||
function OPSGROUP:_CheckDelivered(CargoTransport)
|
||||
|
||||
-- TODO: Check if this group can actually transport any cargo.
|
||||
|
||||
local done=true
|
||||
for _,_cargo in pairs(CargoTransport.cargos) do
|
||||
local cargo=_cargo --Ops.OpsGroup#OPSGROUP.CargoGroup
|
||||
|
||||
if cargo.delivered then
|
||||
-- This one is delivered.
|
||||
elseif cargo.opsgroup==nil or cargo.opsgroup:IsDead() or cargo.opsgroup:IsStopped() then
|
||||
-- This one is dead.
|
||||
else
|
||||
done=false --Someone is not done!
|
||||
end
|
||||
|
||||
--TODO: check if ALL remaining cargo is too heavy for this carrier group ==> el
|
||||
|
||||
end
|
||||
|
||||
if done then
|
||||
self:Delivered(CargoTransport)
|
||||
end
|
||||
|
||||
-- Debug info.
|
||||
self:I(self.lid..string.format("Cargotransport UID=%d Status=%s: delivered=%s", CargoTransport.uid, CargoTransport.status, tostring(done)))
|
||||
|
||||
return done
|
||||
end
|
||||
|
||||
--- Create a cargo transport assignment.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param Core.Set#SET_GROUP GroupSet Set of groups to be transported. Can also be a single @{Wrapper.Group#GROUP} object.
|
||||
@ -4763,12 +4791,16 @@ function OPSGROUP:AddCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, Impo
|
||||
-- Create a new cargo transport assignment.
|
||||
local cargotransport=self:CreateCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, Importance, ClockStart, Embarkzone, Disembarkzone, NewCarrierGroup)
|
||||
|
||||
if cargotransport then
|
||||
|
||||
-- Set state to SCHEDULED.
|
||||
cargotransport.status=OPSGROUP.TransportStatus.SCHEDULED
|
||||
|
||||
--Add to cargo queue
|
||||
table.insert(self.cargoqueue, cargotransport)
|
||||
|
||||
end
|
||||
|
||||
return cargotransport
|
||||
end
|
||||
|
||||
@ -4816,7 +4848,7 @@ function OPSGROUP:CreateCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, I
|
||||
|
||||
-- Data structure.
|
||||
local transport={} --#OPSGROUP.CargoTransport
|
||||
transport.uid=1
|
||||
transport.uid=self.cargocounter
|
||||
transport.status=OPSGROUP.TransportStatus.PLANNING
|
||||
transport.pickupzone=Pickupzone
|
||||
transport.deployzone=Deployzone
|
||||
@ -4830,15 +4862,27 @@ function OPSGROUP:CreateCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, I
|
||||
|
||||
-- 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 and self:CanCargo(cargo.opsgroup) then
|
||||
table.insert(transport.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 and self:CanCargo(cargo.opsgroup) then
|
||||
table.insert(transport.cargos, cargo)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- Debug info.
|
||||
@ -4856,7 +4900,13 @@ function OPSGROUP:CreateCargoTransport(GroupSet, Pickupzone, Deployzone, Prio, I
|
||||
self:I(self.lid..text)
|
||||
end
|
||||
|
||||
if #transport.cargos>0 then
|
||||
self.cargocounter=self.cargocounter+1
|
||||
return transport
|
||||
else
|
||||
self:E(self.lid.."ERROR: Cargo too heavy for this carrier group!")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Create a cargo group data structure.
|
||||
@ -4884,7 +4934,7 @@ function OPSGROUP:CreateCargoGroupData(group, Pickupzone, Deployzone)
|
||||
opsgroup=ARMYGROUP:New(group)
|
||||
end
|
||||
else
|
||||
env.info("FF found opsgroup in createcargo")
|
||||
--env.info("FF found opsgroup in createcargo")
|
||||
end
|
||||
|
||||
end
|
||||
@ -4997,6 +5047,25 @@ function OPSGROUP:RedWeightCargo(UnitName, Weight)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Check if the group can be carrier of a cargo group.
|
||||
-- **Note** that the cargo group *cannot* be split into units, i.e. the largest cargo bay of any element of the group must be able to load the whole cargo group in one piece.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param #OPSGROUP CargoGroup Cargo group, which needs a carrier.
|
||||
-- @return #boolean If `true`, there is an element of the group that can load the whole cargo group.
|
||||
function OPSGROUP:CanCargo(CargoGroup)
|
||||
|
||||
local weight=CargoGroup:GetWeightTotal()
|
||||
|
||||
for _,element in pairs(self.elements) do
|
||||
local can=element.weightMaxCargo>=weight
|
||||
if can then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--- Add weight to the internal cargo of an element of the group.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param #OPSGROUP CargoGroup Cargo group, which needs a carrier.
|
||||
@ -5033,6 +5102,7 @@ function OPSGROUP:onafterPickup(From, Event, To, Zone)
|
||||
|
||||
local airbasePickup=nil --Wrapper.Airbase#AIRBASE
|
||||
if Zone and Zone:IsInstanceOf("ZONE_AIRBASE") then
|
||||
env.info("FF 001")
|
||||
airbasePickup=Zone:GetAirbase()
|
||||
end
|
||||
|
||||
@ -5041,17 +5111,22 @@ function OPSGROUP:onafterPickup(From, Event, To, Zone)
|
||||
if self:IsArmygroup() or self:IsNavygroup() then
|
||||
ready4loading=inzone
|
||||
else
|
||||
env.info("FF 002 currbase="..(self.currbase and self.currbase:GetName() or "unknown"))
|
||||
|
||||
-- Aircraft is already parking at the pickup airbase.
|
||||
ready4loading=self.currbase and self.currbase:GetName()==Zone:GetName() and self:IsParking()
|
||||
|
||||
-- If a helo is landed in the zone, we also are ready for loading.
|
||||
if ready4loading==false and self.isHelo and self:IsLandedAt() and inzone then
|
||||
if ready4loading==false and (self.isHelo or self.isVTOL) and self:IsLandedAt() and inzone then
|
||||
ready4loading=true
|
||||
env.info("FF 003")
|
||||
end
|
||||
end
|
||||
|
||||
if ready4loading then
|
||||
|
||||
env.info("FF 004")
|
||||
|
||||
-- We are already in the pickup zone ==> initiate loading.
|
||||
self:Loading()
|
||||
|
||||
@ -5063,23 +5138,27 @@ function OPSGROUP:onafterPickup(From, Event, To, Zone)
|
||||
-- Add waypoint.
|
||||
if self.isFlightgroup then
|
||||
|
||||
if airbasePickup then
|
||||
|
||||
---
|
||||
-- Pickup at airbase
|
||||
---
|
||||
|
||||
if airbasePickup then
|
||||
|
||||
local airbaseCurrent=self.currbase
|
||||
|
||||
if airbaseCurrent then
|
||||
|
||||
env.info("FF 100")
|
||||
|
||||
-- Activate uncontrolled group.
|
||||
if self:IsParking() then
|
||||
env.info("FF 200")
|
||||
self:StartUncontrolled()
|
||||
end
|
||||
|
||||
else
|
||||
-- Order group to land at an airbase.
|
||||
env.info("FF 300")
|
||||
self:LandAtAirbase(airbasePickup)
|
||||
end
|
||||
|
||||
@ -5286,7 +5365,7 @@ function OPSGROUP:onafterTransport(From, Event, To, Zone)
|
||||
ready2deploy=self.currbase and self.currbase:GetName()==Zone:GetName() and self:IsParking()
|
||||
|
||||
-- If a helo is landed in the zone, we also are ready for loading.
|
||||
if ready2deploy==false and self.isHelo and self:IsLandedAt() and inzone then
|
||||
if ready2deploy==false and (self.isHelo or self.isVTOL) and self:IsLandedAt() and inzone then
|
||||
ready2deploy=true
|
||||
end
|
||||
end
|
||||
@ -5454,6 +5533,7 @@ function OPSGROUP:onafterUnload(From, Event, To, OpsGroup, Coordinate, Heading)
|
||||
---
|
||||
|
||||
OpsGroup:Unboard(Coordinate, Heading)
|
||||
|
||||
else
|
||||
|
||||
---
|
||||
@ -5480,7 +5560,6 @@ end
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param Core.Zone#ZONE Zone Deploy zone.
|
||||
function OPSGROUP:onafterUnloaded(From, Event, To)
|
||||
-- Debug info
|
||||
self:I(self.lid.."Cargo unloaded..")
|
||||
@ -5519,8 +5598,8 @@ function OPSGROUP:onafterUnloaded(From, Event, To)
|
||||
-- This is not a carrier anymore.
|
||||
self.carrierStatus=OPSGROUP.CarrierStatus.NOTCARRIER
|
||||
|
||||
-- No current transport assignment.
|
||||
self.cargoTransport=nil
|
||||
-- Everything delivered.
|
||||
self:Delivered(self.cargoTransport)
|
||||
|
||||
-- Startup uncontrolled aircraft to allow it to go back.
|
||||
if self:IsFlightgroup() then
|
||||
@ -5537,6 +5616,27 @@ function OPSGROUP:onafterUnloaded(From, Event, To)
|
||||
|
||||
end
|
||||
|
||||
--- On after "Delivered" event.
|
||||
-- @param #OPSGROUP self
|
||||
-- @param #string From From state.
|
||||
-- @param #string Event Event.
|
||||
-- @param #string To To state.
|
||||
-- @param #OPSGROUP.CargoTransport CargoTransport
|
||||
function OPSGROUP:onafterDelivered(From, Event, To, CargoTransport)
|
||||
|
||||
-- Set cargo status.
|
||||
CargoTransport.status=OPSGROUP.TransportStatus.DELIVERED
|
||||
|
||||
-- Check if this was the current transport.
|
||||
if self.cargoTransport and self.cargoTransport.uid==CargoTransport.uid then
|
||||
self.cargoTransport=nil
|
||||
end
|
||||
|
||||
-- Remove cargo transport from cargo queue.
|
||||
self:DelCargoTransport(CargoTransport)
|
||||
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- Cargo Group Functions
|
||||
@ -5569,7 +5669,7 @@ function OPSGROUP:onafterBoard(From, Event, To, CarrierGroup, Carrier)
|
||||
local Coordinate=Carrier.unit:GetCoordinate()
|
||||
|
||||
if self.isArmygroup then
|
||||
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Formation, Updateroute)
|
||||
local waypoint=ARMYGROUP.AddWaypoint(self, Coordinate)
|
||||
waypoint.detour=true
|
||||
else
|
||||
local waypoint=NAVYGROUP.AddWaypoint(self, Coordinate)
|
||||
@ -5643,6 +5743,9 @@ function OPSGROUP:onafterUnboard(From, Event, To, Coordinate, Heading, Delay)
|
||||
-- Template for the respawned group.
|
||||
local Template=UTILS.DeepCopy(self.template) --DCS#Template
|
||||
|
||||
-- No late activation.
|
||||
Template.lateActivation=false
|
||||
|
||||
-- Loop over template units.
|
||||
for _,Unit in pairs(Template.units) do
|
||||
|
||||
@ -7869,11 +7972,25 @@ function OPSGROUP:_AddElementByName(unitname)
|
||||
|
||||
-- Weight and cargo.
|
||||
element.weightEmpty=element.descriptors.massEmpty or 666
|
||||
element.weightMaxTotal=element.descriptors.massMax or element.weightEmpty+2*95 --If max mass is not given, we assume 10 soldiers.
|
||||
element.weightMaxCargo=math.max(element.weightMaxTotal-element.weightEmpty, 0)
|
||||
element.weightCargo=0
|
||||
element.weight=element.weightEmpty+element.weightCargo
|
||||
|
||||
-- Looks like only aircraft have a massMax value in the descriptors.
|
||||
element.weightMaxTotal=element.descriptors.massMax or element.weightEmpty+2*95 --If max mass is not given, we assume 10 soldiers.
|
||||
|
||||
|
||||
if self.isArmygroup then
|
||||
|
||||
element.weightMaxTotal=element.weightEmpty+10*95 --If max mass is not given, we assume 10 soldiers.
|
||||
|
||||
elseif self.isNavygroup then
|
||||
|
||||
element.weightMaxTotal=element.weightEmpty+10*1000
|
||||
|
||||
end
|
||||
|
||||
-- Max cargo weight
|
||||
element.weightMaxCargo=math.max(element.weightMaxTotal-element.weightEmpty, 0)
|
||||
|
||||
-- FLIGHTGROUP specific.
|
||||
if self.isFlightgroup then
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user