Optimized the boarding and unboarding of cargo. fixed bug when in defence of APC, cargo would not be loaded. The boarding and unboarding has become much more stable now.

This commit is contained in:
FlightControl 2018-10-18 07:27:50 +02:00
commit f0ac7818b3
8 changed files with 247 additions and 166 deletions

View File

@ -307,7 +307,7 @@ function AI_CARGO:onafterBoard( Carrier, From, Event, To, Cargo, CarrierUnit, Pi
if Carrier and Carrier:IsAlive() then if Carrier and Carrier:IsAlive() then
self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), Carrier:GetName() } ) self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), Carrier:GetName() } )
if not Cargo:IsLoaded() then if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
self:__Board( -10, Cargo, CarrierUnit, PickupZone ) self:__Board( -10, Cargo, CarrierUnit, PickupZone )
return return
end end
@ -487,6 +487,7 @@ function AI_CARGO:onafterDeployed( Carrier, From, Event, To, DeployZone, Defend
self.Transporting = false self.Transporting = false
else else
self:F( "Defending" ) self:F( "Defending" )
end end
end end

View File

@ -276,34 +276,36 @@ function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
if self.CarrierCoordinate then if self.CarrierCoordinate then
if self:IsTransporting() == true then if self:IsTransporting() == true then
local Coordinate = APC:GetCoordinate() local Coordinate = APC:GetCoordinate()
self.Zone:Scan( { Object.Category.UNIT } ) if self:Is( "Unloaded" ) or self:Is( "Loaded" ) then
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then self.Zone:Scan( { Object.Category.UNIT } )
if self:Is( "Unloaded" ) or self:Is( "Following" ) then if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
-- There are no enemies within combat radius. Load the CargoCarrier.
self:Load()
end
else
if self:Is( "Loaded" ) then
-- There are enemies within combat radius. Unload the CargoCarrier.
self:__Unload( 1, nil, true ) -- The 2nd parameter is true, which means that the unload is for defending the carrier, not to deploy!
else
if self:Is( "Unloaded" ) then if self:Is( "Unloaded" ) then
self:Follow() -- There are no enemies within combat radius. Load the CargoCarrier.
self:Load()
end end
self:F( "I am here" .. self:GetCurrentState() ) else
if self:Is( "Following" ) then if self:Is( "Loaded" ) then
for Cargo, APCUnit in pairs( self.Carrier_Cargo ) do -- There are enemies within combat radius. Unload the CargoCarrier.
local Cargo = Cargo -- Cargo.Cargo#CARGO self:__Unload( 1, nil, true ) -- The 2nd parameter is true, which means that the unload is for defending the carrier, not to deploy!
local APCUnit = APCUnit -- Wrapper.Unit#UNIT else
if Cargo:IsAlive() then if self:Is( "Unloaded" ) then
if not Cargo:IsNear( APCUnit, 40 ) then --self:Follow()
APCUnit:RouteStop() end
self.CarrierStopped = true self:F( "I am here" .. self:GetCurrentState() )
else if self:Is( "Following" ) then
if self.CarrierStopped then for Cargo, APCUnit in pairs( self.Carrier_Cargo ) do
if Cargo:IsNear( APCUnit, 25 ) then local Cargo = Cargo -- Cargo.Cargo#CARGO
APCUnit:RouteResume() local APCUnit = APCUnit -- Wrapper.Unit#UNIT
self.CarrierStopped = nil if Cargo:IsAlive() then
if not Cargo:IsNear( APCUnit, 40 ) then
APCUnit:RouteStop()
self.CarrierStopped = true
else
if self.CarrierStopped then
if Cargo:IsNear( APCUnit, 25 ) then
APCUnit:RouteResume()
self.CarrierStopped = nil
end
end end
end end
end end
@ -455,6 +457,30 @@ function AI_CARGO_APC:onafterDeployed( APC, From, Event, To, DeployZone, Defend
self:__Guard( 0.1 ) self:__Guard( 0.1 )
self:GetParent( self, AI_CARGO_APC ).onafterDeployed( self, APC, From, Event, To, DeployZone, Defend ) self:GetParent( self, AI_CARGO_APC ).onafterDeployed( self, APC, From, Event, To, DeployZone, Defend )
-- If Defend == true then we need to scan for possible enemies within combat zone and engage only ground forces.
if Defend == true then
self.Zone:Scan( { Object.Category.UNIT } )
if not self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
-- OK, enemies nearby, now find the enemies and attack them.
local AttackUnits = self.Zone:GetScannedUnits() -- #list<DCS#Unit>
local Move = {}
for CargoId, CargoData in pairs( self.CargoSet:GetSet() ) do
local CargoGroup = CargoData.CargoObject -- Wrapper.Group#GROUP
Move[#Move+1] = CargoGroup:GetCoordinate():WaypointGround( 70, "Custom" )
for UnitId, AttackUnit in pairs( AttackUnits ) do
local MooseUnit = UNIT:Find( AttackUnit )
if MooseUnit:GetCoalition() ~= CargoGroup:GetCoalition() then
Move[#Move+1] = MooseUnit:GetCoordinate():WaypointGround( 70, "Line abreast" )
--MoveTo.Task = CargoGroup:TaskCombo( CargoGroup:TaskAttackUnit( MooseUnit, true ) )
self:F( { MooseUnit = MooseUnit:GetName(), CargoGroup = CargoGroup:GetName() } )
end
end
CargoGroup:RoutePush( Move, 0.1 )
end
end
end
end end

View File

@ -1143,7 +1143,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
LargestLoadCapacity = LoadCapacity LargestLoadCapacity = LoadCapacity
end end
end end
-- So if there is aa carrier that has the required load capacity to load the total weight of the cargo, dispatch the carrier. -- So if there is a carrier that has the required load capacity to load the total weight of the cargo, dispatch the carrier.
-- Otherwise break and go to the next carrier. -- Otherwise break and go to the next carrier.
-- This will skip cargo which is too large to be able to be loaded by carriers -- This will skip cargo which is too large to be able to be loaded by carriers
-- and will secure an efficient dispatching scheme. -- and will secure an efficient dispatching scheme.

View File

@ -20,9 +20,9 @@
do -- CARGO_GROUP do -- CARGO_GROUP
--- @type CARGO_GROUP --- @type CARGO_GROUP
-- @extends Cargo.Cargo#CARGO_REPORTABLE
-- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects. -- @field Core.Set#SET_CARGO CargoSet The collection of derived CARGO objects.
-- @field #string GroupName The name of the CargoGroup. -- @field #string GroupName The name of the CargoGroup.
-- @extends Cargo.Cargo#CARGO_REPORTABLE
--- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator. --- Defines a cargo that is represented by a @{Wrapper.Group} object within the simulator.
-- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers. -- The cargo can be Loaded, UnLoaded, Boarded, UnBoarded to and from Carriers.
@ -291,29 +291,27 @@ do -- CARGO_GROUP
end end
--- Enter Boarding State. --- After Board Event.
-- @param #CARGO_GROUP self -- @param #CARGO_GROUP self
-- @param #string Event -- @param #string Event
-- @param #string From -- @param #string From
-- @param #string To -- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier -- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) function CARGO_GROUP:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } ) self:F( { CargoCarrier.UnitName, From, Event, To, NearRadius = NearRadius } )
NearRadius = NearRadius or self.NearRadius NearRadius = NearRadius or self.NearRadius
if From == "UnLoaded" then -- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2
self.CargoSet:ForEach(
-- For each Cargo object within the CARGO_GROUPED, route each object to the CargoLoadPointVec2 function( Cargo, ... )
self.CargoSet:ForEach( self:F( { "Board Unit", Cargo:GetName( ), Cargo:IsDestroyed(), Cargo.CargoObject:IsAlive() } )
function( Cargo, ... ) Cargo:__Board( 1, CargoCarrier, NearRadius, ... )
Cargo:__Board( 1, CargoCarrier, NearRadius, ... ) end, ...
end, ... )
)
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
self:__Boarding( 1, CargoCarrier, NearRadius, ... )
end
end end
@ -323,13 +321,15 @@ do -- CARGO_GROUP
-- @param #string From -- @param #string From
-- @param #string To -- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier -- @param Wrapper.Unit#UNIT CargoCarrier
function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... ) function CARGO_GROUP:onafterLoad( From, Event, To, CargoCarrier, ... )
--self:F( { From, Event, To, CargoCarrier, ...} ) --self:F( { From, Event, To, CargoCarrier, ...} )
if From == "UnLoaded" then if From == "UnLoaded" then
-- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier. -- For each Cargo object within the CARGO_GROUP, load each cargo to the CargoCarrier.
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
Cargo:Load( CargoCarrier ) if not Cargo:IsDestroyed() then
Cargo:Load( CargoCarrier )
end
end end
end end
@ -360,7 +360,7 @@ do -- CARGO_GROUP
--self:T( { Cargo:GetName(), Cargo.current } ) --self:T( { Cargo:GetName(), Cargo.current } )
if not Cargo:is( "Loaded" ) if not Cargo:is( "Loaded" )
and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function. and (not Cargo:is( "Destroyed" )) then -- If one or more units of a group defined as CARGO_GROUP died, the CARGO_GROUP:Board() command does not trigger the CARGO_GRUOP:OnEnterLoaded() function.
Boarded = false Boarded = false
end end
@ -400,7 +400,7 @@ do -- CARGO_GROUP
-- @param #string To -- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2 -- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) function CARGO_GROUP:onafterUnBoard( From, Event, To, ToPointVec2, NearRadius, ... )
self:F( {From, Event, To, ToPointVec2, NearRadius } ) self:F( {From, Event, To, ToPointVec2, NearRadius } )
NearRadius = NearRadius or 25 NearRadius = NearRadius or 25
@ -443,7 +443,7 @@ do -- CARGO_GROUP
-- @param #string To -- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2 -- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier. -- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... ) function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
--self:F( { From, Event, To, ToPointVec2, NearRadius } ) --self:F( { From, Event, To, ToPointVec2, NearRadius } )
--local NearRadius = NearRadius or 25 --local NearRadius = NearRadius or 25
@ -464,7 +464,7 @@ do -- CARGO_GROUP
end end
if UnBoarded then if UnBoarded then
return true self:__UnLoad( 1, ToPointVec2, ... )
else else
self:__UnBoarding( 1, ToPointVec2, NearRadius, ... ) self:__UnBoarding( 1, ToPointVec2, NearRadius, ... )
end end
@ -474,30 +474,13 @@ do -- CARGO_GROUP
end end
--- UnBoard Event.
-- @param #CARGO_GROUP self
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
--local NearRadius = NearRadius or 25
self:__UnLoad( 1, ToPointVec2, ... )
end
--- Enter UnLoaded State. --- Enter UnLoaded State.
-- @param #CARGO_GROUP self -- @param #CARGO_GROUP self
-- @param #string Event -- @param #string Event
-- @param #string From -- @param #string From
-- @param #string To -- @param #string To
-- @param Core.Point#POINT_VEC2 -- @param Core.Point#POINT_VEC2
function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... ) function CARGO_GROUP:onafterUnLoad( From, Event, To, ToPointVec2, ... )
--self:F( { From, Event, To, ToPointVec2 } ) --self:F( { From, Event, To, ToPointVec2 } )
if From == "Loaded" then if From == "Loaded" then
@ -507,7 +490,7 @@ do -- CARGO_GROUP
function( Cargo ) function( Cargo )
--Cargo:UnLoad( ToPointVec2 ) --Cargo:UnLoad( ToPointVec2 )
local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10) local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10)
Cargo:UnLoad( RandomVec2 ) Cargo:UnBoard( RandomVec2 )
end end
) )

