OPS Cargo

This commit is contained in:
Frank
2021-03-07 23:47:29 +01:00
parent bab097958f
commit 56e2b06e9d
5 changed files with 332 additions and 112 deletions

View File

@@ -115,6 +115,8 @@
-- @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.
-- @field #OPSGROUP.CarrierLoader carrierLoader Carrier loader parameters.
-- @field #OPSGROUP.CarrierLoader carrierUnloader Carrier unloader parameters.
--
-- @extends Core.Fsm#FSM
@@ -174,6 +176,8 @@ OPSGROUP = {
cargoBay = {},
cargocounter = 1,
mycarrier = {},
carrierLoader = {},
carrierUnloader = {},
}
@@ -187,9 +191,9 @@ OPSGROUP = {
-- @field #boolean ai If true, element is AI.
-- @field #string skill Skill level.
--
-- @field Core.Zone#ZONE zoneBoundingbox Bounding box zone of the
-- @field Core.Zone#ZONE zoneLoad Loading zone.
-- @field Core.Zone#ZONE zoneUnload Unloading zone.
-- @field Core.Zone#ZONE_POLYGON_BASE zoneBoundingbox Bounding box zone of the element unit.
-- @field Core.Zone#ZONE_POLYGON_BASE zoneLoad Loading zone.
-- @field Core.Zone#ZONE_POLYGON_BASE zoneUnload Unloading zone.
--
-- @field #string typename Type name.
-- @field #number category Aircraft category.
@@ -409,18 +413,11 @@ OPSGROUP.CargoStatus={
LOADED="loaded",
}
--- Cargo transport status.
-- @type OPSGROUP.TransportStatus
-- @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.
OPSGROUP.TransportStatus={
PLANNING="planning",
SCHEDULED="scheduled",
EXECUTING="executing",
DELIVERED="delivered",
}
--- Cargo carrier loader parameters.
-- @type OPSGROUP.CarrierLoader
-- @field #string type Loader type "Front", "Back", "Left", "Right", "All".
-- @field #number length Length of (un-)loading zone in meters.
-- @field #number width Width of (un-)loading zone in meters.
--- Cargo transport data.
-- @type OPSGROUP.MyCarrier
@@ -503,6 +500,9 @@ function OPSGROUP:New(group)
self.cargoStatus=OPSGROUP.CargoStatus.NOTCARGO
self.carrierStatus=OPSGROUP.CarrierStatus.NOTCARRIER
self.cargocounter=1
self:SetCarrierLoaderAllAspect()
self:SetCarrierUnloaderAllAspect()
-- Init task counter.
self.taskcurrent=0
@@ -1436,8 +1436,8 @@ end
--- Self destruction of group. An explosion is created at the position of each element.
-- @param #OPSGROUP self
-- @param #number Delay Delay in seconds. Default now.
-- @param #number ExplosionPower (Optional) Explosion power in kg TNT. Default 500 kg.
-- @return #number Relative fuel in percent.
-- @param #number ExplosionPower (Optional) Explosion power in kg TNT. Default 100 kg.
-- @return #OPSGROUP self
function OPSGROUP:SelfDestruction(Delay, ExplosionPower)
if Delay and Delay>0 then
@@ -1451,13 +1451,136 @@ function OPSGROUP:SelfDestruction(Delay, ExplosionPower)
local unit=element.unit
if unit and unit:IsAlive() then
unit:Explode(ExplosionPower)
unit:Explode(ExplosionPower or 100)
end
end
end
return self
end
--- Set that this carrier is an all aspect loader.
-- @param #OPSGROUP self
-- @param #number Length Length of loading zone in meters. Default 50 m.
-- @param #number Width Width of loading zone in meters. Default 20 m.
-- @return #OPSGROUP self
function OPSGROUP:SetCarrierLoaderAllAspect(Length, Width)
self.carrierLoader.type="front"
self.carrierLoader.length=Length or 50
self.carrierLoader.width=Width or 20
return self
end
--- Set that this carrier is a front loader.
-- @param #OPSGROUP self
-- @param #number Length Length of loading zone in meters. Default 50 m.
-- @param #number Width Width of loading zone in meters. Default 20 m.
-- @return #OPSGROUP self
function OPSGROUP:SetCarrierLoaderFront(Length, Width)
self.carrierLoader.type="front"
self.carrierLoader.length=Length or 50
self.carrierLoader.width=Width or 20
return self
end
--- Set that this carrier is a back loader.
-- @param #OPSGROUP self
-- @param #number Length Length of loading zone in meters. Default 50 m.
-- @param #number Width Width of loading zone in meters. Default 20 m.
-- @return #OPSGROUP self
function OPSGROUP:SetCarrierLoaderBack(Length, Width)
self.carrierLoader.type="back"
self.carrierLoader.length=Length or 50
self.carrierLoader.width=Width or 20
return self
end
--- Set that this carrier is a starboard (right side) loader.
-- @param #OPSGROUP self
-- @param #number Length Length of loading zone in meters. Default 50 m.
-- @param #number Width Width of loading zone in meters. Default 20 m.
-- @return #OPSGROUP self
function OPSGROUP:SetCarrierLoaderStarboard(Length, Width)
self.carrierLoader.type="right"
self.carrierLoader.length=Length or 50
self.carrierLoader.width=Width or 20
return self
end
--- Set that this carrier is a port (left side) loader.
-- @param #OPSGROUP self
-- @param #number Length Length of loading zone in meters. Default 50 m.
-- @param #number Width Width of loading zone in meters. Default 20 m.
-- @return #OPSGROUP self
function OPSGROUP:SetCarrierLoaderPort(Length, Width)
self.carrierLoader.type="left"
self.carrierLoader.length=Length or 50
self.carrierLoader.width=Width or 20
return self
end
--- Set that this carrier is an all aspect unloader.
-- @param #OPSGROUP self
-- @param #number Length Length of loading zone in meters. Default 50 m.
-- @param #number Width Width of loading zone in meters. Default 20 m.
-- @return #OPSGROUP self
function OPSGROUP:SetCarrierUnloaderAllAspect(Length, Width)
self.carrierUnloader.type="front"
self.carrierUnloader.length=Length or 50
self.carrierUnloader.width=Width or 20
return self
end
--- Set that this carrier is a front unloader.
-- @param #OPSGROUP self
-- @param #number Length Length of loading zone in meters. Default 50 m.
-- @param #number Width Width of loading zone in meters. Default 20 m.
-- @return #OPSGROUP self
function OPSGROUP:SetCarrierUnloaderFront(Length, Width)
self.carrierUnloader.type="front"
self.carrierUnloader.length=Length or 50
self.carrierUnloader.width=Width or 20
return self
end
--- Set that this carrier is a back unloader.
-- @param #OPSGROUP self
-- @param #number Length Length of loading zone in meters. Default 50 m.
-- @param #number Width Width of loading zone in meters. Default 20 m.
-- @return #OPSGROUP self
function OPSGROUP:SetCarrierUnloaderBack(Length, Width)
self.carrierUnloader.type="back"
self.carrierUnloader.length=Length or 50
self.carrierUnloader.width=Width or 20
return self
end
--- Set that this carrier is a starboard (right side) unloader.
-- @param #OPSGROUP self
-- @param #number Length Length of loading zone in meters. Default 50 m.
-- @param #number Width Width of loading zone in meters. Default 20 m.
-- @return #OPSGROUP self
function OPSGROUP:SetCarrierUnloaderStarboard(Length, Width)
self.carrierUnloader.type="right"
self.carrierUnloader.length=Length or 50
self.carrierUnloader.width=Width or 20
return self
end
--- Set that this carrier is a port (left side) unloader.
-- @param #OPSGROUP self
-- @param #number Length Length of loading zone in meters. Default 50 m.
-- @param #number Width Width of loading zone in meters. Default 20 m.
-- @return #OPSGROUP self
function OPSGROUP:SetCarrierUnloaderPort(Length, Width)
self.carrierUnloader.type="left"
self.carrierUnloader.length=Length or 50
self.carrierUnloader.width=Width or 20
return self
end
--- Check if this is a FLIGHTGROUP.
-- @param #OPSGROUP self
-- @return #boolean If true, this is an airplane or helo group.
@@ -5767,27 +5890,12 @@ function OPSGROUP:onafterUnloading(From, Event, To)
Coordinate=self.cargoTransport.disembarkzone:GetRandomCoordinate()
else
-- TODO: Optimize with random Vec2
-- Create a zone around the carrier.
local zoneCarrier=ZONE_RADIUS:New("Carrier", self:GetVec2(), 100)
local d={}
d.p1={x=vec2.x-l/2, y=vec2.y-w/2} --DCS#Vec2
d.p2={x=vec2.x-l/2, y=vec2.y+w/2} --DCS#Vec2
d.p3={x=d2.x+20, y=d2.y+20}
d.p4={x=d1.x+20, y=d1.y+20}
for _,_p in pairs(d) do
local p=_p --#DCSVec2
end
local zoneCarrier=ZONE_POLYGON_BASE:New("Carrier", {d1, d2, d3, d4})
-- Get random point in disembark zone.
local zoneCarrier=self:GetElementZoneUnload(cargo.opsgroup:_GetMyCarrierElement().name)
-- Random coordinate/heading in the zone.
Coordinate=zoneCarrier:GetRandomCoordinate(50)
Coordinate=zoneCarrier:GetRandomCoordinate()
end
@@ -5800,8 +5908,7 @@ function OPSGROUP:onafterUnloading(From, Event, To)
end
-- Trigger "Unloaded" event for current cargo transport
self.cargoTransport:Unloaded(cargo.opsgroup)
self.cargoTransport:Unloaded(cargo.opsgroup)
end
@@ -5898,13 +6005,16 @@ function OPSGROUP:onafterUnload(From, Event, To, OpsGroup, Coordinate, Activated
-- Respawn group.
OpsGroup:_Respawn(0, Template)
if self:IsNavygroup() then
self.currentwp=1
NAVYGROUP.AddWaypoint(self, Coordinate, nil, nil, nil, false)
elseif self:IsArmygroup() then
self.currentwp=1
ARMYGROUP.AddWaypoint(self, Coordinate, nil, nil, nil, false)
end
-- Add current waypoint. These have been cleard on loading.
if OpsGroup:IsNavygroup() then
OpsGroup.currentwp=1
OpsGroup.passedfinalwp=true
NAVYGROUP.AddWaypoint(OpsGroup, Coordinate, nil, nil, nil, false)
elseif OpsGroup:IsArmygroup() then
OpsGroup.currentwp=1
OpsGroup.passedfinalwp=true
ARMYGROUP.AddWaypoint(OpsGroup, Coordinate, nil, nil, nil, false)
end
else
@@ -5919,11 +6029,10 @@ function OPSGROUP:onafterUnload(From, Event, To, OpsGroup, Coordinate, Activated
end
-- Trigger "Disembarked" event.
OpsGroup:Disembarked(OpsGroup.carrierGroup, OpsGroup.carrier)
OpsGroup:Disembarked(OpsGroup:_GetMyCarrierGroup(), OpsGroup:_GetMyCarrierElement())
-- No carrier any more.
OpsGroup.carrier=nil
OpsGroup.carrierGroup=nil
-- Remove my carrier.
OpsGroup:_RemoveMyCarrier()
end
@@ -5966,11 +6075,8 @@ end
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Ops.OpsTransport#OPSTRANSPORT CargoTransport
-- @param Ops.OpsTransport#OPSTRANSPORT CargoTransport The cargo transport assignment.
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
@@ -7995,44 +8101,173 @@ end
-- @param #OPSGROUP self
-- @param #string UnitName Name of unit.
-- @return Core.Zone#ZONE_POLYGON Bounding box polygon zone.
function OPSGROUP:GetElementBoundingBox(UnitName)
function OPSGROUP:GetElementZoneBoundingBox(UnitName)
local element=self:GetElementByName(UnitName)
if element and element.status~=OPSGROUP.ElementStatus.DEAD then
-- Create a new zone if necessary.
element.zoneBoundingbox=element.zoneBoundingbox or ZONE_POLYGON_BASE:New(element.name.." Zone Bounding Box", {})
local l=element.length
local w=element.width
local heading=element.unit:GetHeading()
local X=self:GetOrientationX(element.name)
local heading=math.deg(math.atan2(X.z, X.x))
env.info(string.format("FF l=%d w=%d h=%d", l, w, heading))
local vec2=self:GetVec2(element.name)
-- Set of
-- Set of edges facing "North" at the origin of the map.
local b={}
b[1]={y=l/2, x=-w/2} --DCS#Vec2
b[2]={y=l/2, x=w/2} --DCS#Vec2
b[3]={y=-l/2, x=w/2} --DCS#Vec2
b[4]={y=-l/2, x=-w/2} --DCS#Vec2
b[1]={x=l/2, y=-w/2} --DCS#Vec2
b[2]={x=l/2, y=w/2} --DCS#Vec2
b[3]={x=-l/2, y=w/2} --DCS#Vec2
b[4]={x=-l/2, y=-w/2} --DCS#Vec2
-- Rotate box to match current heading of the unit.
for i,p in pairs(b) do
b[i]=UTILS.Vec2Rotate2D(p, heading)
end
-- Translate the zone to the positon of the unit.
local vec2=self:GetVec2(element.name)
local d=UTILS.Vec2Norm(vec2)
local h=UTILS.Vec2Hdg(vec2)
for i,p in pairs(b) do
--b[i]=UTILS.Vec2Translate(p, d, h)
b[i]=UTILS.Vec2Translate(p, d, h)
end
-- Update existing zone.
element.zoneBoundingbox:UpdateFromVec2(b)
return ZONE_POLYGON_BASE:New(element.name, b)
return element.zoneBoundingbox
end
return nil
end
--- Get the loading zone of the element.
-- @param #OPSGROUP self
-- @param #string UnitName Name of unit.
-- @return Core.Zone#ZONE_POLYGON Bounding box polygon zone.
function OPSGROUP:GetElementZoneLoad(UnitName)
local element=self:GetElementByName(UnitName)
if element and element.status~=OPSGROUP.ElementStatus.DEAD then
element.zoneLoad=element.zoneLoad or ZONE_POLYGON_BASE:New(element.name.." Zone Load", {})
self:_GetElementZoneLoader(element, element.zoneLoad, self.carrierLoader)
return element.zoneLoad
end
return nil
end
--- Get the unloading zone of the element.
-- @param #OPSGROUP self
-- @param #string UnitName Name of unit.
-- @return Core.Zone#ZONE_POLYGON Bounding box polygon zone.
function OPSGROUP:GetElementZoneUnload(UnitName)
local element=self:GetElementByName(UnitName)
if element and element.status~=OPSGROUP.ElementStatus.DEAD then
element.zoneUnload=element.zoneUnload or ZONE_POLYGON_BASE:New(element.name.." Zone Unload", {})
self:_GetElementZoneLoader(element, element.zoneUnload, self.carrierUnloader)
return element.zoneUnload
end
return nil
end
--- Get/update the (un-)loading zone of the element.
-- @param #OPSGROUP self
-- @param #OPSGROUP.Element Element Element.
-- @param Core.Zone#ZONE_POLYGON Zone The zone.
-- @param #OPSGROUP.CarrierLoader Loader Loader parameters.
-- @return Core.Zone#ZONE_POLYGON Bounding box polygon zone.
function OPSGROUP:_GetElementZoneLoader(Element, Zone, Loader)
if Element.status~=OPSGROUP.ElementStatus.DEAD then
local l=Element.length
local w=Element.width
-- Orientation 3D vector where the "nose" is pointing.
local X=self:GetOrientationX(Element.name)
-- Heading in deg.
local heading=math.deg(math.atan2(X.z, X.x))
env.info(string.format("FF l=%d w=%d h=%d", l, w, heading))
-- Bounding box at the origin of the map facing "North".
local b={}
-- Create polygon rectangles.
if Loader.type:lower()=="front" then
table.insert(b, {x= l/2, y=-Loader.width/2}) -- left, low
table.insert(b, {x= l/2+Loader.length, y=-Loader.width/2}) -- left, up
table.insert(b, {x= l/2+Loader.length, y= Loader.width/2}) -- right, up
table.insert(b, {x= l/2, y= Loader.width/2}) -- right, low
elseif Loader.type:lower()=="back" then
table.insert(b, {x=-l/2, y=-Loader.width/2}) -- left, low
table.insert(b, {x=-l/2-Loader.length, y=-Loader.width/2}) -- left, up
table.insert(b, {x=-l/2-Loader.length, y= Loader.width/2}) -- right, up
table.insert(b, {x=-l/2, y= Loader.width/2}) -- right, low
elseif Loader.type:lower()=="left" then
table.insert(b, {x= Loader.length/2, y= -w/2}) -- right, up
table.insert(b, {x= Loader.length/2, y= -w/2-Loader.width}) -- left, up
table.insert(b, {x=-Loader.length/2, y= -w/2-Loader.width}) -- left, down
table.insert(b, {x=-Loader.length/2, y= -w/2}) -- right, down
elseif Loader.type:lower()=="right" then
table.insert(b, {x= Loader.length/2, y= w/2}) -- right, up
table.insert(b, {x= Loader.length/2, y= w/2+Loader.width}) -- left, up
table.insert(b, {x=-Loader.length/2, y= w/2+Loader.width}) -- left, down
table.insert(b, {x=-Loader.length/2, y= w/2}) -- right, down
else
-- All aspect. Rectangle around the unit but need to cut out the area of the unit itself.
b[1]={x= l/2, y=-w/2} --DCS#Vec2
b[2]={x= l/2, y= w/2} --DCS#Vec2
b[3]={x=-l/2, y= w/2} --DCS#Vec2
b[4]={x=-l/2, y=-w/2} --DCS#Vec2
table.insert(b, {x=b[1].x+Loader.length, y=b[1].y-Loader.width})
table.insert(b, {x=b[2].x+Loader.length, y=b[2].y+Loader.width})
table.insert(b, {x=b[3].x-Loader.length, y=b[3].y+Loader.width})
table.insert(b, {x=b[4].x-Loader.length, y=b[4].y-Loader.width})
end
-- Rotate edges to match the current heading of the unit.
for i,p in pairs(b) do
b[i]=UTILS.Vec2Rotate2D(p, heading)
end
-- Translate box to the current position of the unit.
local vec2=self:GetVec2(Element.name)
local d=UTILS.Vec2Norm(vec2)
local h=UTILS.Vec2Hdg(vec2)
for i,p in pairs(b) do
b[i]=UTILS.Vec2Translate(p, d, h)
end
-- Update existing zone.
Zone:UpdateFromVec2(b)
return Zone
end
return nil
end
--- Get the first element of a group, which is alive.
-- @param #OPSGROUP self
-- @return #OPSGROUP.Element The element or `#nil` if no element is alive any more.
@@ -8399,9 +8634,7 @@ function OPSGROUP:_AddElementByName(unitname)
end
-- Max cargo weight
--element.weightMaxCargo=math.max(element.weightMaxTotal-element.weightEmpty, 0)
-- Max cargo weight:
unit:SetCargoBayWeightLimit()
element.weightMaxCargo=unit.__.CargoBayWeightLimit