mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge branch 'develop' into FF/Develop
This commit is contained in:
commit
fc852e0386
@ -1,4 +1,4 @@
|
||||
--- **AI** -- (R2.3) - Models the intelligent transportation of infantry (cargo).
|
||||
--- **AI** -- (R2.3) - Models the intelligent transportation of infantry and other cargo.
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
@ -12,47 +12,184 @@
|
||||
-- @extends Core.Fsm#FSM_CONTROLLABLE
|
||||
|
||||
|
||||
--- # AI\_CARGO\_TROOPS class, extends @{Core.Base@BASE}
|
||||
--- # AI\_CARGO\_APC class, extends @{Core.Base#BASE}
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- AI\_CARGO\APC brings a dynamic cargo handling capability for AI groups.
|
||||
--
|
||||
-- Armoured Personnel Carriers (APC), Trucks, Jeeps and other ground based carrier equipment can be mobilized to intelligently transport infantry and other cargo within the simulation.
|
||||
-- The AI\_CARGO\APC module uses the @{Cargo} capabilities within the MOOSE framework.
|
||||
-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\APC object recognize the cargo.
|
||||
-- Please consult the @{Cargo} module for more information.
|
||||
--
|
||||
-- ## Cargo loading.
|
||||
--
|
||||
-- The module will load automatically cargo when the APCs are within boarding or loading range.
|
||||
-- The boarding or loading range is specified when the cargo is created in the simulation, and therefore, this range depends on the type of cargo
|
||||
-- and the specified boarding range.
|
||||
--
|
||||
-- ## Enemies nearby.
|
||||
--
|
||||
-- When the APCs are approaching enemy units, something special is happening.
|
||||
-- The APCs will stop moving, and the loaded infantry will unboard and follow the APCs and will help to defend the group.
|
||||
-- The carrier will hold the route once the unboarded infantry is further than 50 meters from the APCs,
|
||||
-- to ensure that the APCs are not too far away from the following running infantry.
|
||||
-- Once all enemies are cleared, the infantry will board again automatically into the APCs. Once boarded, the APCs will follow its pre-defined route.
|
||||
--
|
||||
-- A combat range needs to be specified in meters at the @{#AI_CARGO_APC.New}() method.
|
||||
-- This combat range will trigger the unboarding of troops when enemies are within the combat range around the APCs.
|
||||
-- During my tests, I've noticed that there is a balance between ensuring that the infantry is within sufficient hit range (effectiveness) versus
|
||||
-- vulnerability of the infantry. It all depends on the kind of enemies that are expected to be encountered.
|
||||
-- A combat range of 350 meters to 500 meters has been proven to be the most effective and efficient.
|
||||
--
|
||||
-- ## Infantry health.
|
||||
--
|
||||
-- When infantry is unboarded from the APCs, the infantry is actually respawned into the battlefield.
|
||||
-- As a result, the unboarding infantry is very _healthy_ every time it unboards.
|
||||
-- This is due to the limitation of the DCS simulator, which is not able to specify the health of new spawned units as a parameter.
|
||||
-- However, infantry that was destroyed when unboarded and following the APCs, won't be respawned again. Destroyed is destroyed.
|
||||
-- As a result, there is some additional strength that is gained when an unboarding action happens, but in terms of simulation balance this has
|
||||
-- marginal impact on the overall battlefield simulation. Fortunately, the firing strength of infantry is limited, and thus, respacing healthy infantry every
|
||||
-- time is not so much of an issue ...
|
||||
--
|
||||
-- ## Control the APCs on the map.
|
||||
--
|
||||
-- It is possible also as a human ground commander to influence the path of the APCs, by pointing a new path using the DCS user interface on the map.
|
||||
-- In this case, the APCs will change the direction towards its new indicated route. However, there is a catch!
|
||||
-- Once the APCs are near the enemy, and infantry is unboarded, the APCs won't be able to hold the route until the infantry could catch up.
|
||||
-- The APCs will simply drive on and won't stop! This is a limitation in ED that prevents user actions being controlled by the scripting engine.
|
||||
-- No workaround is possible on this.
|
||||
--
|
||||
-- ## Cargo deployment.
|
||||
--
|
||||
-- Using the @{#AI_CARGO_APC.Deploy}() method, you are able to direct the APCs towards a point on the battlefield to unboard/unload the cargo at the specific coordinate.
|
||||
-- The APCs will follow nearby roads as much as possible, to ensure fast and clean cargo transportation between the objects and villages in the simulation environment.
|
||||
--
|
||||
-- ## Cargo pickup.
|
||||
--
|
||||
-- Using the @{#AI_CARGO_APC.Pickup}() method, you are able to direct the APCs towards a point on the battlefield to board/load the cargo at the specific coordinate.
|
||||
-- The APCs will follow nearby roads as much as possible, to ensure fast and clean cargo transportation between the objects and villages in the simulation environment.
|
||||
--
|
||||
--
|
||||
--
|
||||
-- @field #AI_CARGO_APC
|
||||
AI_CARGO_APC = {
|
||||
ClassName = "AI_CARGO_APC",
|
||||
Coordinate = nil -- Core.Point#COORDINATE,
|
||||
Coordinate = nil, -- Core.Point#COORDINATE,
|
||||
APC_Cargo = {},
|
||||
}
|
||||
|
||||
--- Creates a new AI_CARGO_APC object.
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
-- @param Cargo.CargoGroup#CARGO_GROUP CargoGroup
|
||||
-- @param Wrapper.Group#GROUP CargoCarrier
|
||||
-- @param Core.Set#SET_CARGO CargoSet
|
||||
-- @param #number CombatRadius
|
||||
-- @return #AI_CARGO_APC
|
||||
function AI_CARGO_APC:New( CargoCarrier, CargoGroup, CombatRadius )
|
||||
function AI_CARGO_APC:New( CargoCarrier, CargoSet, CombatRadius )
|
||||
|
||||
local self = BASE:Inherit( self, FSM_CONTROLLABLE:New() ) -- #AI_CARGO_APC
|
||||
|
||||
self.CargoGroup = CargoGroup -- Cargo.CargoGroup#CARGO_GROUP
|
||||
self.CargoSet = CargoSet -- Core.Set#SET_CARGO
|
||||
self.CombatRadius = CombatRadius
|
||||
|
||||
self:SetStartState( "UnLoaded" )
|
||||
self:SetStartState( "Unloaded" )
|
||||
|
||||
self:AddTransition( "Unloaded", "Pickup", "*" )
|
||||
self:AddTransition( "Loaded", "Deploy", "*" )
|
||||
|
||||
self:AddTransition( "*", "Load", "Boarding" )
|
||||
self:AddTransition( "Boarding", "Board", "Boarding" )
|
||||
self:AddTransition( "Boarding", "Loaded", "Loaded" )
|
||||
self:AddTransition( "Loaded", "Unload", "Unboarding" )
|
||||
self:AddTransition( "Unboarding", "Unboard", "Unboarding" )
|
||||
self:AddTransition( "Unboarding", "Unloaded", "Unloaded" )
|
||||
self:AddTransition( { "Unboarding", "Unloaded" }, "Unloaded", "Unloaded" )
|
||||
|
||||
self:AddTransition( "*", "Monitor", "*" )
|
||||
self:AddTransition( "*", "Follow", "Following" )
|
||||
self:AddTransition( "*", "Guard", "Guarding" )
|
||||
self:AddTransition( "*", "Guard", "Unloaded" )
|
||||
|
||||
self:AddTransition( "*", "Destroyed", "Destroyed" )
|
||||
|
||||
|
||||
--- Pickup Handler OnBefore for AI_CARGO_APC
|
||||
-- @function [parent=#AI_CARGO_APC] OnBeforePickup
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean
|
||||
|
||||
--- Pickup Handler OnAfter for AI_CARGO_APC
|
||||
-- @function [parent=#AI_CARGO_APC] OnAfterPickup
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
|
||||
--- Pickup Trigger for AI_CARGO_APC
|
||||
-- @function [parent=#AI_CARGO_APC] Pickup
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
|
||||
--- Pickup Asynchronous Trigger for AI_CARGO_APC
|
||||
-- @function [parent=#AI_CARGO_APC] __Pickup
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param #number Delay
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
|
||||
--- Deploy Handler OnBefore for AI_CARGO_APC
|
||||
-- @function [parent=#AI_CARGO_APC] OnBeforeDeploy
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean
|
||||
|
||||
--- Deploy Handler OnAfter for AI_CARGO_APC
|
||||
-- @function [parent=#AI_CARGO_APC] OnAfterDeploy
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
|
||||
--- Deploy Trigger for AI_CARGO_APC
|
||||
-- @function [parent=#AI_CARGO_APC] Deploy
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
|
||||
--- Deploy Asynchronous Trigger for AI_CARGO_APC
|
||||
-- @function [parent=#AI_CARGO_APC] __Deploy
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @param #number Delay
|
||||
|
||||
|
||||
--- Loaded Handler OnAfter for AI_CARGO_APC
|
||||
-- @function [parent=#AI_CARGO_APC] OnAfterLoaded
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
--- Unloaded Handler OnAfter for AI_CARGO_APC
|
||||
-- @function [parent=#AI_CARGO_APC] OnAfterUnloaded
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
-- @param #string From
|
||||
-- @param #string Event
|
||||
-- @param #string To
|
||||
|
||||
|
||||
self:__Monitor( 1 )
|
||||
|
||||
self:SetCarrier( CargoCarrier )
|
||||
self.Transporting = false
|
||||
|
||||
return self
|
||||
end
|
||||
@ -60,11 +197,11 @@ end
|
||||
|
||||
--- Set the Carrier.
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
-- @param Wrapper.Group#GROUP CargoCarrier
|
||||
-- @return #AI_CARGO_APC
|
||||
function AI_CARGO_APC:SetCarrier( CargoCarrier )
|
||||
|
||||
self.CargoCarrier = CargoCarrier -- Wrapper.Unit#UNIT
|
||||
self.CargoCarrier = CargoCarrier -- Wrapper.Group#GROUP
|
||||
self.CargoCarrier:SetState( self.CargoCarrier, "AI_CARGO_APC", self )
|
||||
|
||||
CargoCarrier:HandleEvent( EVENTS.Dead )
|
||||
@ -106,11 +243,16 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier )
|
||||
end
|
||||
|
||||
|
||||
function AI_CARGO_APC:IsTransporting()
|
||||
|
||||
return self.Transporting == true
|
||||
end
|
||||
|
||||
--- Find a free Carrier within a range.
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @param #number Radius
|
||||
-- @return Wrapper.Unit#UNIT NewCarrier
|
||||
-- @return Wrapper.Group#GROUP NewCarrier
|
||||
function AI_CARGO_APC:FindCarrier( Coordinate, Radius )
|
||||
|
||||
local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius )
|
||||
@ -122,11 +264,12 @@ function AI_CARGO_APC:FindCarrier( Coordinate, Radius )
|
||||
local Attributes = NearUnit:GetDesc()
|
||||
self:F({Desc=Attributes})
|
||||
if NearUnit:HasAttribute( "Trucks" ) then
|
||||
self:SetCarrier( NearUnit )
|
||||
break
|
||||
return NearUnit:GetGroup()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
@ -135,18 +278,20 @@ end
|
||||
--- Follow Infantry to the Carrier.
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param #AI_CARGO_APC Me
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
-- @param Wrapper.Group#GROUP InfantryGroup
|
||||
-- @param Wrapper.Unit#UNIT APCUnit
|
||||
-- @param Cargo.CargoGroup#CARGO_GROUP Cargo
|
||||
-- @return #AI_CARGO_APC
|
||||
function AI_CARGO_APC:FollowToCarrier( Me, CargoCarrier, InfantryGroup )
|
||||
function AI_CARGO_APC:FollowToCarrier( Me, APCUnit, CargoGroup )
|
||||
|
||||
local InfantryGroup = CargoGroup:GetGroup()
|
||||
|
||||
self:F( { self = self:GetClassNameAndID(), InfantryGroup = InfantryGroup:GetName() } )
|
||||
|
||||
--if self:Is( "Following" ) then
|
||||
|
||||
if CargoCarrier:IsAlive() then
|
||||
if APCUnit:IsAlive() then
|
||||
-- We check if the Cargo is near to the CargoCarrier.
|
||||
if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", CargoCarrier, 5 ) ) then
|
||||
if InfantryGroup:IsPartlyInZone( ZONE_UNIT:New( "Radius", APCUnit, 25 ) ) then
|
||||
|
||||
-- The Cargo does not need to follow the Carrier.
|
||||
Me:Guard()
|
||||
@ -167,12 +312,12 @@ function AI_CARGO_APC:FollowToCarrier( Me, CargoCarrier, InfantryGroup )
|
||||
self:F({FromGround=FromGround})
|
||||
table.insert( Waypoints, FromGround )
|
||||
|
||||
local ToCoord = CargoCarrier:GetCoordinate():GetRandomCoordinateInRadius( 10, 5 )
|
||||
local ToCoord = APCUnit:GetCoordinate():GetRandomCoordinateInRadius( 10, 5 )
|
||||
local ToGround = ToCoord:WaypointGround( 10, "Diamond" )
|
||||
self:F({ToGround=ToGround})
|
||||
table.insert( Waypoints, ToGround )
|
||||
|
||||
local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_APC.FollowToCarrier", Me, CargoCarrier, InfantryGroup )
|
||||
local TaskRoute = InfantryGroup:TaskFunction( "AI_CARGO_APC.FollowToCarrier", Me, APCUnit, CargoGroup )
|
||||
|
||||
self:F({Waypoints = Waypoints})
|
||||
local Waypoint = Waypoints[#Waypoints]
|
||||
@ -186,48 +331,52 @@ end
|
||||
|
||||
|
||||
--- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function AI_CARGO_APC:onafterMonitor( CargoCarrier, From, Event, To )
|
||||
self:F( { CargoCarrier, From, Event, To } )
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
|
||||
self:F( { APC, From, Event, To } )
|
||||
|
||||
if CargoCarrier and CargoCarrier:IsAlive() then
|
||||
if APC and APC:IsAlive() then
|
||||
if self.CarrierCoordinate then
|
||||
local Coordinate = CargoCarrier:GetCoordinate()
|
||||
self.Zone:Scan( { Object.Category.UNIT } )
|
||||
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
|
||||
if self:Is( "Unloaded" ) or self:Is( "Guarding" ) or self:Is( "Following" ) then
|
||||
-- There are no enemies within combat range. Load the CargoCarrier.
|
||||
self:__Load( 1 )
|
||||
end
|
||||
else
|
||||
if self:Is( "Loaded" ) then
|
||||
-- There are enemies within combat range. Unload the CargoCarrier.
|
||||
self:__Unload( 1 )
|
||||
end
|
||||
end
|
||||
if self:Is( "Guarding" ) then
|
||||
if not self.CargoGroup:IsNear( CargoCarrier, 5 ) then
|
||||
self:Follow()
|
||||
end
|
||||
end
|
||||
if self:Is( "Following" ) then
|
||||
local Distance = Coordinate:Get2DDistance( self.CargoGroup:GetCoordinate() )
|
||||
self:F( { Distance = Distance } )
|
||||
if Distance > 40 then
|
||||
CargoCarrier:RouteStop()
|
||||
self.CarrierStopped = true
|
||||
if self:IsTransporting() then
|
||||
local Coordinate = APC:GetCoordinate()
|
||||
self.Zone:Scan( { Object.Category.UNIT } )
|
||||
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
|
||||
if self:Is( "Unloaded" ) or self:Is( "Following" ) then
|
||||
-- There are no enemies within combat range. Load the CargoCarrier.
|
||||
self:Load()
|
||||
end
|
||||
else
|
||||
if self.CarrierStopped then
|
||||
if self.CargoGroup:IsNear( CargoCarrier, 10 ) then
|
||||
CargoCarrier:RouteResume()
|
||||
self.CarrierStopped = nil
|
||||
if self:Is( "Loaded" ) then
|
||||
-- There are enemies within combat range. Unload the CargoCarrier.
|
||||
self:__Unload( 1 )
|
||||
else
|
||||
if self:Is( "Unloaded" ) then
|
||||
self:Follow()
|
||||
end
|
||||
if self:Is( "Following" ) then
|
||||
for APCUnit, Cargo in pairs( self.APC_Cargo ) do
|
||||
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
self.CarrierCoordinate = CargoCarrier:GetCoordinate()
|
||||
self.CarrierCoordinate = APC:GetCoordinate()
|
||||
end
|
||||
|
||||
self:__Monitor( -5 )
|
||||
@ -236,27 +385,52 @@ end
|
||||
|
||||
|
||||
--- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function AI_CARGO_APC:onafterLoad( CargoCarrier, From, Event, To )
|
||||
self:F( { CargoCarrier, From, Event, To } )
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To )
|
||||
self:F( { APC, From, Event, To } )
|
||||
|
||||
if CargoCarrier and CargoCarrier:IsAlive() then
|
||||
CargoCarrier:RouteStop()
|
||||
self:__Board( 10 )
|
||||
self.CargoGroup:Board( CargoCarrier, 10 )
|
||||
local Boarding = false
|
||||
self.BoardingCount = 0
|
||||
|
||||
if APC and APC:IsAlive() then
|
||||
self.APC_Cargo = {}
|
||||
for _, APCUnit in pairs( APC:GetUnits() ) do
|
||||
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
|
||||
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||
self:F( { IsUnLoaded = Cargo:IsUnLoaded(), Cargo:GetName(), APC:GetName() } )
|
||||
if Cargo:IsUnLoaded() then
|
||||
if Cargo:IsInLoadRadius( APCUnit:GetCoordinate() ) then
|
||||
self:F( { "In radius", APCUnit:GetName() } )
|
||||
APC:RouteStop()
|
||||
--Cargo:Ungroup()
|
||||
Cargo:Board( APCUnit, 25 )
|
||||
self:__Board( 1, Cargo )
|
||||
Boarding = true
|
||||
|
||||
-- So now this APCUnit has Cargo that is being loaded.
|
||||
-- This will be used further in the logic to follow and to check cargo status.
|
||||
self.APC_Cargo[APCUnit] = Cargo
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Boarding
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function AI_CARGO_APC:onafterBoard( CargoCarrier, From, Event, To )
|
||||
self:F( { CargoCarrier, From, Event, To } )
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
function AI_CARGO_APC:onafterBoard( APC, From, Event, To, Cargo )
|
||||
self:F( { APC, From, Event, To, Cargo } )
|
||||
|
||||
if CargoCarrier and CargoCarrier:IsAlive() then
|
||||
self:F({ IsLoaded = self.CargoGroup:IsLoaded() } )
|
||||
if not self.CargoGroup:IsLoaded() then
|
||||
self:__Board( 10 )
|
||||
if APC and APC:IsAlive() then
|
||||
self:F({ IsLoaded = Cargo:IsLoaded(), Cargo:GetName(), APC:GetName() } )
|
||||
if not Cargo:IsLoaded() then
|
||||
self:__Board( 10, Cargo )
|
||||
else
|
||||
self:__Loaded( 1 )
|
||||
end
|
||||
@ -265,76 +439,199 @@ function AI_CARGO_APC:onafterBoard( CargoCarrier, From, Event, To )
|
||||
end
|
||||
|
||||
--- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function AI_CARGO_APC:onafterLoaded( CargoCarrier, From, Event, To )
|
||||
self:F( { CargoCarrier, From, Event, To } )
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To )
|
||||
self:F( { APC, From, Event, To } )
|
||||
|
||||
if CargoCarrier and CargoCarrier:IsAlive() then
|
||||
CargoCarrier:RouteResume()
|
||||
local Loaded = true
|
||||
|
||||
if APC and APC:IsAlive() then
|
||||
for APCUnit, Cargo in pairs( self.APC_Cargo ) do
|
||||
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||
self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed(), Cargo:GetName(), APC:GetName() } )
|
||||
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
|
||||
Loaded = false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if Loaded == true then
|
||||
APC:RouteResume()
|
||||
end
|
||||
|
||||
return Loaded
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function AI_CARGO_APC:onafterUnload( CargoCarrier, From, Event, To )
|
||||
self:F( { CargoCarrier, From, Event, To } )
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
function AI_CARGO_APC:onafterUnload( APC, From, Event, To )
|
||||
self:F( { APC, From, Event, To } )
|
||||
|
||||
if CargoCarrier and CargoCarrier:IsAlive() then
|
||||
CargoCarrier:RouteStop()
|
||||
self.CargoGroup:UnBoard( )
|
||||
self:__Unboard( 10 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function AI_CARGO_APC:onafterUnboard( CargoCarrier, From, Event, To )
|
||||
self:F( { CargoCarrier, From, Event, To } )
|
||||
|
||||
if CargoCarrier and CargoCarrier:IsAlive() then
|
||||
if not self.CargoGroup:IsUnLoaded() then
|
||||
self:__Unboard( 10 )
|
||||
else
|
||||
self:__Unloaded( 1 )
|
||||
if APC and APC:IsAlive() then
|
||||
for _, APCUnit in pairs( APC:GetUnits() ) do
|
||||
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
|
||||
APC:RouteStop()
|
||||
for _, Cargo in pairs( APCUnit:GetCargo() ) do
|
||||
Cargo:UnBoard()
|
||||
self:__Unboard( 10, Cargo )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function AI_CARGO_APC:onafterUnloaded( CargoCarrier, From, Event, To )
|
||||
self:F( { CargoCarrier, From, Event, To } )
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
function AI_CARGO_APC:onafterUnboard( APC, From, Event, To, Cargo )
|
||||
self:F( { APC, From, Event, To, Cargo:GetName() } )
|
||||
|
||||
if CargoCarrier and CargoCarrier:IsAlive() then
|
||||
self:Guard()
|
||||
self.CargoCarrier = CargoCarrier
|
||||
CargoCarrier:RouteResume()
|
||||
if APC and APC:IsAlive() then
|
||||
if not Cargo:IsUnLoaded() then
|
||||
self:__Unboard( 10, Cargo )
|
||||
else
|
||||
self:__Unloaded( 1, Cargo )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo )
|
||||
self:F( { APC, From, Event, To, Cargo:GetName() } )
|
||||
|
||||
local AllUnloaded = true
|
||||
|
||||
--Cargo:Regroup()
|
||||
|
||||
if APC and APC:IsAlive() then
|
||||
for _, APCUnit in pairs( APC:GetUnits() ) do
|
||||
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
|
||||
local CargoCheck = self.APC_Cargo[APCUnit]
|
||||
self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } )
|
||||
if CargoCheck:IsUnLoaded() == false then
|
||||
AllUnloaded = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if AllUnloaded == true then
|
||||
self:Guard()
|
||||
self.CargoCarrier = APC
|
||||
self.APC_Cargo = {}
|
||||
end
|
||||
end
|
||||
|
||||
self:F( { AllUnloaded = AllUnloaded } )
|
||||
return AllUnloaded
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
function AI_CARGO_APC:onafterFollow( APC, From, Event, To )
|
||||
self:F( { APC, From, Event, To } )
|
||||
|
||||
self:F( "Follow" )
|
||||
if APC and APC:IsAlive() then
|
||||
for APCUnit, Cargo in pairs( self.APC_Cargo ) do
|
||||
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||
if Cargo:IsUnLoaded() then
|
||||
self:FollowToCarrier( self, APCUnit, Cargo )
|
||||
APCUnit:RouteResume()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_CARGO_APC
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
function AI_CARGO_APC._Pickup( APC, self )
|
||||
|
||||
APC:F( { "AI_CARGO_APC._Pickup:", APC:GetName() } )
|
||||
|
||||
if APC:IsAlive() then
|
||||
self:Load()
|
||||
self.Transporting = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_CARGO_APC
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
function AI_CARGO_APC._Deploy( APC, self )
|
||||
|
||||
APC:F( { "AI_CARGO_APC._Deploy:", APC } )
|
||||
|
||||
if APC:IsAlive() then
|
||||
self:Unload()
|
||||
self.Transporting = false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
-- @param From
|
||||
-- @param Event
|
||||
-- @param To
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @param #number Speed
|
||||
-- @param #string EndPointFormation The formation at the end point of the action.
|
||||
function AI_CARGO_APC:onafterPickup( APC, From, Event, To, Coordinate, Speed, EndPointFormation )
|
||||
|
||||
if APC and APC:IsAlive() then
|
||||
|
||||
if Coordinate then
|
||||
self.RoutePickup = true
|
||||
|
||||
local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed, EndPointFormation )
|
||||
|
||||
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Pickup", self )
|
||||
|
||||
self:F({Waypoints = Waypoints})
|
||||
local Waypoint = Waypoints[#Waypoints]
|
||||
APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||
|
||||
APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||
else
|
||||
AI_CARGO_APC._Pickup( APC, self )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function AI_CARGO_APC:onafterFollow( CargoCarrier, From, Event, To )
|
||||
self:F( { CargoCarrier, From, Event, To } )
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
-- @param From
|
||||
-- @param Event
|
||||
-- @param To
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @param #number Speed
|
||||
-- @param #string EndPointFormation The formation at the end point of the action.
|
||||
function AI_CARGO_APC:onafterDeploy( APC, From, Event, To, Coordinate, Speed, EndPointFormation )
|
||||
|
||||
self:F( "Follow" )
|
||||
if CargoCarrier and CargoCarrier:IsAlive() then
|
||||
self.CargoGroup.CargoSet:ForEach(
|
||||
--- @param Core.Cargo#CARGO Cargo
|
||||
function( Cargo )
|
||||
self:F( { "Follow", Cargo.CargoObject:GetName() } )
|
||||
if Cargo.CargoObject:IsAlive() == true then
|
||||
self:F( { "Follow", Cargo.CargoObject:GetID() } )
|
||||
self:FollowToCarrier( self, CargoCarrier, Cargo.CargoObject:GetGroup() )
|
||||
end
|
||||
end
|
||||
)
|
||||
if APC and APC:IsAlive() then
|
||||
|
||||
self.RouteDeploy = true
|
||||
|
||||
local Waypoints = APC:TaskGroundOnRoad( Coordinate, Speed, EndPointFormation )
|
||||
|
||||
local TaskFunction = APC:TaskFunction( "AI_CARGO_APC._Deploy", self )
|
||||
|
||||
self:F({Waypoints = Waypoints})
|
||||
local Waypoint = Waypoints[#Waypoints]
|
||||
APC:SetTaskWaypoint( Waypoint, TaskFunction ) -- Set for the given Route at Waypoint 2 the TaskRouteToZone.
|
||||
|
||||
APC:Route( Waypoints, 1 ) -- Move after a random seconds to the Route. See the Route method for details.
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -24,7 +24,7 @@ AI_CARGO_HELICOPTER = {
|
||||
|
||||
--- Creates a new AI_CARGO_HELICOPTER object.
|
||||
-- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Wrapper.Unit#UNIT Helicopter
|
||||
-- @param Wrapper.Group#GROUP Helicopter
|
||||
-- @param Core.Set#SET_CARGO CargoSet
|
||||
-- @param #number CombatRadius
|
||||
-- @return #AI_CARGO_HELICOPTER
|
||||
@ -116,13 +116,13 @@ end
|
||||
|
||||
--- Set the Carrier.
|
||||
-- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Wrapper.Unit#UNIT Helicopter
|
||||
-- @param Wrapper.Group#GROUP Helicopter
|
||||
-- @return #AI_CARGO_HELICOPTER
|
||||
function AI_CARGO_HELICOPTER:SetCarrier( Helicopter )
|
||||
|
||||
local AICargo = self
|
||||
|
||||
self.Helicopter = Helicopter -- Wrapper.Unit#UNIT
|
||||
self.Helicopter = Helicopter -- Wrapper.Group#GROUP
|
||||
self.Helicopter:SetState( self.Helicopter, "AI_CARGO_HELICOPTER", self )
|
||||
|
||||
self.RoutePickup = false
|
||||
@ -173,7 +173,7 @@ end
|
||||
-- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @param #number Radius
|
||||
-- @return Wrapper.Unit#UNIT NewCarrier
|
||||
-- @return Wrapper.Group#GROUP NewCarrier
|
||||
function AI_CARGO_HELICOPTER:FindCarrier( Coordinate, Radius )
|
||||
|
||||
local CoordinateZone = ZONE_RADIUS:New( "Zone" , Coordinate:GetVec2(), Radius )
|
||||
@ -183,18 +183,19 @@ function AI_CARGO_HELICOPTER:FindCarrier( Coordinate, Radius )
|
||||
self:F({NearUnit=NearUnit})
|
||||
if not NearUnit:GetState( NearUnit, "AI_CARGO_HELICOPTER" ) then
|
||||
local Attributes = NearUnit:GetDesc()
|
||||
self:F({Desc=Attributes})
|
||||
self:F({Attributes=Attributes})
|
||||
if NearUnit:HasAttribute( "Trucks" ) then
|
||||
self:SetCarrier( NearUnit )
|
||||
break
|
||||
return NearUnit:GetGroup()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Wrapper.Unit#UNIT Helicopter
|
||||
-- @param Wrapper.Group#GROUP Helicopter
|
||||
-- @param From
|
||||
-- @param Event
|
||||
-- @param To
|
||||
@ -221,7 +222,7 @@ end
|
||||
|
||||
|
||||
--- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Wrapper.Unit#UNIT Helicopter
|
||||
-- @param Wrapper.Group#GROUP Helicopter
|
||||
-- @param From
|
||||
-- @param Event
|
||||
-- @param To
|
||||
@ -276,7 +277,7 @@ end
|
||||
|
||||
|
||||
--- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Wrapper.Unit#UNIT Helicopter
|
||||
-- @param Wrapper.Group#GROUP Helicopter
|
||||
-- @param From
|
||||
-- @param Event
|
||||
-- @param To
|
||||
@ -331,25 +332,47 @@ end
|
||||
|
||||
|
||||
--- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Wrapper.Unit#UNIT Helicopter
|
||||
function AI_CARGO_HELICOPTER:onafterLoad( Helicopter, From, Event, To, Coordinate )
|
||||
-- @param Wrapper.Group#GROUP Helicopter
|
||||
function AI_CARGO_HELICOPTER:onbeforeLoad( Helicopter, From, Event, To, Coordinate )
|
||||
|
||||
local Boarding = false
|
||||
|
||||
if Helicopter and Helicopter:IsAlive() then
|
||||
|
||||
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||
if Cargo:IsInLoadRadius( Coordinate ) then
|
||||
self:__Board( 5 )
|
||||
Cargo:Board( Helicopter, 25 )
|
||||
self.Cargo = Cargo
|
||||
break
|
||||
self.BoardingCount = 0
|
||||
|
||||
if Helicopter and Helicopter:IsAlive() then
|
||||
self.Helicopter_Cargo = {}
|
||||
for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do
|
||||
local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT
|
||||
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||
self:F( { IsUnLoaded = Cargo:IsUnLoaded() } )
|
||||
if Cargo:IsUnLoaded() then
|
||||
if Cargo:IsInLoadRadius( HelicopterUnit:GetCoordinate() ) then
|
||||
self:F( { "In radius", HelicopterUnit:GetName() } )
|
||||
--Cargo:Ungroup()
|
||||
Cargo:Board( HelicopterUnit, 25 )
|
||||
self:__Board( 1, Cargo )
|
||||
Boarding = true
|
||||
|
||||
-- So now this APCUnit has Cargo that is being loaded.
|
||||
-- This will be used further in the logic to follow and to check cargo status.
|
||||
self.Helicopter_Cargo[HelicopterUnit] = Cargo
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Boarding
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Wrapper.Unit#UNIT Helicopter
|
||||
-- @param Wrapper.Group#GROUP Helicopter
|
||||
function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To )
|
||||
|
||||
if Helicopter and Helicopter:IsAlive() then
|
||||
@ -364,28 +387,46 @@ function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To )
|
||||
end
|
||||
|
||||
--- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Wrapper.Unit#UNIT Helicopter
|
||||
function AI_CARGO_HELICOPTER:onafterLoaded( Helicopter, From, Event, To )
|
||||
-- @param Wrapper.Group#GROUP Helicopter
|
||||
function AI_CARGO_HELICOPTER:onbeforeLoaded( Helicopter, From, Event, To )
|
||||
|
||||
local Loaded = true
|
||||
|
||||
if Helicopter and Helicopter:IsAlive() then
|
||||
for HelicopterUnit, Cargo in pairs( self.APC_Cargo ) do
|
||||
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||
self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed() } )
|
||||
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
|
||||
Loaded = false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return Loaded
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Wrapper.Unit#UNIT Helicopter
|
||||
-- @param Wrapper.Group#GROUP Helicopter
|
||||
function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To )
|
||||
|
||||
if Helicopter and Helicopter:IsAlive() then
|
||||
self.Cargo:UnBoard()
|
||||
self:__Unboard( 10 )
|
||||
for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do
|
||||
local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT
|
||||
for _, Cargo in pairs( HelicopterUnit:GetCargo() ) do
|
||||
Cargo:UnBoard()
|
||||
self:__Unboard( 10, Cargo )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
--- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Wrapper.Unit#UNIT Helicopter
|
||||
-- @param Wrapper.Group#GROUP Helicopter
|
||||
function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To )
|
||||
|
||||
if Helicopter and Helicopter:IsAlive() then
|
||||
@ -399,13 +440,32 @@ function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To )
|
||||
end
|
||||
|
||||
--- @param #AI_CARGO_HELICOPTER self
|
||||
-- @param Wrapper.Unit#UNIT Helicopter
|
||||
function AI_CARGO_HELICOPTER:onafterUnloaded( Helicopter, From, Event, To )
|
||||
-- @param Wrapper.Group#GROUP Helicopter
|
||||
function AI_CARGO_HELICOPTER:onbeforeUnloaded( Helicopter, From, Event, To )
|
||||
|
||||
local AllUnloaded = true
|
||||
|
||||
--Cargo:Regroup()
|
||||
|
||||
if Helicopter and Helicopter:IsAlive() then
|
||||
self.Helicopter = Helicopter
|
||||
for _, CargoCheck in pairs( self.CargoSet:GetSet() ) do
|
||||
local CargoCheck = CargoCheck -- Cargo.Cargo#CARGO
|
||||
self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } )
|
||||
if CargoCheck:IsUnLoaded() == false then
|
||||
AllUnloaded = false
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if AllUnloaded == true then
|
||||
self.Helicopter = Helicopter
|
||||
self.Helicopter_Cargo = {}
|
||||
end
|
||||
end
|
||||
|
||||
self:F( { AllUnloaded = AllUnloaded } )
|
||||
return AllUnloaded
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
@ -6,31 +6,11 @@
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- Cargo can be of various forms, always are composed out of ONE object ( one unit or one static or one slingload crate ):
|
||||
--
|
||||
-- * CARGO_UNIT, represented by a @{Unit} in a singleton @{Group}: Cargo can be represented by a Unit in a Group. a CARGO_UNIT is representable...
|
||||
-- * CARGO_GROUP, represented by a @{Group}. A CARGO_GROUP is reportable...
|
||||
--
|
||||
-- This module is still under construction, but is described above works already, and will keep working ...
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # Demo Missions
|
||||
--
|
||||
-- ### [CARGO Demo Missions source code](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master-release/CGO%20-%20Cargo)
|
||||
--
|
||||
-- ### [CARGO Demo Missions, only for beta testers](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/master/CGO%20-%20Cargo)
|
||||
--
|
||||
-- ### [ALL Demo Missions pack of the last release](https://github.com/FlightControl-Master/MOOSE_MISSIONS/releases)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- # YouTube Channel
|
||||
--
|
||||
-- ### [CARGO YouTube Channel](https://www.youtube.com/watch?v=tM00lTlkpYs&list=PL7ZUrU4zZUl2zUTuKrLW5RsO9zLMqUtbf)
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
-- ### Contributions:
|
||||
--
|
||||
@ -172,11 +152,31 @@ do -- CARGO
|
||||
-- @field #boolean Representable This flag defines if the cargo can be represented by a DCS Unit.
|
||||
-- @field #boolean Containable This flag defines if the cargo can be contained within a DCS Unit.
|
||||
|
||||
--- # (R2.1) CARGO class, extends @{Fsm#FSM_PROCESS}
|
||||
--- # (R2.4) CARGO class, extends @{Fsm#FSM_PROCESS}
|
||||
--
|
||||
-- The CARGO class defines the core functions that defines a cargo object within MOOSE.
|
||||
-- A cargo is a logical object defined that is available for transport, and has a life status within a simulation.
|
||||
-- A cargo is a **logical object** defined that is available for transport, and has a life status within a simulation.
|
||||
--
|
||||
-- CARGO is not meant to be used directly by mission designers, but provides a base class for **concrete cargo implementation classes** to handle:
|
||||
--
|
||||
-- * Cargo **group objects**, implemented by the @{Cargo.CargoGroup#CARGO_GROUP} class.
|
||||
-- * Cargo **Unit objects**, implemented by the @{Cargo.CargoUnit#CARGO_UNIT} class.
|
||||
-- * Cargo **Crate objects**, implemented by the @{Cargo.CargoCrate#CARGO_CRATE} class.
|
||||
-- * Cargo **Sling Load objects**, implemented by the @{Cargo.CargoSlingload#CARGO_SLINGLOAD} class.
|
||||
--
|
||||
-- The above cargo classes are used by the AI\_CARGO\_ classes to allow AI groups to transport cargo:
|
||||
--
|
||||
-- * AI Armoured Personnel Carriers to transport cargo and engage in battles, using the @{AI.AI_Cargo_APC#AI_CARGO_APC} class.
|
||||
-- * AI Helicopters to transport cargo, using the @{AI.AI_Cargo_Helicopter#AI_CARGO_HELICOPTER} class.
|
||||
-- * AI Planes to transport cargo, using the @{AI.AI_Cargo_Plane#AI_CARGO_PLANE} class.
|
||||
-- * AI Ships is planned.
|
||||
--
|
||||
-- The above cargo classes are also used by the TASK\_CARGO\_ classes to allow human players to transport cargo as part of a tasking:
|
||||
--
|
||||
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_TRANSPORT} to transport cargo by human players.
|
||||
-- * @{Tasking.Task_Cargo_Transport#TASK_CARGO_CSAR} to transport downed pilots by human players.
|
||||
--
|
||||
--
|
||||
-- The CARGO is a state machine: it manages the different events and states of the cargo.
|
||||
-- All derived classes from CARGO follow the same state machine, expose the same cargo event functions, and provide the same cargo states.
|
||||
--
|
||||
@ -186,32 +186,8 @@ do -- CARGO
|
||||
-- * @{#CARGO.Load}( ToCarrier ): Loads the cargo into a carrier, regardless of its position.
|
||||
-- * @{#CARGO.UnBoard}( ToPointVec2 ): UnBoard the cargo from a carrier. This will trigger a movement of the cargo to the option ToPointVec2.
|
||||
-- * @{#CARGO.UnLoad}( ToPointVec2 ): UnLoads the cargo from a carrier.
|
||||
-- * @{#CARGO.Dead}( Controllable ): The cargo is dead. The cargo process will be ended.
|
||||
-- * @{#CARGO.Destroyed}( Controllable ): The cargo is dead. The cargo process will be ended.
|
||||
--
|
||||
-- ## CARGO States:
|
||||
--
|
||||
-- * **UnLoaded**: The cargo is unloaded from a carrier.
|
||||
-- * **Boarding**: The cargo is currently boarding (= running) into a carrier.
|
||||
-- * **Loaded**: The cargo is loaded into a carrier.
|
||||
-- * **UnBoarding**: The cargo is currently unboarding (=running) from a carrier.
|
||||
-- * **Dead**: The cargo is dead ...
|
||||
-- * **End**: The process has come to an end.
|
||||
--
|
||||
-- ## CARGO state transition methods:
|
||||
--
|
||||
-- State transition functions can be set **by the mission designer** customizing or improving the behaviour of the state.
|
||||
-- There are 2 moments when state transition methods will be called by the state machine:
|
||||
--
|
||||
-- * **Leaving** the state.
|
||||
-- The state transition method needs to start with the name **OnLeave + the name of the state**.
|
||||
-- If the state transition method returns false, then the processing of the state transition will not be done!
|
||||
-- If you want to change the behaviour of the AIControllable at this event, return false,
|
||||
-- but then you'll need to specify your own logic using the AIControllable!
|
||||
--
|
||||
-- * **Entering** the state.
|
||||
-- The state transition method needs to start with the name **OnEnter + the name of the state**.
|
||||
-- These state transition methods need to provide a return value, which is specified at the function description.
|
||||
--
|
||||
-- @field #CARGO
|
||||
CARGO = {
|
||||
ClassName = "CARGO",
|
||||
@ -293,7 +269,41 @@ do -- CARGO
|
||||
|
||||
local CargoFound = _DATABASE:FindCargo( CargoName )
|
||||
return CargoFound
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the x position of the cargo.
|
||||
-- @param #CARGO self
|
||||
-- @return #number
|
||||
function CARGO:GetX()
|
||||
if self:IsLoaded() then
|
||||
return self.CargoCarrier:GetCoordinate().x
|
||||
else
|
||||
return self.CargoObject:GetCoordinate().x
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the y position of the cargo.
|
||||
-- @param #CARGO self
|
||||
-- @return #number
|
||||
function CARGO:GetY()
|
||||
if self:IsLoaded() then
|
||||
return self.CargoCarrier:GetCoordinate().z
|
||||
else
|
||||
return self.CargoObject:GetCoordinate().z
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the heading of the cargo.
|
||||
-- @param #CARGO self
|
||||
-- @return #number
|
||||
function CARGO:GetHeading()
|
||||
if self:IsLoaded() then
|
||||
return self.CargoCarrier:GetHeading()
|
||||
else
|
||||
return self.CargoObject:GetHeading()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Check if the cargo can be Slingloaded.
|
||||
-- @param #CARGO self
|
||||
@ -431,7 +441,16 @@ do -- CARGO
|
||||
function CARGO:IsBoarding()
|
||||
return self:Is( "Boarding" )
|
||||
end
|
||||
|
||||
|
||||
--- Check if cargo is unboarding.
|
||||
-- @param #CARGO self
|
||||
-- @return #boolean true if unboarding
|
||||
function CARGO:IsUnboarding()
|
||||
return self:Is( "UnBoarding" )
|
||||
end
|
||||
|
||||
|
||||
--- Check if cargo is alive.
|
||||
-- @param #CARGO self
|
||||
-- @return #boolean true if unloaded
|
||||
@ -566,14 +585,14 @@ do -- CARGO
|
||||
|
||||
--- Check if Cargo is in the LoadRadius for the Cargo to be Boarded or Loaded.
|
||||
-- @param #CARGO self
|
||||
-- @param Core.Point#Coordinate Coordinate
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean true if the CargoGroup is within the loading radius.
|
||||
function CARGO:IsInLoadRadius( Coordinate )
|
||||
self:F( { Coordinate, LoadRadius = self.LoadRadius } )
|
||||
|
||||
local Distance = 0
|
||||
if self:IsUnLoaded() then
|
||||
Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() )
|
||||
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||
self:T( Distance )
|
||||
if Distance <= self.LoadRadius then
|
||||
return true
|
||||
@ -586,14 +605,14 @@ do -- CARGO
|
||||
|
||||
--- Check if the Cargo can report itself to be Boarded or Loaded.
|
||||
-- @param #CARGO self
|
||||
-- @param Core.Point#Coordinate Coordinate
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean true if the Cargo can report itself.
|
||||
function CARGO:IsInReportRadius( Coordinate )
|
||||
self:F( { Coordinate } )
|
||||
|
||||
local Distance = 0
|
||||
if self:IsUnLoaded() then
|
||||
Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() )
|
||||
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||
self:T( Distance )
|
||||
if Distance <= self.LoadRadius then
|
||||
return true
|
||||
@ -606,18 +625,18 @@ do -- CARGO
|
||||
|
||||
--- Check if CargoCarrier is near the Cargo to be Loaded.
|
||||
-- @param #CARGO self
|
||||
-- @param Core.Point#POINT_VEC2 PointVec2
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision).
|
||||
-- @return #boolean
|
||||
function CARGO:IsNear( PointVec2, NearRadius )
|
||||
function CARGO:IsNear( Coordinate, NearRadius )
|
||||
--self:F( { PointVec2 = PointVec2, NearRadius = NearRadius } )
|
||||
|
||||
if self.CargoObject:IsAlive() then
|
||||
--local Distance = PointVec2:DistanceFromPointVec2( self.CargoObject:GetPointVec2() )
|
||||
--local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() )
|
||||
--self:F( { CargoObjectName = self.CargoObject:GetName() } )
|
||||
--self:F( { CargoObjectVec2 = self.CargoObject:GetVec2() } )
|
||||
--self:F( { PointVec2 = PointVec2:GetVec2() } )
|
||||
local Distance = PointVec2:Get2DDistance( self.CargoObject:GetPointVec2() )
|
||||
local Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||
--self:F( Distance )
|
||||
|
||||
if Distance <= NearRadius then
|
||||
@ -979,9 +998,9 @@ end
|
||||
function CARGO_PACKAGE:IsNear( CargoCarrier )
|
||||
self:F()
|
||||
|
||||
local CargoCarrierPoint = CargoCarrier:GetPointVec2()
|
||||
local CargoCarrierPoint = CargoCarrier:GetCoordinate()
|
||||
|
||||
local Distance = CargoCarrierPoint:DistanceFromPointVec2( self.CargoCarrier:GetPointVec2() )
|
||||
local Distance = CargoCarrierPoint:Get2DDistance( self.CargoCarrier:GetCoordinate() )
|
||||
self:T( Distance )
|
||||
|
||||
if Distance <= self.NearRadius then
|
||||
|
||||
@ -166,14 +166,14 @@ do -- CARGO_CRATE
|
||||
|
||||
--- Check if Cargo Crate is in the radius for the Cargo to be reported.
|
||||
-- @param #CARGO self
|
||||
-- @param Core.Point#Coordinate Coordinate
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean true if the Cargo Crate is within the report radius.
|
||||
function CARGO_CRATE:IsInReportRadius( Coordinate )
|
||||
--self:F( { Coordinate, LoadRadius = self.LoadRadius } )
|
||||
|
||||
local Distance = 0
|
||||
if self:IsUnLoaded() then
|
||||
Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() )
|
||||
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||
--self:T( Distance )
|
||||
if Distance <= self.LoadRadius then
|
||||
return true
|
||||
@ -193,7 +193,7 @@ do -- CARGO_CRATE
|
||||
|
||||
local Distance = 0
|
||||
if self:IsUnLoaded() then
|
||||
Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() )
|
||||
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||
--self:T( Distance )
|
||||
if Distance <= self.NearRadius then
|
||||
return true
|
||||
|
||||
@ -53,46 +53,47 @@ do -- CARGO_GROUP
|
||||
self:F( { Type, Name, LoadRadius } )
|
||||
|
||||
self.CargoSet = SET_CARGO:New()
|
||||
self.CargoGroup = CargoGroup
|
||||
self.Grouped = true
|
||||
self.CargoUnitTemplate = {}
|
||||
|
||||
self:SetDeployed( false )
|
||||
|
||||
local WeightGroup = 0
|
||||
|
||||
self.GroupName = CargoGroup:GetName()
|
||||
self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( self.GroupName ) )
|
||||
self.CargoGroup:Destroy()
|
||||
|
||||
local GroupName = CargoGroup:GetName()
|
||||
self.CargoName = GroupName:match("(.*)~CARGO") or GroupName
|
||||
self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) )
|
||||
|
||||
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
||||
GroupTemplate.name = self.CargoName .. "#CARGO"
|
||||
GroupTemplate.groupId = nil
|
||||
|
||||
CargoGroup:Destroy()
|
||||
GroupTemplate.units = {}
|
||||
|
||||
-- We iterate through the group template and for each unit in the template, we create a new group with one unit.
|
||||
for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do
|
||||
|
||||
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
||||
local GroupName = env.getValueDictByKey( GroupTemplate.name )
|
||||
|
||||
-- We create a new group object with one unit...
|
||||
-- First we prepare the template...
|
||||
GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID
|
||||
GroupTemplate.groupId = nil
|
||||
GroupTemplate.units = {}
|
||||
GroupTemplate.units[1] = UnitTemplate
|
||||
local UnitName = UnitTemplate.name .. "#CARGO"
|
||||
GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO"
|
||||
|
||||
|
||||
-- Then we register the new group in the database
|
||||
local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID)
|
||||
|
||||
-- Now we spawn the new group based on the template created.
|
||||
_DATABASE:Spawn( GroupTemplate )
|
||||
UnitTemplate.name = UnitTemplate.name .. "#CARGO"
|
||||
local CargoUnitName = UnitTemplate.name
|
||||
self.CargoUnitTemplate[CargoUnitName] = UnitTemplate
|
||||
|
||||
GroupTemplate.units[#GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName]
|
||||
GroupTemplate.units[#GroupTemplate.units].unitId = nil
|
||||
|
||||
-- And we register the spawned unit as part of the CargoSet.
|
||||
local Unit = UNIT:FindByName( UnitName )
|
||||
local Unit = UNIT:Register( CargoUnitName )
|
||||
--local WeightUnit = Unit:GetDesc().massEmpty
|
||||
--WeightGroup = WeightGroup + WeightUnit
|
||||
local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 )
|
||||
self.CargoSet:Add( UnitName, CargoUnit )
|
||||
local CargoUnit = CARGO_UNIT:New( Unit, Type, CargoUnitName, 10 )
|
||||
self.CargoSet:Add( CargoUnitName, CargoUnit )
|
||||
end
|
||||
|
||||
|
||||
-- Then we register the new group in the database
|
||||
self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID)
|
||||
|
||||
-- Now we spawn the new group based on the template created.
|
||||
_DATABASE:Spawn( GroupTemplate )
|
||||
|
||||
self:SetWeight( WeightGroup )
|
||||
self.CargoLimit = 10
|
||||
@ -111,13 +112,108 @@ do -- CARGO_GROUP
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Ungroup the cargo group into individual groups with one unit.
|
||||
-- This is required because by default a group will move in formation and this is really an issue for group control.
|
||||
-- Therefore this method is made to be able to ungroup a group.
|
||||
-- This works for ground only groups.
|
||||
-- @param #CARGO_GROUP self
|
||||
function CARGO_GROUP:Ungroup()
|
||||
|
||||
if self.Grouped == true then
|
||||
|
||||
self.Grouped = false
|
||||
|
||||
self.CargoGroup:Destroy()
|
||||
|
||||
for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do
|
||||
local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT
|
||||
|
||||
if CargoUnit:IsUnLoaded() then
|
||||
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
||||
--local GroupName = env.getValueDictByKey( GroupTemplate.name )
|
||||
|
||||
-- We create a new group object with one unit...
|
||||
-- First we prepare the template...
|
||||
GroupTemplate.name = self.CargoName .. "#CARGO#" .. CargoUnitName
|
||||
GroupTemplate.groupId = nil
|
||||
|
||||
if CargoUnit:IsUnLoaded() then
|
||||
GroupTemplate.units = {}
|
||||
GroupTemplate.units[1] = self.CargoUnitTemplate[CargoUnitName]
|
||||
GroupTemplate.units[#GroupTemplate.units].unitId = nil
|
||||
GroupTemplate.units[#GroupTemplate.units].x = CargoUnit:GetX()
|
||||
GroupTemplate.units[#GroupTemplate.units].y = CargoUnit:GetY()
|
||||
GroupTemplate.units[#GroupTemplate.units].heading = CargoUnit:GetHeading()
|
||||
end
|
||||
|
||||
|
||||
-- Then we register the new group in the database
|
||||
local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID)
|
||||
|
||||
-- Now we spawn the new group based on the template created.
|
||||
_DATABASE:Spawn( GroupTemplate )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Regroup the cargo group into one group with multiple unit.
|
||||
-- This is required because by default a group will move in formation and this is really an issue for group control.
|
||||
-- Therefore this method is made to be able to regroup a group.
|
||||
-- This works for ground only groups.
|
||||
-- @param #CARGO_GROUP self
|
||||
function CARGO_GROUP:Regroup()
|
||||
|
||||
self:F("Regroup")
|
||||
|
||||
if self.Grouped == false then
|
||||
|
||||
self.Grouped = true
|
||||
|
||||
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
||||
GroupTemplate.name = self.CargoName .. "#CARGO"
|
||||
GroupTemplate.groupId = nil
|
||||
GroupTemplate.units = {}
|
||||
|
||||
for CargoUnitName, CargoUnit in pairs( self.CargoSet:GetSet() ) do
|
||||
local CargoUnit = CargoUnit -- Cargo.CargoUnit#CARGO_UNIT
|
||||
|
||||
self:F( { CargoUnit:GetName(), UnLoaded = CargoUnit:IsUnLoaded() } )
|
||||
|
||||
if CargoUnit:IsUnLoaded() then
|
||||
|
||||
CargoUnit.CargoObject:Destroy()
|
||||
|
||||
GroupTemplate.units[#GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName]
|
||||
GroupTemplate.units[#GroupTemplate.units].unitId = nil
|
||||
GroupTemplate.units[#GroupTemplate.units].x = CargoUnit:GetX()
|
||||
GroupTemplate.units[#GroupTemplate.units].y = CargoUnit:GetY()
|
||||
GroupTemplate.units[#GroupTemplate.units].heading = CargoUnit:GetHeading()
|
||||
end
|
||||
end
|
||||
|
||||
-- Then we register the new group in the database
|
||||
self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID)
|
||||
|
||||
self:F( { "Regroup", GroupTemplate } )
|
||||
|
||||
-- Now we spawn the new group based on the template created.
|
||||
_DATABASE:Spawn( GroupTemplate )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- @param #CARGO_GROUP self
|
||||
-- @param Core.Event#EVENTDATA EventData
|
||||
function CARGO_GROUP:OnEventCargoDead( EventData )
|
||||
self:I( EventData )
|
||||
|
||||
local Destroyed = false
|
||||
local Destroyed = false
|
||||
|
||||
if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() then
|
||||
if self:IsDestroyed() or self:IsUnLoaded() or self:IsBoarding() or self:IsUnboarding() then
|
||||
Destroyed = true
|
||||
for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do
|
||||
local Cargo = CargoData -- #CARGO
|
||||
@ -170,10 +266,10 @@ do -- CARGO_GROUP
|
||||
|
||||
--- Enter Loaded State.
|
||||
-- @param #CARGO_GROUP self
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
-- @param #string Event
|
||||
-- @param #string From
|
||||
-- @param #string To
|
||||
-- @param Wrapper.Unit#UNIT CargoCarrier
|
||||
function CARGO_GROUP:onenterLoaded( From, Event, To, CargoCarrier, ... )
|
||||
--self:F( { From, Event, To, CargoCarrier, ...} )
|
||||
|
||||
@ -186,6 +282,7 @@ do -- CARGO_GROUP
|
||||
|
||||
--self.CargoObject:Destroy()
|
||||
self.CargoCarrier = CargoCarrier
|
||||
self.CargoCarrier:AddCargo( self )
|
||||
|
||||
end
|
||||
|
||||
@ -243,14 +340,6 @@ do -- CARGO_GROUP
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Get the amount of cargo units in the group.
|
||||
-- @param #CARGO_GROUP self
|
||||
-- @return #CARGO_GROUP
|
||||
function CARGO_GROUP:GetCount()
|
||||
return self.CargoSet:Count()
|
||||
end
|
||||
|
||||
|
||||
--- Enter UnBoarding State.
|
||||
-- @param #CARGO_GROUP self
|
||||
@ -273,10 +362,12 @@ do -- CARGO_GROUP
|
||||
|
||||
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
|
||||
self.CargoSet:ForEach(
|
||||
--- @param Cargo.Cargo#CARGO Cargo
|
||||
function( Cargo, NearRadius )
|
||||
|
||||
Cargo:__UnBoard( Timer, ToPointVec2, NearRadius )
|
||||
Timer = Timer + 3
|
||||
if not Cargo:IsDestroyed() then
|
||||
Cargo:__UnBoard( Timer, ToPointVec2, NearRadius )
|
||||
Timer = Timer + 3
|
||||
end
|
||||
end, { NearRadius }
|
||||
)
|
||||
|
||||
@ -306,7 +397,7 @@ do -- CARGO_GROUP
|
||||
|
||||
-- For each Cargo object within the CARGO_GROUP, route each object to the CargoLoadPointVec2
|
||||
for CargoID, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||
self:T( Cargo.current )
|
||||
self:T( { Cargo:GetName(), Cargo.current } )
|
||||
if not Cargo:is( "UnLoaded" ) and not Cargo:IsDestroyed() then
|
||||
UnBoarded = false
|
||||
end
|
||||
@ -361,6 +452,9 @@ do -- CARGO_GROUP
|
||||
|
||||
end
|
||||
|
||||
self.CargoCarrier:RemoveCargo( self )
|
||||
self.CargoCarrier = nil
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -370,8 +464,8 @@ do -- CARGO_GROUP
|
||||
-- @return #nil There is no valid Cargo in the CargoGroup.
|
||||
function CARGO_GROUP:GetCoordinate()
|
||||
self:F()
|
||||
|
||||
local Cargo = self.CargoSet:GetFirst()
|
||||
|
||||
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||
|
||||
if Cargo then
|
||||
return Cargo.CargoObject:GetCoordinate()
|
||||
@ -386,26 +480,46 @@ do -- CARGO_GROUP
|
||||
-- @return #boolean false if the CargoGroup is dead.
|
||||
function CARGO_GROUP:IsAlive()
|
||||
|
||||
local Alive = true
|
||||
|
||||
-- For each Cargo within the CargoSet, check if the Cargo is Alive.
|
||||
-- When the Cargo is Loaded, the Cargo is in the CargoCarrier, so we check if the CargoCarrier is alive.
|
||||
-- When the Cargo is not Loaded, the Cargo is the CargoObject, so we check if the CargoObject is alive.
|
||||
self.CargoSet:ForEach(
|
||||
function( Cargo )
|
||||
if self:IsLoaded() then
|
||||
Alive = Alive == true and Cargo.CargoCarrier:IsAlive()
|
||||
else
|
||||
Alive = Alive == true and Cargo.CargoObject:IsAlive()
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
return Alive
|
||||
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||
return Cargo ~= nil
|
||||
|
||||
end
|
||||
|
||||
|
||||
--- Get the first alive Cargo Unit of the Cargo Group.
|
||||
-- @param #CARGO_GROUP self
|
||||
-- @return #CARGO_GROUP
|
||||
function CARGO_GROUP:GetFirstAlive()
|
||||
|
||||
local CargoFirstAlive = nil
|
||||
|
||||
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||
if not Cargo:IsDestroyed() then
|
||||
CargoFirstAlive = Cargo
|
||||
break
|
||||
end
|
||||
end
|
||||
return CargoFirstAlive
|
||||
end
|
||||
|
||||
|
||||
--- Get the amount of cargo units in the group.
|
||||
-- @param #CARGO_GROUP self
|
||||
-- @return #CARGO_GROUP
|
||||
function CARGO_GROUP:GetCount()
|
||||
return self.CargoSet:Count()
|
||||
end
|
||||
|
||||
|
||||
--- Get the amount of cargo units in the group.
|
||||
-- @param #CARGO_GROUP self
|
||||
-- @return #CARGO_GROUP
|
||||
function CARGO_GROUP:GetGroup( Cargo )
|
||||
local Cargo = Cargo or self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||
return Cargo.CargoObject:GetGroup()
|
||||
end
|
||||
|
||||
|
||||
--- Route Cargo to Coordinate and randomize locations.
|
||||
-- @param #CARGO_GROUP self
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
@ -429,12 +543,16 @@ do -- CARGO_GROUP
|
||||
-- @return #boolean The Cargo is near to the Carrier.
|
||||
-- @return #nil The Cargo is not near to the Carrier.
|
||||
function CARGO_GROUP:IsNear( CargoCarrier, NearRadius )
|
||||
--self:F( {NearRadius = NearRadius } )
|
||||
self:F( {NearRadius = NearRadius } )
|
||||
|
||||
local Cargo = self.CargoSet:GetFirst() -- #CARGO
|
||||
|
||||
if Cargo then
|
||||
return Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius )
|
||||
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
|
||||
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||
if Cargo:IsAlive() then
|
||||
if Cargo:IsNear( CargoCarrier:GetCoordinate(), NearRadius ) then
|
||||
self:F( "Near" )
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
@ -442,22 +560,22 @@ do -- CARGO_GROUP
|
||||
|
||||
--- Check if Cargo Group is in the radius for the Cargo to be Boarded.
|
||||
-- @param #CARGO_GROUP self
|
||||
-- @param Core.Point#Coordinate Coordinate
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean true if the Cargo Group is within the load radius.
|
||||
function CARGO_GROUP:IsInLoadRadius( Coordinate )
|
||||
--self:F( { Coordinate } )
|
||||
|
||||
local Cargo = self.CargoSet:GetFirst() -- #CARGO
|
||||
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||
|
||||
if Cargo then
|
||||
local Distance = 0
|
||||
if Cargo:IsLoaded() then
|
||||
Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoCarrier:GetPointVec2() )
|
||||
Distance = Coordinate:Get2DDistance( Cargo.CargoCarrier:GetCoordinate() )
|
||||
else
|
||||
Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() )
|
||||
Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() )
|
||||
end
|
||||
--self:T( Distance )
|
||||
|
||||
self:F( { Distance = Distance, LoadRadius = self.LoadRadius } )
|
||||
if Distance <= self.LoadRadius then
|
||||
return true
|
||||
else
|
||||
@ -477,12 +595,13 @@ do -- CARGO_GROUP
|
||||
function CARGO_GROUP:IsInReportRadius( Coordinate )
|
||||
--self:F( { Coordinate } )
|
||||
|
||||
local Cargo = self.CargoSet:GetFirst() -- #CARGO
|
||||
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
|
||||
|
||||
if Cargo then
|
||||
self:F( { Cargo } )
|
||||
local Distance = 0
|
||||
if Cargo:IsUnLoaded() then
|
||||
Distance = Coordinate:DistanceFromPointVec2( Cargo.CargoObject:GetPointVec2() )
|
||||
Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() )
|
||||
--self:T( Distance )
|
||||
if Distance <= self.LoadRadius then
|
||||
return true
|
||||
|
||||
@ -119,14 +119,14 @@ do -- CARGO_SLINGLOAD
|
||||
|
||||
--- Check if Cargo Crate is in the radius for the Cargo to be reported.
|
||||
-- @param #CARGO_SLINGLOAD self
|
||||
-- @param Core.Point#Coordinate Coordinate
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean true if the Cargo Crate is within the report radius.
|
||||
function CARGO_SLINGLOAD:IsInReportRadius( Coordinate )
|
||||
--self:F( { Coordinate, LoadRadius = self.LoadRadius } )
|
||||
|
||||
local Distance = 0
|
||||
if self:IsUnLoaded() then
|
||||
Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() )
|
||||
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||
if Distance <= self.LoadRadius then
|
||||
return true
|
||||
end
|
||||
@ -138,14 +138,14 @@ do -- CARGO_SLINGLOAD
|
||||
|
||||
--- Check if Cargo Slingload is in the radius for the Cargo to be Boarded or Loaded.
|
||||
-- @param #CARGO_SLINGLOAD self
|
||||
-- @param Core.Point#Coordinate Coordinate
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @return #boolean true if the Cargo Slingload is within the loading radius.
|
||||
function CARGO_SLINGLOAD:IsInLoadRadius( Coordinate )
|
||||
--self:F( { Coordinate } )
|
||||
|
||||
local Distance = 0
|
||||
if self:IsUnLoaded() then
|
||||
Distance = Coordinate:DistanceFromPointVec2( self.CargoObject:GetPointVec2() )
|
||||
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
|
||||
if Distance <= self.NearRadius then
|
||||
return true
|
||||
end
|
||||
|
||||
@ -49,7 +49,7 @@ do -- CARGO_UNIT
|
||||
-- @return #CARGO_UNIT
|
||||
function CARGO_UNIT:New( CargoUnit, Type, Name, Weight, NearRadius )
|
||||
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, Weight, NearRadius ) ) -- #CARGO_UNIT
|
||||
self:F( { Type, Name, Weight, NearRadius } )
|
||||
self:I( { Type, Name, Weight, NearRadius } )
|
||||
|
||||
self:T( CargoUnit )
|
||||
self.CargoObject = CargoUnit
|
||||
@ -146,13 +146,13 @@ do -- CARGO_UNIT
|
||||
local Distance = 5
|
||||
|
||||
if From == "UnBoarding" then
|
||||
if self:IsNear( ToPointVec2, NearRadius ) then
|
||||
--if self:IsNear( ToPointVec2, NearRadius ) then
|
||||
return true
|
||||
else
|
||||
--else
|
||||
|
||||
self:__UnBoarding( 1, ToPointVec2, NearRadius )
|
||||
end
|
||||
return false
|
||||
--self:__UnBoarding( 1, ToPointVec2, NearRadius )
|
||||
--end
|
||||
--return false
|
||||
end
|
||||
|
||||
end
|
||||
@ -258,14 +258,17 @@ do -- CARGO_UNIT
|
||||
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 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( -1, CargoCarrier, NearRadius )
|
||||
@ -295,7 +298,7 @@ do -- CARGO_UNIT
|
||||
else
|
||||
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
|
||||
self.RunCount = self.RunCount + 1
|
||||
if self.RunCount >= 60 then
|
||||
if self.RunCount >= 40 then
|
||||
self.RunCount = 0
|
||||
local Speed = 90
|
||||
local Angle = 180
|
||||
@ -308,12 +311,15 @@ do -- CARGO_UNIT
|
||||
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 PointStartVec2 = self.CargoObject:GetPointVec2()
|
||||
|
||||
Points[#Points+1] = PointStartVec2:WaypointGround( Speed )
|
||||
Points[#Points+1] = CargoDeployPointVec2:WaypointGround( Speed )
|
||||
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 )
|
||||
@ -367,6 +373,7 @@ do -- CARGO_UNIT
|
||||
if self.CargoObject then
|
||||
self:T("Destroying")
|
||||
self.CargoObject:Destroy()
|
||||
--self.CargoObject:ReSpawnAt( COORDINATE:NewFromVec2( {x=0,y=0} ), 0 )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -284,7 +284,7 @@ do -- cargo
|
||||
|
||||
TemplateName = env.getValueDictByKey( TemplateName )
|
||||
|
||||
local Cargo = TemplateName:match( "#(CARGO)" )
|
||||
local Cargo = TemplateName:match( "~(CARGO)" )
|
||||
|
||||
return Cargo and Cargo == "CARGO"
|
||||
end
|
||||
@ -293,6 +293,7 @@ do -- cargo
|
||||
-- @param #DATABASE self
|
||||
-- @return #DATABASE self
|
||||
function DATABASE:RegisterCargos()
|
||||
|
||||
|
||||
for CargoGroupName, CargoGroup in pairs( self.GROUPS ) do
|
||||
if self:IsCargo( CargoGroupName ) then
|
||||
@ -300,11 +301,12 @@ do -- cargo
|
||||
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)")
|
||||
local CargoName = CargoGroupName:match("(.*)~CARGO")
|
||||
local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?")
|
||||
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?")
|
||||
local LoadRadius = CargoParam and CargoParam:match( "RR=([%a%d]+),?")
|
||||
local NearRadius = CargoParam and CargoParam:match( "NR=([%a%d]+),?")
|
||||
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName
|
||||
local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") )
|
||||
local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") )
|
||||
|
||||
CARGO_GROUP:New( CargoGroup, Type, Name or CargoName, LoadRadius, NearRadius )
|
||||
self:F({"Register CargoGroup:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
|
||||
CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius )
|
||||
end
|
||||
end
|
||||
|
||||
@ -315,15 +317,17 @@ do -- cargo
|
||||
local CargoName = CargoStaticName:match("(.*)~CARGO")
|
||||
local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?")
|
||||
local Category = CargoParam and CargoParam:match( "C=([%a%d ]+),?")
|
||||
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?")
|
||||
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName
|
||||
local LoadRadius = CargoParam and tonumber( CargoParam:match( "RR=([%a%d]+),?") )
|
||||
local NearRadius = CargoParam and tonumber( CargoParam:match( "NR=([%a%d]+),?") )
|
||||
|
||||
if Category == "SLING" then
|
||||
CARGO_SLINGLOAD:New( CargoStatic, Type, Name or CargoName, LoadRadius, NearRadius )
|
||||
self:F({"Register CargoSlingload:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
|
||||
CARGO_SLINGLOAD:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
|
||||
else
|
||||
if Category == "CRATE" then
|
||||
CARGO_CRATE:New( CargoStatic, Type, Name or CargoName, LoadRadius, NearRadius )
|
||||
self:F({"Register CargoCrate:",Type=Type,Name=Name,LoadRadius=LoadRadius,NearRadius=NearRadius})
|
||||
CARGO_CRATE:New( CargoStatic, Type, Name, LoadRadius, NearRadius )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -274,21 +274,19 @@ do -- COORDINATE
|
||||
|
||||
|
||||
|
||||
--TODO: check this to replace
|
||||
--- Calculate the distance from a reference @{DCSTypes#Vec2}.
|
||||
--- Calculate the distance from a reference @{#COORDINATE}.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Dcs.DCSTypes#Vec2 Vec2Reference The reference @{DCSTypes#Vec2}.
|
||||
-- @return Dcs.DCSTypes#Distance The distance from the reference @{DCSTypes#Vec2} in meters.
|
||||
function COORDINATE:DistanceFromVec2( Vec2Reference )
|
||||
self:F2( Vec2Reference )
|
||||
-- @param #COORDINATE PointVec2Reference The reference @{#COORDINATE}.
|
||||
-- @return Dcs.DCSTypes#Distance The distance from the reference @{#COORDINATE} in meters.
|
||||
function COORDINATE:DistanceFromPointVec2( PointVec2Reference )
|
||||
self:F2( PointVec2Reference )
|
||||
|
||||
local Distance = ( ( Vec2Reference.x - self.x ) ^ 2 + ( Vec2Reference.y - self.z ) ^2 ) ^0.5
|
||||
local Distance = ( ( PointVec2Reference.x - self.x ) ^ 2 + ( PointVec2Reference.z - self.z ) ^2 ) ^ 0.5
|
||||
|
||||
self:T2( Distance )
|
||||
return Distance
|
||||
end
|
||||
|
||||
|
||||
--- Add a Distance in meters from the COORDINATE orthonormal plane, with the given angle, and calculate the new COORDINATE.
|
||||
-- @param #COORDINATE self
|
||||
-- @param Dcs.DCSTypes#Distance Distance The Distance to be added in meters.
|
||||
@ -895,11 +893,13 @@ do -- COORDINATE
|
||||
function COORDINATE:WaypointGround( Speed, Formation )
|
||||
self:F2( { Formation, Speed } )
|
||||
|
||||
|
||||
local RoutePoint = {}
|
||||
RoutePoint.x = self.x
|
||||
RoutePoint.y = self.z
|
||||
|
||||
RoutePoint.action = Formation or ""
|
||||
--RoutePoint.formation_template = Formation and "" or nil
|
||||
|
||||
|
||||
RoutePoint.speed = ( Speed or 20 ) / 3.6
|
||||
@ -940,13 +940,17 @@ do -- COORDINATE
|
||||
-- @param #COORDINATE ToCoord Coordinate of destination.
|
||||
-- @return #table Table of coordinates on road.
|
||||
function COORDINATE:GetPathOnRoad(ToCoord)
|
||||
self:F2(ToCoord)
|
||||
local path = land.findPathOnRoads("roads", self.x, self.z, ToCoord.x, ToCoord.z)
|
||||
local Path={}
|
||||
for i, v in ipairs(path) do
|
||||
Path[#Path+1]=COORDINATE:NewFromVec2(v)
|
||||
end
|
||||
self:F(string.format("Number of points in Path on Road = %d", #Path))
|
||||
local path = land.findPathOnRoads("roads", self.x, self.z, ToCoord.x, ToCoord.z)
|
||||
Path[#Path+1]=COORDINATE:NewFromVec2(path[1])
|
||||
Path[#Path+1]=COORDINATE:NewFromVec2(path[#path])
|
||||
-- I've removed this stuff because it severely slows down DCS in case of paths with a lot of segments.
|
||||
-- Just the beginning and the end point is sufficient.
|
||||
-- for i, v in ipairs(path) do
|
||||
-- self:I(v)
|
||||
-- local coord=COORDINATE:NewFromVec2(v)
|
||||
-- Path[#Path+1]=COORDINATE:NewFromVec2(v)
|
||||
-- end
|
||||
return Path
|
||||
end
|
||||
|
||||
|
||||
@ -357,9 +357,11 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime )
|
||||
local function SetTask( Controller, DCSTask )
|
||||
if self and self:IsAlive() then
|
||||
local Controller = self:_GetController()
|
||||
self:I( "Before SetTask" )
|
||||
Controller:setTask( DCSTask )
|
||||
self:I( "After SetTask" )
|
||||
else
|
||||
BASE:E( DCSControllableName .. " is not alive anymore. Cannot set DCSTask " .. DCSTask )
|
||||
BASE:E( { DCSControllableName .. " is not alive anymore.", DCSTask = DCSTask } )
|
||||
end
|
||||
end
|
||||
|
||||
@ -496,7 +498,7 @@ function CONTROLLABLE:SetTaskWaypoint( Waypoint, Task )
|
||||
|
||||
Waypoint.task = self:TaskCombo( { Task } )
|
||||
|
||||
self:T3( { Waypoint.task } )
|
||||
self:F( { Waypoint.task } )
|
||||
return Waypoint.task
|
||||
end
|
||||
|
||||
@ -1766,351 +1768,390 @@ function CONTROLLABLE:TaskRoute( Points )
|
||||
return DCSTask
|
||||
end
|
||||
|
||||
--- (AIR + GROUND) Make the Controllable move to fly to a given point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format.
|
||||
-- @param #number Speed The speed to travel.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:RouteToVec2( Point, Speed )
|
||||
self:F2( { Point, Speed } )
|
||||
do -- Route methods
|
||||
|
||||
local ControllablePoint = self:GetUnit( 1 ):GetVec2()
|
||||
|
||||
local PointFrom = {}
|
||||
PointFrom.x = ControllablePoint.x
|
||||
PointFrom.y = ControllablePoint.y
|
||||
PointFrom.type = "Turning Point"
|
||||
PointFrom.action = "Turning Point"
|
||||
PointFrom.speed = Speed
|
||||
PointFrom.speed_locked = true
|
||||
PointFrom.properties = {
|
||||
["vnav"] = 1,
|
||||
["scale"] = 0,
|
||||
["angle"] = 0,
|
||||
["vangle"] = 0,
|
||||
["steer"] = 2,
|
||||
}
|
||||
|
||||
|
||||
local PointTo = {}
|
||||
PointTo.x = Point.x
|
||||
PointTo.y = Point.y
|
||||
PointTo.type = "Turning Point"
|
||||
PointTo.action = "Fly Over Point"
|
||||
PointTo.speed = Speed
|
||||
PointTo.speed_locked = true
|
||||
PointTo.properties = {
|
||||
["vnav"] = 1,
|
||||
["scale"] = 0,
|
||||
["angle"] = 0,
|
||||
["vangle"] = 0,
|
||||
["steer"] = 2,
|
||||
}
|
||||
|
||||
|
||||
local Points = { PointFrom, PointTo }
|
||||
|
||||
self:T3( Points )
|
||||
|
||||
self:Route( Points )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- (AIR + GROUND) Make the Controllable move to a given point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format.
|
||||
-- @param #number Speed The speed to travel.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:RouteToVec3( Point, Speed )
|
||||
self:F2( { Point, Speed } )
|
||||
|
||||
local ControllableVec3 = self:GetUnit( 1 ):GetVec3()
|
||||
|
||||
local PointFrom = {}
|
||||
PointFrom.x = ControllableVec3.x
|
||||
PointFrom.y = ControllableVec3.z
|
||||
PointFrom.alt = ControllableVec3.y
|
||||
PointFrom.alt_type = "BARO"
|
||||
PointFrom.type = "Turning Point"
|
||||
PointFrom.action = "Turning Point"
|
||||
PointFrom.speed = Speed
|
||||
PointFrom.speed_locked = true
|
||||
PointFrom.properties = {
|
||||
["vnav"] = 1,
|
||||
["scale"] = 0,
|
||||
["angle"] = 0,
|
||||
["vangle"] = 0,
|
||||
["steer"] = 2,
|
||||
}
|
||||
|
||||
|
||||
local PointTo = {}
|
||||
PointTo.x = Point.x
|
||||
PointTo.y = Point.z
|
||||
PointTo.alt = Point.y
|
||||
PointTo.alt_type = "BARO"
|
||||
PointTo.type = "Turning Point"
|
||||
PointTo.action = "Fly Over Point"
|
||||
PointTo.speed = Speed
|
||||
PointTo.speed_locked = true
|
||||
PointTo.properties = {
|
||||
["vnav"] = 1,
|
||||
["scale"] = 0,
|
||||
["angle"] = 0,
|
||||
["vangle"] = 0,
|
||||
["steer"] = 2,
|
||||
}
|
||||
|
||||
|
||||
local Points = { PointFrom, PointTo }
|
||||
|
||||
self:T3( Points )
|
||||
|
||||
self:Route( Points )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Make the controllable to follow a given route.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #table Route A table of Route Points.
|
||||
-- @param #number DelaySeconds Wait for the specified seconds before executing the Route.
|
||||
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||
function CONTROLLABLE:Route( 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:SetTask( 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.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE
|
||||
function CONTROLLABLE:RouteStop()
|
||||
self:F("RouteStop")
|
||||
--- (AIR + GROUND) Make the Controllable move to fly to a given point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format.
|
||||
-- @param #number Speed The speed to travel.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:RouteToVec2( Point, Speed )
|
||||
self:F2( { Point, Speed } )
|
||||
|
||||
local CommandStop = self:CommandStopRoute( true )
|
||||
self:SetCommand( CommandStop )
|
||||
|
||||
end
|
||||
|
||||
--- Resumes the movement of the vehicle on the route.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE
|
||||
function CONTROLLABLE:RouteResume()
|
||||
self:F("RouteResume")
|
||||
local ControllablePoint = self:GetUnit( 1 ):GetVec2()
|
||||
|
||||
local CommandResume = self:CommandStopRoute( false )
|
||||
self:SetCommand( CommandResume )
|
||||
|
||||
end
|
||||
|
||||
--- Make the GROUND Controllable to drive towards a specific point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
||||
-- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h.
|
||||
-- @param #string Formation (optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right".
|
||||
-- @param #number DelaySeconds Wait for the specified seconds before executing the Route.
|
||||
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||
function CONTROLLABLE:RouteGroundTo( ToCoordinate, Speed, Formation, DelaySeconds )
|
||||
|
||||
local FromCoordinate = self:GetCoordinate()
|
||||
|
||||
local FromWP = FromCoordinate:WaypointGround()
|
||||
local ToWP = ToCoordinate:WaypointGround( Speed, Formation )
|
||||
|
||||
self:Route( { FromWP, ToWP }, DelaySeconds )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Make the GROUND Controllable to drive towards a specific point using (only) roads.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
||||
-- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h.
|
||||
-- @param #number DelaySeconds Wait for the specified seconds before executing the Route.
|
||||
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||
function CONTROLLABLE:RouteGroundOnRoad( ToCoordinate, Speed, DelaySeconds )
|
||||
|
||||
-- Current coordinate.
|
||||
local FromCoordinate = self:GetCoordinate()
|
||||
|
||||
-- Formation is set to on road.
|
||||
local Formation="On Road"
|
||||
|
||||
-- Path on road from current position to destination coordinate.
|
||||
local path=FromCoordinate:GetPathOnRoad(ToCoordinate)
|
||||
|
||||
-- Route, ground waypoints along roads.
|
||||
local route={}
|
||||
table.insert(route, FromCoordinate:WaypointGround(Speed, Formation))
|
||||
|
||||
-- Convert coordinates to ground waypoints and insert into table.
|
||||
for _, coord in ipairs(path) do
|
||||
table.insert(route, coord:WaypointGround(Speed, Formation))
|
||||
end
|
||||
|
||||
-- Add the final coordinate because the final coordinate in path is last point on road.
|
||||
local dist=ToCoordinate:Get2DDistance(path[#path])
|
||||
if dist>10 then
|
||||
table.insert(route, ToCoordinate:WaypointGround(Speed, "Vee"))
|
||||
end
|
||||
|
||||
-- Route controllable to destination.
|
||||
self:Route(route, DelaySeconds)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Make the AIR Controllable fly towards a specific point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
||||
-- @param Core.Point#COORDINATE.RoutePointAltType AltType The altitude type.
|
||||
-- @param Core.Point#COORDINATE.RoutePointType Type The route point type.
|
||||
-- @param Core.Point#COORDINATE.RoutePointAction Action The route point action.
|
||||
-- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h.
|
||||
-- @param #number DelaySeconds Wait for the specified seconds before executing the Route.
|
||||
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||
function CONTROLLABLE:RouteAirTo( ToCoordinate, AltType, Type, Action, Speed, DelaySeconds )
|
||||
|
||||
local FromCoordinate = self:GetCoordinate()
|
||||
local FromWP = FromCoordinate:WaypointAir()
|
||||
|
||||
local ToWP = ToCoordinate:WaypointAir( AltType, Type, Action, Speed )
|
||||
|
||||
self:Route( { FromWP, ToWP }, DelaySeconds )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- (AIR + GROUND) Route the controllable to a given zone.
|
||||
-- The controllable final destination point can be randomized.
|
||||
-- A speed can be given in km/h.
|
||||
-- A given formation can be given.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Zone#ZONE Zone The zone where to route to.
|
||||
-- @param #boolean Randomize Defines whether to target point gets randomized within the Zone.
|
||||
-- @param #number Speed The speed.
|
||||
-- @param Base#FORMATION Formation The formation string.
|
||||
function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation )
|
||||
self:F2( Zone )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
|
||||
if DCSControllable then
|
||||
|
||||
local ControllablePoint = self:GetVec2()
|
||||
|
||||
local PointFrom = {}
|
||||
PointFrom.x = ControllablePoint.x
|
||||
PointFrom.y = ControllablePoint.y
|
||||
PointFrom.type = "Turning Point"
|
||||
PointFrom.action = Formation or "Cone"
|
||||
PointFrom.speed = 20 / 1.6
|
||||
|
||||
|
||||
PointFrom.action = "Turning Point"
|
||||
PointFrom.speed = Speed
|
||||
PointFrom.speed_locked = true
|
||||
PointFrom.properties = {
|
||||
["vnav"] = 1,
|
||||
["scale"] = 0,
|
||||
["angle"] = 0,
|
||||
["vangle"] = 0,
|
||||
["steer"] = 2,
|
||||
}
|
||||
|
||||
|
||||
local PointTo = {}
|
||||
local ZonePoint
|
||||
|
||||
if Randomize then
|
||||
ZonePoint = Zone:GetRandomVec2()
|
||||
else
|
||||
ZonePoint = Zone:GetVec2()
|
||||
end
|
||||
|
||||
PointTo.x = ZonePoint.x
|
||||
PointTo.y = ZonePoint.y
|
||||
PointTo.x = Point.x
|
||||
PointTo.y = Point.y
|
||||
PointTo.type = "Turning Point"
|
||||
|
||||
if Formation then
|
||||
PointTo.action = Formation
|
||||
else
|
||||
PointTo.action = "Cone"
|
||||
end
|
||||
|
||||
if Speed then
|
||||
PointTo.speed = Speed
|
||||
else
|
||||
PointTo.speed = 20 / 1.6
|
||||
end
|
||||
|
||||
PointTo.action = "Fly Over Point"
|
||||
PointTo.speed = Speed
|
||||
PointTo.speed_locked = true
|
||||
PointTo.properties = {
|
||||
["vnav"] = 1,
|
||||
["scale"] = 0,
|
||||
["angle"] = 0,
|
||||
["vangle"] = 0,
|
||||
["steer"] = 2,
|
||||
}
|
||||
|
||||
|
||||
local Points = { PointFrom, PointTo }
|
||||
|
||||
|
||||
self:T3( Points )
|
||||
|
||||
|
||||
self:Route( Points )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- (GROUND) Route the controllable to a given Vec2.
|
||||
-- A speed can be given in km/h.
|
||||
-- A given formation can be given.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #Vec2 Vec2 The Vec2 where to route to.
|
||||
-- @param #number Speed The speed.
|
||||
-- @param Base#FORMATION Formation The formation string.
|
||||
function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
|
||||
if DCSControllable then
|
||||
|
||||
local ControllablePoint = self:GetVec2()
|
||||
|
||||
|
||||
--- (AIR + GROUND) Make the Controllable move to a given point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Dcs.DCSTypes#Vec3 Point The destination point in Vec3 format.
|
||||
-- @param #number Speed The speed to travel.
|
||||
-- @return #CONTROLLABLE self
|
||||
function CONTROLLABLE:RouteToVec3( Point, Speed )
|
||||
self:F2( { Point, Speed } )
|
||||
|
||||
local ControllableVec3 = self:GetUnit( 1 ):GetVec3()
|
||||
|
||||
local PointFrom = {}
|
||||
PointFrom.x = ControllablePoint.x
|
||||
PointFrom.y = ControllablePoint.y
|
||||
PointFrom.x = ControllableVec3.x
|
||||
PointFrom.y = ControllableVec3.z
|
||||
PointFrom.alt = ControllableVec3.y
|
||||
PointFrom.alt_type = "BARO"
|
||||
PointFrom.type = "Turning Point"
|
||||
PointFrom.action = Formation or "Cone"
|
||||
PointFrom.speed = 20 / 1.6
|
||||
|
||||
|
||||
PointFrom.action = "Turning Point"
|
||||
PointFrom.speed = Speed
|
||||
PointFrom.speed_locked = true
|
||||
PointFrom.properties = {
|
||||
["vnav"] = 1,
|
||||
["scale"] = 0,
|
||||
["angle"] = 0,
|
||||
["vangle"] = 0,
|
||||
["steer"] = 2,
|
||||
}
|
||||
|
||||
|
||||
local PointTo = {}
|
||||
|
||||
PointTo.x = Vec2.x
|
||||
PointTo.y = Vec2.y
|
||||
PointTo.x = Point.x
|
||||
PointTo.y = Point.z
|
||||
PointTo.alt = Point.y
|
||||
PointTo.alt_type = "BARO"
|
||||
PointTo.type = "Turning Point"
|
||||
|
||||
if Formation then
|
||||
PointTo.action = Formation
|
||||
else
|
||||
PointTo.action = "Cone"
|
||||
end
|
||||
|
||||
if Speed then
|
||||
PointTo.speed = Speed
|
||||
else
|
||||
PointTo.speed = 60 / 3.6
|
||||
end
|
||||
|
||||
PointTo.action = "Fly Over Point"
|
||||
PointTo.speed = Speed
|
||||
PointTo.speed_locked = true
|
||||
PointTo.properties = {
|
||||
["vnav"] = 1,
|
||||
["scale"] = 0,
|
||||
["angle"] = 0,
|
||||
["vangle"] = 0,
|
||||
["steer"] = 2,
|
||||
}
|
||||
|
||||
|
||||
local Points = { PointFrom, PointTo }
|
||||
|
||||
|
||||
self:T3( Points )
|
||||
|
||||
|
||||
self:Route( Points )
|
||||
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Make the controllable to follow a given route.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #table Route A table of Route Points.
|
||||
-- @param #number DelaySeconds Wait for the specified seconds before executing the Route.
|
||||
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||
function CONTROLLABLE:Route( 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:SetTask( 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.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE
|
||||
function CONTROLLABLE:RouteStop()
|
||||
self:F("RouteStop")
|
||||
|
||||
local CommandStop = self:CommandStopRoute( true )
|
||||
self:SetCommand( CommandStop )
|
||||
|
||||
end
|
||||
|
||||
--- Resumes the movement of the vehicle on the route.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @return #CONTROLLABLE
|
||||
function CONTROLLABLE:RouteResume()
|
||||
self:F("RouteResume")
|
||||
|
||||
local CommandResume = self:CommandStopRoute( false )
|
||||
self:SetCommand( CommandResume )
|
||||
|
||||
end
|
||||
|
||||
--- Make the GROUND Controllable to drive towards a specific point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
||||
-- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h.
|
||||
-- @param #string Formation (optional) The route point Formation, which is a text string that specifies exactly the Text in the Type of the route point, like "Vee", "Echelon Right".
|
||||
-- @param #number DelaySeconds Wait for the specified seconds before executing the Route.
|
||||
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||
function CONTROLLABLE:RouteGroundTo( ToCoordinate, Speed, Formation, DelaySeconds )
|
||||
|
||||
local FromCoordinate = self:GetCoordinate()
|
||||
|
||||
local FromWP = FromCoordinate:WaypointGround()
|
||||
local ToWP = ToCoordinate:WaypointGround( Speed, Formation )
|
||||
|
||||
self:Route( { FromWP, ToWP }, DelaySeconds )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Make the GROUND Controllable to drive towards a specific point using (only) roads.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
||||
-- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h.
|
||||
-- @param #number DelaySeconds Wait for the specified seconds before executing the Route.
|
||||
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||
function CONTROLLABLE:RouteGroundOnRoad( ToCoordinate, Speed, DelaySeconds )
|
||||
|
||||
-- Current coordinate.
|
||||
local FromCoordinate = self:GetCoordinate()
|
||||
|
||||
-- Formation is set to on road.
|
||||
local Formation="On Road"
|
||||
|
||||
-- Path on road from current position to destination coordinate.
|
||||
local path=FromCoordinate:GetPathOnRoad(ToCoordinate)
|
||||
|
||||
-- Route, ground waypoints along roads.
|
||||
local route={}
|
||||
table.insert(route, FromCoordinate:WaypointGround(Speed, Formation))
|
||||
|
||||
-- Convert coordinates to ground waypoints and insert into table.
|
||||
for _, coord in ipairs(path) do
|
||||
table.insert(route, coord:WaypointGround(Speed, Formation))
|
||||
end
|
||||
|
||||
-- Add the final coordinate because the final coordinate in path is last point on road.
|
||||
local dist=ToCoordinate:Get2DDistance(path[#path])
|
||||
if dist>10 then
|
||||
table.insert(route, ToCoordinate:WaypointGround(Speed, "Vee"))
|
||||
end
|
||||
|
||||
-- Route controllable to destination.
|
||||
self:Route( route, DelaySeconds )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- Make a task for a GROUND Controllable to drive towards a specific point using (only) roads.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
||||
-- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h.
|
||||
-- @param #string EndPointFormation The formation to achieve at the end point.
|
||||
-- @return Task
|
||||
function CONTROLLABLE:TaskGroundOnRoad( ToCoordinate, Speed, EndPointFormation )
|
||||
|
||||
-- Current coordinate.
|
||||
local FromCoordinate = self:GetCoordinate()
|
||||
|
||||
-- Formation is set to on road.
|
||||
local Formation="On Road"
|
||||
|
||||
-- Path on road from current position to destination coordinate.
|
||||
local path=FromCoordinate:GetPathOnRoad( ToCoordinate )
|
||||
|
||||
-- Route, ground waypoints along roads.
|
||||
local Route = {}
|
||||
table.insert( Route, FromCoordinate:WaypointGround( Speed, Formation ) )
|
||||
|
||||
-- Convert coordinates to ground waypoints and insert into table.
|
||||
for _, coord in ipairs(path) do
|
||||
table.insert( Route, coord:WaypointGround( Speed, Formation ) )
|
||||
end
|
||||
|
||||
-- Add the final coordinate because the final coordinate in path is last point on road.
|
||||
local dist=ToCoordinate:Get2DDistance(path[#path])
|
||||
if dist>10 then
|
||||
table.insert( Route, ToCoordinate:WaypointGround( Speed, EndPointFormation ) )
|
||||
end
|
||||
|
||||
return Route
|
||||
end
|
||||
|
||||
|
||||
--- Make the AIR Controllable fly towards a specific point.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Point#COORDINATE ToCoordinate A Coordinate to drive to.
|
||||
-- @param Core.Point#COORDINATE.RoutePointAltType AltType The altitude type.
|
||||
-- @param Core.Point#COORDINATE.RoutePointType Type The route point type.
|
||||
-- @param Core.Point#COORDINATE.RoutePointAction Action The route point action.
|
||||
-- @param #number Speed (optional) Speed in km/h. The default speed is 999 km/h.
|
||||
-- @param #number DelaySeconds Wait for the specified seconds before executing the Route.
|
||||
-- @return #CONTROLLABLE The CONTROLLABLE.
|
||||
function CONTROLLABLE:RouteAirTo( ToCoordinate, AltType, Type, Action, Speed, DelaySeconds )
|
||||
|
||||
local FromCoordinate = self:GetCoordinate()
|
||||
local FromWP = FromCoordinate:WaypointAir()
|
||||
|
||||
local ToWP = ToCoordinate:WaypointAir( AltType, Type, Action, Speed )
|
||||
|
||||
self:Route( { FromWP, ToWP }, DelaySeconds )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- (AIR + GROUND) Route the controllable to a given zone.
|
||||
-- The controllable final destination point can be randomized.
|
||||
-- A speed can be given in km/h.
|
||||
-- A given formation can be given.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param Core.Zone#ZONE Zone The zone where to route to.
|
||||
-- @param #boolean Randomize Defines whether to target point gets randomized within the Zone.
|
||||
-- @param #number Speed The speed.
|
||||
-- @param Base#FORMATION Formation The formation string.
|
||||
function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation )
|
||||
self:F2( Zone )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
|
||||
if DCSControllable then
|
||||
|
||||
local ControllablePoint = self:GetVec2()
|
||||
|
||||
local PointFrom = {}
|
||||
PointFrom.x = ControllablePoint.x
|
||||
PointFrom.y = ControllablePoint.y
|
||||
PointFrom.type = "Turning Point"
|
||||
PointFrom.action = Formation or "Cone"
|
||||
PointFrom.speed = 20 / 1.6
|
||||
|
||||
|
||||
local PointTo = {}
|
||||
local ZonePoint
|
||||
|
||||
if Randomize then
|
||||
ZonePoint = Zone:GetRandomVec2()
|
||||
else
|
||||
ZonePoint = Zone:GetVec2()
|
||||
end
|
||||
|
||||
PointTo.x = ZonePoint.x
|
||||
PointTo.y = ZonePoint.y
|
||||
PointTo.type = "Turning Point"
|
||||
|
||||
if Formation then
|
||||
PointTo.action = Formation
|
||||
else
|
||||
PointTo.action = "Cone"
|
||||
end
|
||||
|
||||
if Speed then
|
||||
PointTo.speed = Speed
|
||||
else
|
||||
PointTo.speed = 20 / 1.6
|
||||
end
|
||||
|
||||
local Points = { PointFrom, PointTo }
|
||||
|
||||
self:T3( Points )
|
||||
|
||||
self:Route( Points )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--- (GROUND) Route the controllable to a given Vec2.
|
||||
-- A speed can be given in km/h.
|
||||
-- A given formation can be given.
|
||||
-- @param #CONTROLLABLE self
|
||||
-- @param #Vec2 Vec2 The Vec2 where to route to.
|
||||
-- @param #number Speed The speed.
|
||||
-- @param Base#FORMATION Formation The formation string.
|
||||
function CONTROLLABLE:TaskRouteToVec2( Vec2, Speed, Formation )
|
||||
|
||||
local DCSControllable = self:GetDCSObject()
|
||||
|
||||
if DCSControllable then
|
||||
|
||||
local ControllablePoint = self:GetVec2()
|
||||
|
||||
local PointFrom = {}
|
||||
PointFrom.x = ControllablePoint.x
|
||||
PointFrom.y = ControllablePoint.y
|
||||
PointFrom.type = "Turning Point"
|
||||
PointFrom.action = Formation or "Cone"
|
||||
PointFrom.speed = 20 / 1.6
|
||||
|
||||
|
||||
local PointTo = {}
|
||||
|
||||
PointTo.x = Vec2.x
|
||||
PointTo.y = Vec2.y
|
||||
PointTo.type = "Turning Point"
|
||||
|
||||
if Formation then
|
||||
PointTo.action = Formation
|
||||
else
|
||||
PointTo.action = "Cone"
|
||||
end
|
||||
|
||||
if Speed then
|
||||
PointTo.speed = Speed
|
||||
else
|
||||
PointTo.speed = 60 / 3.6
|
||||
end
|
||||
|
||||
local Points = { PointFrom, PointTo }
|
||||
|
||||
self:T3( Points )
|
||||
|
||||
self:Route( Points )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
end -- Route methods
|
||||
|
||||
-- Commands
|
||||
|
||||
|
||||
@ -808,6 +808,15 @@ function POSITIONABLE:AddCargo( Cargo )
|
||||
return self
|
||||
end
|
||||
|
||||
--- Get all contained cargo.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @return #POSITIONABLE
|
||||
function POSITIONABLE:GetCargo()
|
||||
return self.__.Cargo
|
||||
end
|
||||
|
||||
|
||||
|
||||
--- Remove cargo.
|
||||
-- @param #POSITIONABLE self
|
||||
-- @param Core.Cargo#CARGO Cargo
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user