View File

@ -233,46 +233,47 @@ do -- CARGO_UNIT
--self:F({Unit=self.CargoObject:GetName()}) --self:F({Unit=self.CargoObject:GetName()})
-- Only move the group to the carrier when the cargo is not in the air -- A cargo unit can only be boarded if it is not dead
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
if not self.CargoInAir then -- Only move the group to the carrier when the cargo is not in the air
-- If NearRadius is given, then use the given NearRadius, otherwise calculate the NearRadius -- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
-- based upon the Carrier bounding radius, which is calculated from the bounding rectangle on the Y axis. if not self.CargoInAir then
local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius() + 5 -- If NearRadius is given, then use the given NearRadius, otherwise calculate the NearRadius
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then -- based upon the Carrier bounding radius, which is calculated from the bounding rectangle on the Y axis.
self:Load( CargoCarrier, NearRadius, ... ) local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius() + 5
else if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
if MaxSpeed and MaxSpeed == 0 or TypeName and TypeName == "Stinger comm" then
self:Load( CargoCarrier, NearRadius, ... ) self:Load( CargoCarrier, NearRadius, ... )
else else
if MaxSpeed and MaxSpeed == 0 or TypeName and TypeName == "Stinger comm" then
self:Load( CargoCarrier, NearRadius, ... )
else
local Speed = 90
local Angle = 180
local Distance = 0
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
-- Set the CargoObject to state Green to ensure it is boarding!
self.CargoObject:OptionAlarmStateGreen()
local Points = {}
local Speed = 90 local PointStartVec2 = self.CargoObject:GetPointVec2()
local Angle = 180
local Distance = 0
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2() Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 2 )
-- Set the CargoObject to state Green to ensure it is boarding! self:__Boarding( -5, CargoCarrier, NearRadius, ... )
self.CargoObject:OptionAlarmStateGreen() self.RunCount = 0
end
local Points = {}
local PointStartVec2 = self.CargoObject:GetPointVec2()
Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 2 )
self:__Boarding( -5, CargoCarrier, NearRadius, ... )
self.RunCount = 0
end end
end end
end
end end
@ -286,53 +287,53 @@ do -- CARGO_UNIT
function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... ) function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } ) self:F( { From, Event, To, CargoCarrier:GetName(), NearRadius = NearRadius } )
--self:F({Unit=self.CargoObject:GetName()}) self:F( { IsAlive=self.CargoObject:IsAlive() } )
if CargoCarrier and CargoCarrier:IsAlive() then -- and self.CargoObject and self.CargoObject:IsAlive() then if CargoCarrier and CargoCarrier:IsAlive() then -- and self.CargoObject and self.CargoObject:IsAlive() then
if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then if (CargoCarrier:IsAir() and not CargoCarrier:InAir()) or true then
local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius( NearRadius ) + 5 local NearRadius = NearRadius or CargoCarrier:GetBoundingRadius( NearRadius ) + 5
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
self:__Load( 1, CargoCarrier, ... ) self:__Load( -1, CargoCarrier, ... )
else
if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then
self:__Boarding( 1, CargoCarrier, NearRadius, ... )
self.RunCount = self.RunCount + 1
else else
self:__Boarding( 2, CargoCarrier, NearRadius, ... ) if self:IsNear( CargoCarrier:GetPointVec2(), 20 ) then
self.RunCount = self.RunCount + 2 self:__Boarding( -1, CargoCarrier, NearRadius, ... )
end self.RunCount = self.RunCount + 1
if self.RunCount >= 40 then else
self.RunCount = 0 self:__Boarding( -2, CargoCarrier, NearRadius, ... )
local Speed = 90 self.RunCount = self.RunCount + 2
local Angle = 180 end
local Distance = 0 if self.RunCount >= 40 then
self.RunCount = 0
local Speed = 90
local Angle = 180
local Distance = 0
--self:F({Unit=self.CargoObject:GetName()})
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading )
--self:F({Unit=self.CargoObject:GetName()}) -- Set the CargoObject to state Green to ensure it is boarding!
self.CargoObject:OptionAlarmStateGreen()
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees. local Points = {}
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
local CargoDeployPointVec2 = CargoCarrierPointVec2:Translate( Distance, CargoDeployHeading ) local PointStartVec2 = self.CargoObject:GetPointVec2()
-- Set the CargoObject to state Green to ensure it is boarding! Points[#Points+1] = PointStartVec2:WaypointGround( Speed, "Off road" )
self.CargoObject:OptionAlarmStateGreen() Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed, "Off road" )
local Points = {} local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 0.2 )
local PointStartVec2 = self.CargoObject:GetPointVec2() end
Points[#Points+1] = PointStartVec2:WaypointGround( Speed, "Off road" )
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed, "Off road" )
local TaskRoute = self.CargoObject:TaskRoute( Points )
self.CargoObject:SetTask( TaskRoute, 0.2 )
end end
else
self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() )
self:CancelBoarding( CargoCarrier, NearRadius, ... )
self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) )
end end
else
self.CargoObject:MessageToGroup( "Cancelling Boarding... Get back on the ground!", 5, CargoCarrier:GetGroup(), self:GetName() )
self:CancelBoarding( CargoCarrier, NearRadius, ... )
self.CargoObject:SetCommand( self.CargoObject:CommandStopRoute( true ) )
end
else else
self:E("Something is wrong") self:E("Something is wrong")
end end

View File

@ -12,7 +12,7 @@
-- * Strategic components such as capturing, defending and destroying warehouses and their associated infrastructure. -- * Strategic components such as capturing, defending and destroying warehouses and their associated infrastructure.
-- * Intelligent spawning of aircraft on airports (only if enough parking spots are available). -- * Intelligent spawning of aircraft on airports (only if enough parking spots are available).
-- * Possibility to hook into events and customize actions. -- * Possibility to hook into events and customize actions.
-- * Persistance of assets. Warehouse assets can be saved and loaded from file. -- * Persistence of assets. Warehouse assets can be saved and loaded from file.
-- * Can be easily interfaced to other MOOSE classes. -- * Can be easily interfaced to other MOOSE classes.
-- --
-- === -- ===
@ -66,6 +66,9 @@
-- @field #table offroadpaths Table holding user defined paths from one warehouse to another. -- @field #table offroadpaths Table holding user defined paths from one warehouse to another.
-- @field #boolean autodefence When the warehouse is under attack, automatically spawn assets to defend the warehouse. -- @field #boolean autodefence When the warehouse is under attack, automatically spawn assets to defend the warehouse.
-- @field #number spawnzonemaxdist Max distance between warehouse and spawn zone. Default 5000 meters. -- @field #number spawnzonemaxdist Max distance between warehouse and spawn zone. Default 5000 meters.
-- @field #boolean autosave Automatically save assets to file when mission ends.
-- @field #string autosavepath Path where the asset file is saved on auto save.
-- @field #string autosavefilename File name of the auto asset save file. Default is auto generated from warehouse id and name.
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
--- Have your assets at the right place at the right time - or not! --- Have your assets at the right place at the right time - or not!
@ -677,7 +680,7 @@
-- --
-- === -- ===
-- --
-- # Persistance of Assets -- # Persistence of Assets
-- --
-- Assets in stock of a warehouse can be saved to a file on your hard drive and then loaded from that file at a later point. This enables to restart the mission -- Assets in stock of a warehouse can be saved to a file on your hard drive and then loaded from that file at a later point. This enables to restart the mission
-- and restore the warehouse stock. -- and restore the warehouse stock.
@ -696,7 +699,7 @@
-- --
-- in the file "MissionScripting.lua", which is located in the subdirectory "Scripts" of your DCS installation root directory. -- in the file "MissionScripting.lua", which is located in the subdirectory "Scripts" of your DCS installation root directory.
-- --
-- ### Don'ts -- ### Don't!
-- --
-- Do not use **semi-colons** or **equal signs** in the group names of your assets as these are used as separators in the saved and loaded files texts. -- Do not use **semi-colons** or **equal signs** in the group names of your assets as these are used as separators in the saved and loaded files texts.
-- If you do, it will cause problems and give you a headache! -- If you do, it will cause problems and give you a headache!
@ -708,10 +711,16 @@
-- The parameter *filename* is optional and defines the name of the saved file. By default this is automatically created from the warehouse id and name, for example -- The parameter *filename* is optional and defines the name of the saved file. By default this is automatically created from the warehouse id and name, for example
-- "Warehouse-1234_Batumi.txt". -- "Warehouse-1234_Batumi.txt".
-- --
-- warehouseBatumi:Save("D:\\My Warehouse Data\\") -- warehouseBatumi:Save("D:\\My Warehouse Data\\")
-- --
-- This will save all asset data to in "D:\\My Warehouse Data\\Warehouse-1234_Batumi.txt". -- This will save all asset data to in "D:\\My Warehouse Data\\Warehouse-1234_Batumi.txt".
-- --
-- ### Automatic Save at Mission End
--
-- The assets can be saved automatically when the mission is ended via the @{WAREHOUSE.SetSaveOnMissionEnd}(*path*, *filename*) function, i.e.
--
-- warehouseBatumi:SetSaveOnMissionEnd("D:\\My Warehouse Data\\")
--
-- ## Load Assets -- ## Load Assets
-- --
-- Loading assets data from file is achieved by the @{WAREHOUSE.Load}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the -- Loading assets data from file is achieved by the @{WAREHOUSE.Load}(*path*, *filename*) function. The parameter *path* specifies the path on the file system where the
@ -724,9 +733,9 @@
-- --
-- Loading the assets is done by -- Loading the assets is done by
-- --
-- warehouseBatumi:New(STATIC:FindByName("Warehouse Batumi")) -- warehouseBatumi:New(STATIC:FindByName("Warehouse Batumi"))
-- warehouseBatumi:Load("D:\\My Warehouse Data\\") -- warehouseBatumi:Load("D:\\My Warehouse Data\\")
-- warehouseBatumi:Start() -- warehouseBatumi:Start()
-- --
-- This sequence loads all assets from file. If a warehouse was captured in the last mission, it also respawns the static warehouse structure with the right coaliton. -- This sequence loads all assets from file. If a warehouse was captured in the last mission, it also respawns the static warehouse structure with the right coaliton.
-- However, it due to DCS limitations it is not possible to set the airbase coalition. This has to be done manually in the mission editor. Or alternatively, one could -- However, it due to DCS limitations it is not possible to set the airbase coalition. This has to be done manually in the mission editor. Or alternatively, one could
@ -1543,6 +1552,9 @@ WAREHOUSE = {
offroadpaths = {}, offroadpaths = {},
autodefence = false, autodefence = false,
spawnzonemaxdist = 5000, spawnzonemaxdist = 5000,
autosave = false,
autosavepath = nil,
autosavefile = nil,
} }
--- Item of the warehouse stock table. --- Item of the warehouse stock table.
@ -1714,7 +1726,7 @@ WAREHOUSE.db = {
--- Warehouse class version. --- Warehouse class version.
-- @field #string version -- @field #string version
WAREHOUSE.version="0.6.3" WAREHOUSE.version="0.6.4"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Warehouse todo list. -- TODO: Warehouse todo list.
@ -2397,6 +2409,18 @@ function WAREHOUSE:SetAutoDefenceOff()
return self return self
end end
--- Set auto defence off. This is the default.
-- @param #WAREHOUSE self
-- @param #string path Path where to save the asset data file.
-- @param #string filename File name. Default is generated automatically from warehouse id.
-- @return #WAREHOUSE self
function WAREHOUSE:SetSaveOnMissionEnd(path, filename)
self.autosave=true
self.autosavepath=path
self.autosavefile=filename
return self
end
--- Set the airbase belonging to this warehouse. --- Set the airbase belonging to this warehouse.
-- Note that it has to be of the same coalition as the warehouse. -- Note that it has to be of the same coalition as the warehouse.
@ -3042,6 +3066,7 @@ function WAREHOUSE:onafterStart(From, Event, To)
self:HandleEvent(EVENTS.Crash, self._OnEventCrashOrDead) self:HandleEvent(EVENTS.Crash, self._OnEventCrashOrDead)
self:HandleEvent(EVENTS.Dead, self._OnEventCrashOrDead) self:HandleEvent(EVENTS.Dead, self._OnEventCrashOrDead)
self:HandleEvent(EVENTS.BaseCaptured, self._OnEventBaseCaptured) self:HandleEvent(EVENTS.BaseCaptured, self._OnEventBaseCaptured)
self:HandleEvent(EVENTS.MissionEnd, self._OnEventMissionEnd)
-- This event triggers the arrived event for air assets. -- This event triggers the arrived event for air assets.
-- TODO Might need to make this landing or optional! -- TODO Might need to make this landing or optional!
@ -4925,6 +4950,7 @@ function WAREHOUSE:onbeforeLoad(From, Event, To, path, filename)
return true return true
else else
self:_ErrorMessage(string.format("ERROR: file %s does not exist! Cannot load assets.", filename), 60) self:_ErrorMessage(string.format("ERROR: file %s does not exist! Cannot load assets.", filename), 60)
return false
end end
end end
@ -4977,6 +5003,7 @@ function WAREHOUSE:onafterLoad(From, Event, To, path, filename)
local descriptors=UTILS.Split(asset,";") local descriptors=UTILS.Split(asset,";")
local asset={} local asset={}
local isasset=false
for _,descriptor in pairs(descriptors) do for _,descriptor in pairs(descriptors) do
local keyval=UTILS.Split(descriptor,"=") local keyval=UTILS.Split(descriptor,"=")
@ -4989,15 +5016,20 @@ function WAREHOUSE:onafterLoad(From, Event, To, path, filename)
elseif keyval[1]=="country" then elseif keyval[1]=="country" then
-- Get country id. -- Get country id.
Country=tonumber(keyval[2]) Country=tonumber(keyval[2])
elseif #keyval==2 then else
-- This is an asset.
isasset=true
local key=keyval[1] local key=keyval[1]
local val=keyval[2] local val=keyval[2]
--env.info(string.format("FF asset key=%s val=%s", key, val))
-- Livery or skill could be "nil". -- Livery or skill could be "nil".
if val=="nil" then if val=="nil" then
val=nil val=nil
end end
-- Convert string to number where necessary. -- Convert string to number where necessary.
if key=="cargobay" or key=="weight" or key=="loadradius" then if key=="cargobay" or key=="weight" or key=="loadradius" then
@ -5011,13 +5043,14 @@ function WAREHOUSE:onafterLoad(From, Event, To, path, filename)
end end
-- Add to table. -- Add to table.
table.insert(assets, asset) if isasset then
table.insert(assets, asset)
end
end end
-- Respawn warehouse with prev coalition if necessary. -- Respawn warehouse with prev coalition if necessary.
self:E(string.format("Changing country %d-->%d (before)", self:GetCountry(), Country))
if Country~=self:GetCountry() then if Country~=self:GetCountry() then
self:E(string.format("Changing country %d-->%d (after)", self:GetCountry(), Country)) self:T(self.wid..string.format("Changing warehouse country %d-->%d on loading assets.", self:GetCountry(), Country))
self:ChangeCountry(Country) self:ChangeCountry(Country)
end end
@ -5960,6 +5993,18 @@ function WAREHOUSE:_OnEventBaseCaptured(EventData)
end end
end end
--- Warehouse event handling function.
-- Handles the case when the mission is ended.
-- @param #WAREHOUSE self
-- @param Core.Event#EVENTDATA EventData Event data.
function WAREHOUSE:_OnEventMissionEnd(EventData)
self:T3(self.wid..string.format("Warehouse %s captured event mission end!",self.alias))
if self.autosave then
self:Save(self.autosavepath, self.autosavefile)
end
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Helper functions -- Helper functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -7712,7 +7757,7 @@ end
function WAREHOUSE:_ErrorMessage(text, duration) function WAREHOUSE:_ErrorMessage(text, duration)
duration=duration or 20 duration=duration or 20
if duration>0 then if duration>0 then
MESSAGE:New(text, duration):ToAllIf() MESSAGE:New(text, duration):ToAll()
end end
self:E(self.wid..text) self:E(self.wid..text)
end end

View File

@ -1975,6 +1975,24 @@ do -- Route methods
return nil return nil
end end
--- Make the controllable to push follow a given route.
-- @param #CONTROLLABLE self
-- @param #table Route A table of Route Points.
-- @param #number DelaySeconds (Optional) Wait for the specified seconds before executing the Route. Default is one second.
-- @return #CONTROLLABLE The CONTROLLABLE.
function CONTROLLABLE:RoutePush( Route, DelaySeconds )
self:F2( Route )
local DCSControllable = self:GetDCSObject()
if DCSControllable then
local RouteTask = self:TaskRoute( Route ) -- Create a RouteTask, that will route the CONTROLLABLE to the Route.
self:PushTask( RouteTask, DelaySeconds or 1 ) -- Execute the RouteTask after the specified seconds (default is 1).
return self
end
return nil
end
--- Stops the movement of the vehicle on the route. --- Stops the movement of the vehicle on the route.
-- @param #CONTROLLABLE self -- @param #CONTROLLABLE self

View File

@ -908,16 +908,23 @@ function UNIT:InAir()
-- Implementation of workaround. The original code is below. -- Implementation of workaround. The original code is below.
-- This to simulate the landing on buildings. -- This to simulate the landing on buildings.
-- local UnitInAir = DCSUnit:inAir()
local UnitInAir = true local UnitInAir = true
local VelocityVec3 = DCSUnit:getVelocity()
local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec local UnitCategory = DCSUnit:getDesc().category
local Coordinate = DCSUnit:getPoint() if UnitCategory == Unit.Category.HELICOPTER then
local LandHeight = land.getHeight( { x = Coordinate.x, y = Coordinate.z } ) local VelocityVec3 = DCSUnit:getVelocity()
local Height = Coordinate.y - LandHeight local Velocity = ( VelocityVec3.x ^ 2 + VelocityVec3.y ^ 2 + VelocityVec3.z ^ 2 ) ^ 0.5 -- in meters / sec
if Velocity < 1 and Height <= 60 then local Coordinate = DCSUnit:getPoint()
UnitInAir = false local LandHeight = land.getHeight( { x = Coordinate.x, y = Coordinate.z } )
local Height = Coordinate.y - LandHeight
if Velocity < 1 and Height <= 60 then
UnitInAir = false
end
else
UnitInAir = DCSUnit:inAir()
end end
self:T3( UnitInAir ) self:T3( UnitInAir )
return UnitInAir return UnitInAir
end end