Finish Cargo/Limits

This commit is contained in:
FlightControl 2018-08-22 21:40:49 +02:00
commit 4f38d8109d
29 changed files with 2560 additions and 749 deletions

View File

@ -96,7 +96,7 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius )
self:AddTransition( "Loaded", "Deploy", "*" )
self:AddTransition( "*", "Load", "Boarding" )
self:AddTransition( "Boarding", "Board", "Boarding" )
self:AddTransition( { "Boarding", "Loaded" }, "Board", "Boarding" )
self:AddTransition( "Boarding", "Loaded", "Loaded" )
self:AddTransition( "Loaded", "Unload", "Unboarding" )
self:AddTransition( "Unboarding", "Unboard", "Unboarding" )
@ -139,7 +139,7 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius )
-- @function [parent=#AI_CARGO_APC] __Pickup
-- @param #AI_CARGO_APC self
-- @param #number Delay
-- @param Core.Point#COORDINATE Coordinate
-- @param Core.Point#COORDINATE Coordinate Pickup place. If not given, loading starts at the current location.
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
--- Deploy Handler OnBefore for AI_CARGO_APC
@ -170,8 +170,8 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius )
--- 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
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h. Default is 50% of max possible speed the group can do.
@ -194,8 +194,12 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius )
self:__Monitor( 1 )
self:SetCarrier( APC )
for _, APCUnit in pairs( APC:GetUnits() ) do
APCUnit:SetCargoBayWeightLimit()
end
self.Transporting = false
self.Relocating = false
@ -411,7 +415,6 @@ function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To )
self:F( { APC, From, Event, To } )
local Boarding = false
self.BoardingCount = 0
if APC and APC:IsAlive() then
self.APC_Cargo = {}
@ -423,21 +426,30 @@ function AI_CARGO_APC:onbeforeLoad( APC, From, Event, To )
if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then
if Cargo:IsInLoadRadius( APCUnit:GetCoordinate() ) then
self:F( { "In radius", APCUnit:GetName() } )
local CargoBayFreeWeight = APCUnit:GetCargoBayFreeWeight()
local CargoWeight = Cargo:GetWeight()
self:F({CargoBayFreeWeight=CargoBayFreeWeight})
-- Only when there is space within the bay to load the next cargo item!
if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then
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
Boarding = true
break
end
end
end
end
end
end
return Boarding
@ -458,7 +470,31 @@ function AI_CARGO_APC:onafterBoard( APC, From, Event, To, Cargo )
if not Cargo:IsLoaded() then
self:__Board( 10, Cargo )
else
self:__Loaded( 1 )
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
if Cargo:IsUnLoaded() then
if Cargo:IsInLoadRadius( APCUnit:GetCoordinate() ) then
local CargoBayFreeWeight = APCUnit:GetCargoBayFreeWeight()
local CargoWeight = Cargo:GetWeight()
self:F({CargoBayFreeWeight=CargoBayFreeWeight})
-- Only when there is space within the bay to load the next cargo item!
if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then
Cargo:Board( APCUnit, 25 )
self:__Board( 10, Cargo )
-- 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
return
end
end
end
end
end
self:__Loaded( 5, Cargo )
end
end
@ -471,7 +507,7 @@ end
-- @param #string Event Event.
-- @param #string To To state.
-- @return #boolean Cargo loaded.
function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To )
function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To, Cargo )
self:F( { APC, From, Event, To } )
local Loaded = true
@ -484,7 +520,6 @@ function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To )
Loaded = false
end
end
end
if Loaded == true then
@ -496,6 +531,9 @@ function AI_CARGO_APC:onbeforeLoaded( APC, From, Event, To )
end
--- On after Unload event.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
@ -511,11 +549,14 @@ function AI_CARGO_APC:onafterUnload( APC, From, Event, To, Deployed )
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
APC:RouteStop()
for _, Cargo in pairs( APCUnit:GetCargo() ) do
if Cargo:IsLoaded() then
Cargo:UnBoard()
Cargo:SetDeployed( true )
self:__Unboard( 10, Cargo, Deployed )
end
end
end
end
end
@ -534,6 +575,17 @@ function AI_CARGO_APC:onafterUnboard( APC, From, Event, To, Cargo, Deployed )
if not Cargo:IsUnLoaded() then
self:__Unboard( 10, Cargo, Deployed )
else
for _, APCUnit in pairs( APC:GetUnits() ) do
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
for _, Cargo in pairs( APCUnit:GetCargo() ) do
if Cargo:IsLoaded() then
Cargo:UnBoard()
Cargo:SetDeployed( true )
self:__Unboard( 10, Cargo, Deployed )
return
end
end
end
self:__Unloaded( 1, Cargo, Deployed )
end
end
@ -559,22 +611,16 @@ function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo, Deployed )
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]
if CargoCheck then
self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } )
if CargoCheck:IsUnLoaded() == false then
local IsEmpty = APCUnit:IsCargoEmpty()
self:I({ IsEmpty = IsEmpty })
if not IsEmpty then
AllUnloaded = false
break
end
end
end
if AllUnloaded == true then
if Deployed == true then
for APCUnit, Cargo in pairs( self.APC_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
Cargo:SetDeployed( true )
end
self.APC_Cargo = {}
end
self:Guard()
@ -587,6 +633,21 @@ function AI_CARGO_APC:onbeforeUnloaded( APC, From, Event, To, Cargo, Deployed )
end
--- On after Unloaded event.
-- @param #AI_CARGO_APC self
-- @param Wrapper.Group#GROUP APC
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #string Cargo.Cargo#CARGO Cargo Cargo object.
-- @param #boolean Deployed Cargo is deployed.
-- @return #boolean All cargo unloaded.
function AI_CARGO_APC:onafterUnloaded( APC, From, Event, To, Cargo, Deployed )
self:F( { APC, From, Event, To, Cargo:GetName(), Deployed = Deployed } )
self.Transporting = false
end
--- On after Follow event.
-- @param #AI_CARGO_APC self
@ -632,7 +693,6 @@ function AI_CARGO_APC._Deploy( APC, self )
if APC:IsAlive() then
self:Unload( true )
self.Transporting = false
self.Relocating = false
end
end

View File

@ -23,8 +23,8 @@ AI_CARGO_AIRPLANE = {
--- Creates a new AI_CARGO_AIRPLANE object.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
-- @param Core.Set#SET_CARGO CargoSet
-- @param Wrapper.Group#GROUP Airplane Plane used for transportation of cargo.
-- @param Core.Set#SET_CARGO CargoSet Cargo set to be transported.
-- @return #AI_CARGO_AIRPLANE
function AI_CARGO_AIRPLANE:New( Airplane, CargoSet )
@ -34,10 +34,10 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet )
self:SetStartState( "Unloaded" )
self:AddTransition( "Unloaded", "Pickup", "*" )
self:AddTransition( { "Unloaded", "Loaded" }, "Pickup", "*" )
self:AddTransition( "Loaded", "Deploy", "*" )
self:AddTransition( "Unloaded", "Load", "Boarding" )
self:AddTransition( { "Unloaded", "Boarding" }, "Load", "Boarding" )
self:AddTransition( "Boarding", "Board", "Boarding" )
self:AddTransition( "Boarding", "Loaded", "Loaded" )
self:AddTransition( "Loaded", "Unload", "Unboarding" )
@ -45,76 +45,113 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet )
self:AddTransition( "Unboarding" , "Unloaded", "Unloaded" )
self:AddTransition( "*", "Landed", "*" )
self:AddTransition( "*", "Home" , "*" )
self:AddTransition( "*", "Destroyed", "Destroyed" )
--- Pickup Handler OnBefore for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnBeforePickup
-- @param #AI_CARGO_AIRPLANE self
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
-- @param #number Speed in km/h for travelling to pickup base.
-- @return #boolean
--- Pickup Handler OnAfter for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnAfterPickup
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
-- @param #number Speed in km/h for travelling to pickup base.
--- Pickup Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] Pickup
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
-- @param #number Speed in km/h for travelling to pickup base.
--- Pickup Asynchronous Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] __Pickup
-- @param #AI_CARGO_AIRPLANE self
-- @param #number Delay
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Delay Delay in seconds.
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troops are picked up.
-- @param #number Speed in km/h for travelling to pickup base.
--- Deploy Handler OnBefore for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnBeforeDeploy
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
-- @param #number Speed Speed in km/h for travelling to deploy base.
-- @return #boolean
--- Deploy Handler OnAfter for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] OnAfterDeploy
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
-- @param #number Speed Speed in km/h for travelling to deploy base.
--- Deploy Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] Deploy
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
-- @param #number Speed Speed in km/h for travelling to deploy base.
--- Deploy Asynchronous Trigger for AI_CARGO_AIRPLANE
-- @function [parent=#AI_CARGO_AIRPLANE] __Deploy
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Delay
-- @param #number Delay Delay in seconds.
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase where troops are deployed.
-- @param #number Speed Speed in km/h for travelling to deploy base.
--- On after Loaded event, i.e. triggered when the cargo is inside the carrier.
-- @function [parent=#AI_CARGO_AIRPLANE] OnAfterLoaded
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo plane.
-- @param From
-- @param Event
-- @param To
-- Set carrier.
self:SetCarrier( Airplane )
Airplane:SetCargoBayWeightLimit()
self.Relocating = true
return self
end
--- Set the Carrier.
function AI_CARGO_AIRPLANE:IsTransporting()
return self.Transporting == true
end
function AI_CARGO_AIRPLANE:IsRelocating()
return self.Relocating == true
end
--- Set the Carrier (controllable). Also initializes events for carrier and defines the coalition.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
-- @return #AI_CARGO_AIRPLANE
-- @param Wrapper.Group#GROUP Airplane Transport plane.
-- @return #AI_CARGO_AIRPLANE self
function AI_CARGO_AIRPLANE:SetCarrier( Airplane )
local AICargo = self
@ -155,7 +192,8 @@ function AI_CARGO_AIRPLANE:SetCarrier( Airplane )
function Airplane:OnEventEngineShutdown( EventData )
AICargo:Landed()
AICargo.Relocating = false
AICargo:Landed( self.Airplane )
end
self.Coalition = self.Airplane:GetCoalition()
@ -190,25 +228,32 @@ function AI_CARGO_AIRPLANE:FindCarrier( Coordinate, Radius )
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
--- On after "Landed" event. Called on engine shutdown and initiates the pickup mission or unloading event.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param From
-- @param Event
-- @param To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Speed
function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To )
if Airplane and Airplane:IsAlive() then
self:F({Airplane, From, Event, To})
if Airplane and Airplane:IsAlive()~=nil then
-- Aircraft was sent to this airbase to pickup troops. Initiate loadling.
if self.RoutePickup == true then
self:Load( Airplane:GetPointVec2() )
env.info("FF load airplane "..Airplane:GetName())
self:Load( Airplane:GetCoordinate() )
self.RoutePickup = false
self.Relocating = true
end
-- Aircraft was send to this airbase to deploy troops. Initiate unloading.
if self.RouteDeploy == true then
self:Unload()
self.RouteDeploy = false
self.Transporting = false
self.Relocating = false
end
end
@ -216,231 +261,344 @@ function AI_CARGO_AIRPLANE:onafterLanded( Airplane, From, Event, To )
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
-- @param From
-- @param Event
-- @param To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Speed
--- On after "Pickup" event. Routes transport to pickup airbase.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where the troops as picked up.
-- @param #number Speed in km/h for travelling to pickup base.
function AI_CARGO_AIRPLANE:onafterPickup( Airplane, From, Event, To, Airbase, Speed )
if Airplane and Airplane:IsAlive() then
if Airplane and Airplane:IsAlive()~=nil then
env.info("FF onafterpick aircraft alive")
-- Get closest airbase of current position.
local ClosestAirbase, DistToAirbase=Airplane:GetCoordinate():GetClosestAirbase()
env.info("FF onafterpickup closest airbase "..ClosestAirbase:GetName())
-- Two cases. Aircraft spawned in air or at an airbase.
if Airplane:InAir() then
self.Airbase=nil --> route will start in air
else
self.Airbase=ClosestAirbase
end
-- Distance from closest to pickup airbase ==> we need to know if we are already at the pickup airbase.
local Dist=Airbase:GetCoordinate():Get2DDistance(ClosestAirbase:GetCoordinate())
env.info("Distance closest to pickup airbase = "..Dist)
if Airplane:InAir() or Dist>500 then
env.info("FF onafterpickup routing to airbase "..ClosestAirbase:GetName())
-- Route aircraft to pickup airbase.
self:Route( Airplane, Airbase, Speed )
self.RoutePickup = true
-- Set airbase as starting point in the next Route() call.
self.Airbase = Airbase
-- Aircraft is on a pickup mission.
self.RoutePickup = true
-- Unclear!?
self.Transporting = true
self.Relocating = false
else
env.info("FF onafterpick calling landed")
-- We are already at the right airbase ==> Landed ==> triggers loading of troops. Is usually called at engine shutdown event.
self.RoutePickup=true
self:Landed()
end
else
env.info("FF onafterpick aircraft not alive")
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
-- @param From
-- @param Event
-- @param To
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Speed
--- On after Depoly event. Routes plane to the airbase where the troops are deployed.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Airbase#AIRBASE Airbase Airbase where troups should be deployed.
-- @param #number Speed Speed in km/h for travelling to deploy base.
function AI_CARGO_AIRPLANE:onafterDeploy( Airplane, From, Event, To, Airbase, Speed )
if Airplane and Airplane:IsAlive() then
if Airplane and Airplane:IsAlive()~=nil then
-- Activate uncontrolled airplane.
if Airplane:IsAlive()==false then
Airplane:SetCommand({id = 'Start', params = {}})
end
-- Route to destination airbase.
self:Route( Airplane, Airbase, Speed )
-- Aircraft is on a depoly mission.
self.RouteDeploy = true
-- Set destination airbase for next :Route() command.
self.Airbase = Airbase
self.Transporting = true
self.Relocating = false
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
--- On after Load event. Checks if cargo is inside the load radius and if so starts the boarding process.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Point#COORDINATE Coordinate Place where the cargo is guided to if it is inside the load radius.
function AI_CARGO_AIRPLANE:onafterLoad( Airplane, From, Event, To, Coordinate )
if Airplane and Airplane:IsAlive() then
if Airplane and Airplane:IsAlive() ~= nil then
for _, Cargo in pairs( self.CargoSet:GetSet() ) do
if Cargo:IsInLoadRadius( Coordinate ) then
self:__Board( 5 )
for _,_Cargo in pairs( self.CargoSet:GetSet() ) do
self:F({_Cargo:GetName()})
local Cargo=_Cargo --Cargo.Cargo#CARGO
local InRadius = Cargo:IsInLoadRadius( Coordinate )
if InRadius then
-- Is there a cargo still unloaded?
if Cargo:IsUnLoaded() == true then
self:__Board( 5, Cargo )
Cargo:Board( Airplane, 25 )
self.Cargo = Cargo
break
end
end
end
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To )
--- On after Board event. Cargo is inside the load radius and boarding is performed.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function AI_CARGO_AIRPLANE:onafterBoard( Airplane, From, Event, To, Cargo )
if Airplane and Airplane:IsAlive() then
self:F({ IsLoaded = self.Cargo:IsLoaded() } )
if not self.Cargo:IsLoaded() then
self:__Board( 10 )
self:F({ IsLoaded = Cargo:IsLoaded() } )
if not Cargo:IsLoaded() then
self:__Board( 10, Cargo )
else
self:__Loaded( 1 )
-- Check if another cargo can be loaded into the airplane.
for _,_Cargo in pairs( self.CargoSet:GetSet() ) do
self:F({_Cargo:GetName()})
local Cargo =_Cargo --Cargo.Cargo#CARGO
-- Is there a cargo still unloaded?
if Cargo:IsUnLoaded() == true then
-- Only when the cargo is within load radius.
local InRadius = Cargo:IsInLoadRadius( Airplane:GetCoordinate() )
if InRadius then
local CargoBayFreeWeight = Airplane:GetCargoBayFreeWeight()
--local CargoBayFreeVolume = Airplane:GetCargoBayFreeVolume()
local CargoWeight = Cargo:GetWeight()
--local CargoVolume = Cargo:GetVolume()
-- Only when there is space within the bay to load the next cargo item!
if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then
-- ok, board.
self:__Load( 5, Airplane:GetCoordinate() )
-- And start the boarding loop for the AI_CARGO_AIRPLANE object until the cargo is boarded.
--Cargo:Board( Airplane, 25 )
return
end
end
end
end
self:__Loaded( 1, Cargo )
end
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To )
--- On after Loaded event. Cargo is inside the carrier and ready to be transported.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function AI_CARGO_AIRPLANE:onafterLoaded( Airplane, From, Event, To, Cargo )
env.info("FF troops loaded into cargo plane")
if Airplane and Airplane:IsAlive() then
self:F( { "Transporting" } )
self.Transporting = true -- This will only be executed when there is no cargo boarded anymore. The dispatcher will then kick-off the deploy cycle!
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
--- On after Unload event. Cargo is beeing unloaded, i.e. the unboarding process is started.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function AI_CARGO_AIRPLANE:onafterUnload( Airplane, From, Event, To )
if Airplane and Airplane:IsAlive() then
self.Cargo:UnBoard()
self:__Unboard( 10 )
local Cargos = Airplane:GetCargo()
for CargoID, Cargo in pairs( Cargos ) do
local Angle = 180
local CargoCarrierHeading = Airplane:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
self:T( { CargoCarrierHeading, CargoDeployHeading } )
local CargoDeployCoordinate = Airplane:GetPointVec2():Translate( 150, CargoDeployHeading )
Cargo:UnBoard( CargoDeployCoordinate )
Cargo:SetDeployed( true )
self:__Unboard( 10, Cargo )
end
end
end
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To )
--- On after Unboard event. Checks if unboarding process is finished.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function AI_CARGO_AIRPLANE:onafterUnboard( Airplane, From, Event, To, Cargo )
self:E( { "Unboard", Cargo } )
if Airplane and Airplane:IsAlive() then
if not self.Cargo:IsUnLoaded() then
self:__Unboard( 10 )
if not Cargo:IsUnLoaded() then
self:__Unboard( 10, Cargo )
else
self:__Unloaded( 1 )
local Cargos = Airplane:GetCargo()
for CargoID, Cargo in pairs( Cargos ) do
if Cargo:IsLoaded() then
local Angle = 180
local CargoCarrierHeading = Airplane:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
self:T( { CargoCarrierHeading, CargoDeployHeading } )
local CargoDeployCoordinate = Airplane:GetPointVec2():Translate( 150, CargoDeployHeading )
Cargo:UnBoard( CargoDeployCoordinate )
Cargo:SetDeployed( true )
self:__Unboard( 10, Cargo )
return
end
end
self:__Unloaded( 1, Cargo )
end
end
end
end
--- On after Unloaded event. Cargo has been unloaded, i.e. the unboarding process is finished.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Cargo transport plane.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Cargo.Cargo#CARGO Cargo
function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To, Cargo )
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
function AI_CARGO_AIRPLANE:onafterUnloaded( Airplane, From, Event, To )
self:E( { "Unloaded", Cargo } )
if Airplane and Airplane:IsAlive() then
self.Airplane = Airplane
self.Transporting = false -- This will only be executed when there is no cargo onboard anymore. The dispatcher will then kick-off the pickup cycle!
end
end
end
--- Route the airplane from one airport or it's current position to another airbase.
-- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane Airplane group to be routed.
-- @param Wrapper.Airbase#AIRBASE Airbase Destination airbase.
-- @param #number Speed Speed in km/h. Default is 80% of max possible speed the group can do.
-- @param #boolean Uncontrolled If true, spawn group in uncontrolled state.
function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed, Uncontrolled )
if Airplane and Airplane:IsAlive()~=nil then
--- @param #AI_CARGO_AIRPLANE self
-- @param Wrapper.Group#GROUP Airplane
-- @param Wrapper.Airbase#AIRBASE Airbase
-- @param #number Speed
function AI_CARGO_AIRPLANE:Route( Airplane, Airbase, Speed )
if Airplane and Airplane:IsAlive() then
local PointVec3 = Airplane:GetPointVec3()
local Takeoff = SPAWN.Takeoff.Hot
-- Set takeoff type.
local Takeoff = SPAWN.Takeoff.Cold
-- Get template of group.
local Template = Airplane:GetTemplate()
if Template then
-- Nil check
if Template==nil then
return
end
-- Waypoints of the route.
local Points={}
if self.Airbase then
local FromWaypoint = Template.route.points[1]
-- These are only for ships.
FromWaypoint.linkUnit = nil
FromWaypoint.helipadId = nil
FromWaypoint.airdromeId = nil
local AirbaseID = self.Airbase:GetID()
local AirbaseCategory = self.Airbase:GetDesc().category
FromWaypoint.airdromeId = AirbaseID
FromWaypoint.alt = 0
FromWaypoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
FromWaypoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
-- Translate the position of the Group Template to the Vec3.
for UnitID = 1, #Template.units do
self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. Template.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. Template.units[UnitID].y )
-- These cause a lot of confusion.
local UnitTemplate = Template.units[UnitID]
UnitTemplate.parking = 15
UnitTemplate.parking_id = "1"
UnitTemplate.alt = 0
local SX = UnitTemplate.x
local SY = UnitTemplate.y
local BX = FromWaypoint.x
local BY = FromWaypoint.y
local TX = PointVec3.x + ( SX - BX )
local TY = PointVec3.z + ( SY - BY )
UnitTemplate.x = TX
UnitTemplate.y = TY
self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y )
end
FromWaypoint.x = PointVec3.x
FromWaypoint.y = PointVec3.z
Points[#Points+1] = FromWaypoint
else
local GroupPoint = Airplane:GetVec2()
local GroupVelocity = Airplane:GetUnit(1):GetDesc().speedMax
local FromWaypoint = {}
FromWaypoint.x = GroupPoint.x
FromWaypoint.y = GroupPoint.y
FromWaypoint.type = "Turning Point"
FromWaypoint.action = "Turning Point"
FromWaypoint.speed = GroupVelocity
Points[#Points+1] = FromWaypoint
end
-- To point.
local AirbasePointVec2 = Airbase:GetPointVec2()
local ToWaypoint = AirbasePointVec2:WaypointAir(
POINT_VEC3.RoutePointAltType.BARO,
"Land",
"Landing",
Speed or Airplane:GetUnit(1):GetDesc().speedMax
Speed or Airplane:GetSpeedMax()*0.8
)
ToWaypoint["airdromeId"] = Airbase:GetID()
ToWaypoint["speed_locked"] = true,
ToWaypoint["speed_locked"] = true
self:F( ToWaypoint )
Points[#Points+1] = ToWaypoint
-- If self.Airbase~=nil then group is currently at an airbase, where it should be respawned.
if self.Airbase then
-- Second point of the route. First point is done in RespawnAtCurrentAirbase() routine.
Template.route.points[2] = ToWaypoint
-- Respawn group at the current airbase.
Airplane:RespawnAtCurrentAirbase(Template, Takeoff, Uncontrolled)
else
-- From point.
local GroupPoint = Airplane:GetVec2()
local FromWaypoint = {}
FromWaypoint.x = GroupPoint.x
FromWaypoint.y = GroupPoint.y
FromWaypoint.type = "Turning Point"
FromWaypoint.action = "Turning Point"
FromWaypoint.speed = Airplane:GetSpeedMax()*0.8
-- The two route points.
Points[1] = FromWaypoint
Points[2] = ToWaypoint
local PointVec3 = Airplane:GetPointVec3()
Template.x = PointVec3.x
Template.y = PointVec3.z
self:T3( Points )
Template.route.points = Points
--self:Respawn( Template )
local GroupSpawned = Airplane:Respawn(Template)
return GroupSpawned
end
end
end

View File

@ -74,7 +74,7 @@
AI_CARGO_DISPATCHER = {
ClassName = "AI_CARGO_DISPATCHER",
SetCarrier = nil,
SetDeployZones = nil,
DeployZonesSet = nil,
AI_Cargo = {},
PickupCargo = {}
}
@ -90,23 +90,21 @@ AI_CARGO_DISPATCHER.PickupCargo = {}
-- @param #AI_CARGO_DISPATCHER self
-- @param Core.Set#SET_GROUP SetCarrier
-- @param Core.Set#SET_CARGO SetCargo
-- @param Core.Set#SET_ZONE SetDeployZones
-- @return #AI_CARGO_DISPATCHER
-- @usage
--
-- -- Create a new cargo dispatcher
-- SetCarrier = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- SetCarriers = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone )
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo )
--
function AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZones )
function AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo )
local self = BASE:Inherit( self, FSM:New() ) -- #AI_CARGO_DISPATCHER
self.SetCarrier = SetCarrier -- Core.Set#SET_GROUP
self.SetCargo = SetCargo -- Core.Set#SET_CARGO
self.SetDeployZones = SetDeployZones -- Core.Set#SET_ZONE
self:SetStartState( "Idle" )
@ -144,6 +142,58 @@ function AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZones )
end
--- Creates a new AI_CARGO_DISPATCHER object.
-- @param #AI_CARGO_DISPATCHER self
-- @param Core.Set#SET_GROUP SetCarrier
-- @param Core.Set#SET_CARGO SetCargo
-- @param Core.Set#SET_ZONE DeployZonesSet
-- @return #AI_CARGO_DISPATCHER
-- @usage
--
-- -- Create a new cargo dispatcher
-- SetCarriers = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- DeployZonesSet = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, SetDeployZone )
--
function AI_CARGO_DISPATCHER:NewWithZones( SetCarriers, SetCargos, DeployZonesSet )
local self = AI_CARGO_DISPATCHER:New( SetCarriers, SetCargos ) -- #AI_CARGO_DISPATCHER
self.DeployZonesSet = DeployZonesSet
return self
end
--- Creates a new AI_CARGO_DISPATCHER object.
-- @param #AI_CARGO_DISPATCHER self
-- @param Core.Set#SET_GROUP SetCarrier
-- @param Core.Set#SET_CARGO SetCargo
-- @param Core.Set#SET_AIRBASE PickupAirbasesSet
-- @param Core.Set#SET_AIRBASE DeployAirbasesSet
-- @return #AI_CARGO_DISPATCHER
-- @usage
--
-- -- Create a new cargo dispatcher
-- SetCarriers = SET_GROUP:New():FilterPrefixes( "APC" ):FilterStart()
-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- PickupAirbasesSet = SET_AIRBASES:New()
-- DeployAirbasesSet = SET_AIRBASES:New()
-- AICargoDispatcher = AI_CARGO_DISPATCHER:New( SetCarrier, SetCargo, PickupAirbasesSet, DeployAirbasesSet )
--
function AI_CARGO_DISPATCHER:NewWithAirbases( SetCarriers, SetCargos, PickupAirbasesSet, DeployAirbasesSet )
local self = AI_CARGO_DISPATCHER:New( SetCarriers, SetCargos ) -- #AI_CARGO_DISPATCHER
self.DeployAirbasesSet = DeployAirbasesSet
self.PickupAirbasesSet = PickupAirbasesSet
return self
end
--- Set the home zone.
-- When there is nothing anymore to pickup, the carriers will go to a random coordinate in this zone.
-- They will await here new orders.
@ -166,6 +216,31 @@ function AI_CARGO_DISPATCHER:SetHomeZone( HomeZone )
return self
end
--- Set the home airbase. This is for air units, i.e. helicopters and airplanes.
-- When there is nothing anymore to pickup, the carriers will go back to their home base. They will await here new orders.
-- @param #AI_CARGO_DISPATCHER self
-- @param Wrapper.Airbase#AIRBASE HomeBase Airbase where the carriers will go after all pickup assignments are done.
-- @return #AI_CARGO_DISPATCHER self
function AI_CARGO_DISPATCHER:SetHomeBase( HomeBase )
self.HomeBase = HomeBase
return self
end
--- Set the home base.
-- When there is nothing anymore to pickup, the carriers will return to their home airbase. There they will await new orders.
-- @param #AI_CARGO_DISPATCHER self
-- @param Wrapper.Airbase#AIRBASE HomeBase The airbase where the carrier will go to, once they completed all pending assignments.
-- @return #AI_CARGO_DISPATCHER self
function AI_CARGO_DISPATCHER:SetHomeBase( HomeBase )
self.HomeBase = HomeBase
return self
end
--- Sets or randomizes the pickup location for the carrier around the cargo coordinate in a radius defined an outer and optional inner radius.
-- This radius is influencing the location where the carrier will land to pickup the cargo.
@ -328,8 +403,9 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
-- The Pickup sequence ...
-- Check if this Carrier need to go and Pickup something...
self:I( { IsTransporting = AI_Cargo:IsTransporting() } )
if AI_Cargo:IsTransporting() == false then
-- So, if the cargo bay is not full yet with cargo to be loaded ...
self:I( { IsRelocating = AI_Cargo:IsRelocating(), IsTransporting = AI_Cargo:IsTransporting() } )
if AI_Cargo:IsRelocating() == false and AI_Cargo:IsTransporting() == false then
-- ok, so there is a free Carrier
-- now find the first cargo that is Unloaded
@ -338,7 +414,7 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
for CargoName, Cargo in pairs( self.SetCargo:GetSet() ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { Cargo = Cargo:GetName(), UnLoaded = Cargo:IsUnLoaded(), Deployed = Cargo:IsDeployed(), PickupCargo = self.PickupCargo[Carrier] ~= nil } )
if Cargo:IsUnLoaded() and not Cargo:IsDeployed() then
if Cargo:IsUnLoaded() == true and Cargo:IsDeployed() == false then
local CargoCoordinate = Cargo:GetCoordinate()
local CoordinateFree = true
for CarrierPickup, Coordinate in pairs( self.PickupCargo ) do
@ -358,10 +434,20 @@ function AI_CARGO_DISPATCHER:onafterMonitor()
end
end
end
if PickupCargo then
self.CarrierHome[Carrier] = nil
local PickupCoordinate = PickupCargo:GetCoordinate():GetRandomCoordinateInRadius( self.PickupOuterRadius, self.PickupInnerRadius )
if self.PickupAirbasesSet then
-- Find airbase within 2km from the cargo with the set.
local PickupAirbase = self.PickupAirbasesSet:FindAirbaseInRange( PickupCoordinate, 4000 )
if PickupAirbase then
AI_Cargo:Pickup( PickupAirbase, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ) )
end
else
AI_Cargo:Pickup( PickupCoordinate, math.random( self.PickupMinSpeed, self.PickupMaxSpeed ) )
end
break
else
if self.HomeZone then
@ -464,14 +550,23 @@ end
-- @return #AI_CARGO_DISPATCHER
function AI_CARGO_DISPATCHER:OnAfterLoaded( From, Event, To, Carrier, Cargo )
local DeployZone = self.SetDeployZones:GetRandomZone()
if self.DeployZonesSet then
local DeployZone = self.DeployZonesSet:GetRandomZone()
local DeployCoordinate = DeployZone:GetCoordinate():GetRandomCoordinateInRadius( self.DeployOuterRadius, self.DeployInnerRadius )
self.AI_Cargo[Carrier]:Deploy( DeployCoordinate, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) )
end
if self.DeployAirbasesSet then
if self.AI_Cargo[Carrier]:IsTransporting() == true then
local DeployAirbase = self.DeployAirbasesSet:GetRandomAirbase()
self.AI_Cargo[Carrier]:Deploy( DeployAirbase, math.random( self.DeployMinSpeed, self.DeployMaxSpeed ) )
end
end
self.PickupCargo[Carrier] = nil
end

View File

@ -103,7 +103,7 @@ AI_CARGO_DISPATCHER_APC = {
--
function AI_CARGO_DISPATCHER_APC:New( SetAPC, SetCargo, SetDeployZone, CombatRadius )
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAPC, SetCargo, SetDeployZone ) ) -- #AI_CARGO_DISPATCHER_APC
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:NewWithZones( SetAPC, SetCargo, SetDeployZone ) ) -- #AI_CARGO_DISPATCHER_APC
self.CombatRadius = CombatRadius or 500

View File

@ -16,8 +16,8 @@
--- Brings a dynamic cargo handling capability for AI groups.
--
-- Airplanes can be mobilized to intelligently transport infantry and other cargo within the simulation.
-- The AI\_CARGO\_DISPATCHER\_AIRPLANE module uses the @{Cargo} capabilities within the MOOSE framework.
-- CARGO derived objects must be declared within the mission to make the AI\_CARGO\_DISPATCHER\_AIRPLANE object recognize the cargo.
-- The AI_CARGO_DISPATCHER_AIRPLANE module uses the @{Cargo} capabilities within the MOOSE framework.
-- CARGO derived objects must be declared within the mission to make the AI_CARGO_DISPATCHER_AIRPLANE object recognize the cargo.
-- Please consult the @{Cargo} module for more information.
--
--
@ -29,23 +29,33 @@ AI_CARGO_DISPATCHER_AIRPLANE = {
--- Creates a new AI_CARGO_DISPATCHER_AIRPLANE object.
-- @param #AI_CARGO_DISPATCHER_AIRPLANE self
-- @param Core.Set#SET_GROUP SetAirplane
-- @param Core.Set#SET_CARGO SetCargo
-- @param Core.Set#SET_ZONE SetDeployZone
-- @return #AI_CARGO_DISPATCHER_AIRPLANE
-- @param Core.Set#SET_GROUP SetAirplanes Set of cargo transport airplanes.
-- @param Core.Set#SET_CARGO SetCargos Set of cargo, which is supposed to be transported.
-- @param Core.Set#SET_AIRBASE PickupAirbasesSet Set of airbases where the cargo has to be picked up.
-- @param Core.Set#SET_AIRBASE DeployAirbasesSet Set of airbases where the cargo is deployed. Choice for each cargo is random.
-- @return #AI_CARGO_DISPATCHER_AIRPLANE self
-- @usage
--
-- -- Create a new cargo dispatcher
-- SetAirplane = SET_GROUP:New():FilterPrefixes( "Airplane" ):FilterStart()
-- SetCargo = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- SetDeployZone = SET_ZONE:New():FilterPrefixes( "Deploy" ):FilterStart()
-- AICargoDispatcher = AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplane, SetCargo )
-- SetAirplanes = SET_GROUP:New():FilterPrefixes( "Airplane" ):FilterStart()
-- SetCargos = SET_CARGO:New():FilterTypes( "Infantry" ):FilterStart()
-- PickupAirbasesSet = SET_AIRBASE:New()
-- DeployAirbasesSet = SET_AIRBASE:New()
-- AICargoDispatcher = AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplanes, SetCargos, PickupAirbasesSet, DeployAirbasesSet )
--
function AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplane, SetCargo, SetDeployZones )
function AI_CARGO_DISPATCHER_AIRPLANE:New( SetAirplanes, SetCargos, PickupAirbasesSet, DeployAirbasesSet )
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetAirplane, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_AIRPLANE
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:NewWithAirbases( SetAirplanes, SetCargos, PickupAirbasesSet, DeployAirbasesSet ) ) -- #AI_CARGO_DISPATCHER_AIRPLANE
self:SetDeploySpeed( 200, 150 )
self:SetPickupSpeed( 200, 150 )
self:SetPickupRadius( 0, 0 )
self:SetDeployRadius( 0, 0 )
return self
end
function AI_CARGO_DISPATCHER_AIRPLANE:AICargo( Airplane, SetCargo )
return AI_CARGO_AIRPLANE:New( Airplane, SetCargo )
end

View File

@ -102,7 +102,7 @@ AI_CARGO_DISPATCHER_HELICOPTER = {
--
function AI_CARGO_DISPATCHER_HELICOPTER:New( SetHelicopter, SetCargo, SetDeployZones )
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:New( SetHelicopter, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:NewWithZones( SetHelicopter, SetCargo, SetDeployZones ) ) -- #AI_CARGO_DISPATCHER_HELICOPTER
self:SetDeploySpeed( 200, 150 )
self:SetPickupSpeed( 200, 150 )

View File

@ -20,7 +20,8 @@
-- @field #AI_CARGO_HELICOPTER
AI_CARGO_HELICOPTER = {
ClassName = "AI_CARGO_HELICOPTER",
Coordinate = nil -- Core.Point#COORDINATE,
Coordinate = nil, -- Core.Point#COORDINATE,
Helicopter_Cargo = {},
}
AI_CARGO_QUEUE = {}
@ -43,7 +44,7 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
self:AddTransition( "Unloaded", "Pickup", "*" )
self:AddTransition( "Loaded", "Deploy", "*" )
self:AddTransition( "Unloaded", "Load", "Boarding" )
self:AddTransition( { "Unloaded", "Loading" }, "Load", "Boarding" )
self:AddTransition( "Boarding", "Board", "Boarding" )
self:AddTransition( "Boarding", "Loaded", "Loaded" )
self:AddTransition( "Loaded", "Unload", "Unboarding" )
@ -73,17 +74,20 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Pickup Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] Pickup
-- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Pickup Asynchronous Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] __Pickup
-- @param #AI_CARGO_HELICOPTER self
-- @param #number Delay
-- @param #number Delay Delay in seconds.
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h to go to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Deploy Handler OnBefore for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] OnBeforeDeploy
@ -91,7 +95,8 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
-- @param #string From
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
-- @param Core.Point#COORDINATE Coordinate Place at which cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- @return #boolean
--- Deploy Handler OnAfter for AI_CARGO_HELICOPTER
@ -101,17 +106,20 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
-- @param #string Event
-- @param #string To
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Deploy Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] Deploy
-- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
--- Deploy Asynchronous Trigger for AI_CARGO_HELICOPTER
-- @function [parent=#AI_CARGO_HELICOPTER] __Deploy
-- @param #number Delay Delay in seconds.
-- @param #AI_CARGO_HELICOPTER self
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Delay
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
-- We need to capture the Crash events for the helicopters.
@ -137,6 +145,13 @@ function AI_CARGO_HELICOPTER:New( Helicopter, CargoSet )
end
)
for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do
HelicopterUnit:SetCargoBayWeightLimit()
end
self.Relocating = false
self.Transporting = false
self:SetCarrier( Helicopter )
return self
@ -217,7 +232,8 @@ function AI_CARGO_HELICOPTER:onafterLanded( Helicopter, From, Event, To )
if self.RoutePickup == true then
if Helicopter:GetHeight( true ) <= 5 and Helicopter:GetVelocityKMH() < 10 then
self:Load( Helicopter:GetPointVec2() )
--self:Load( Helicopter:GetPointVec2() )
self:Load()
self.RoutePickup = false
self.Relocating = true
end
@ -372,23 +388,28 @@ function AI_CARGO_HELICOPTER:onbeforeLoad( Helicopter, From, Event, To)
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:IsUnLoaded() and not Cargo:IsDeployed() then
if Cargo:IsInLoadRadius( HelicopterUnit:GetCoordinate() ) then
self:F( { "In radius", HelicopterUnit:GetName() } )
local CargoBayFreeWeight = HelicopterUnit:GetCargoBayFreeWeight()
local CargoWeight = Cargo:GetWeight()
self:F({CargoBayFreeWeight=CargoBayFreeWeight})
-- Only when there is space within the bay to load the next cargo item!
if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then
--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
Boarding = true
break
end
end
@ -396,6 +417,7 @@ function AI_CARGO_HELICOPTER:onbeforeLoad( Helicopter, From, Event, To)
end
end
end
end
return Boarding
@ -416,13 +438,65 @@ function AI_CARGO_HELICOPTER:onafterBoard( Helicopter, From, Event, To, Cargo )
if not Cargo:IsLoaded() then
self:__Board( 10, Cargo )
else
self:__Loaded( 1, 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
if Cargo:IsUnLoaded() then
if Cargo:IsInLoadRadius( HelicopterUnit:GetCoordinate() ) then
local CargoBayFreeWeight = HelicopterUnit:GetCargoBayFreeWeight()
local CargoWeight = Cargo:GetWeight()
self:F({CargoBayFreeWeight=CargoBayFreeWeight})
-- Only when there is space within the bay to load the next cargo item!
if CargoBayFreeWeight > CargoWeight then --and CargoBayFreeVolume > CargoVolume then
Cargo:Board( HelicopterUnit, 25 )
self:__Board( 10, Cargo )
self.Helicopter_Cargo[HelicopterUnit] = Cargo
return
end
end
end
end
end
self:__Loaded( 1, Cargo ) -- Will only be executed when no more cargo is boarded.
end
end
end
--- On before Land event.
--- On before Loaded event.
-- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @return #boolean Cargo loaded.
function AI_CARGO_HELICOPTER:onbeforeLoaded( Helicopter, From, Event, To, Cargo )
self:F( { Helicopter, From, Event, To } )
local Loaded = true
if Helicopter and Helicopter:IsAlive() then
for HelicopterUnit, Cargo in pairs( self.Helicopter_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
self:F( { IsLoaded = Cargo:IsLoaded(), IsDestroyed = Cargo:IsDestroyed(), Cargo:GetName(), Helicopter:GetName() } )
if not Cargo:IsLoaded() and not Cargo:IsDestroyed() then
Loaded = false
end
end
end
return Loaded
end
--- On after Loaded event. Check if cargo is loaded.
-- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param #string From From state.
@ -430,26 +504,14 @@ end
-- @param #string To To state.
-- @param Cargo.Cargo#CARGO Cargo Cargo object.
-- @return #boolean Cargo is loaded.
function AI_CARGO_HELICOPTER:onbeforeLoaded( Helicopter, From, Event, To, Cargo )
function AI_CARGO_HELICOPTER:onafterLoaded( Helicopter, From, Event, To, Cargo )
self:F( { Helicopter, From, Event, To, Cargo } )
local Loaded = true
if Helicopter and Helicopter:IsAlive() then
for HelicopterUnit, Cargo in pairs( self.Helicopter_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
self.Transporting = true
end
end
end
return Loaded
end
--- On after Unload event.
-- @param #AI_CARGO_HELICOPTER self
@ -463,12 +525,14 @@ function AI_CARGO_HELICOPTER:onafterUnload( Helicopter, From, Event, To, Deploye
for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do
local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT
for _, Cargo in pairs( HelicopterUnit:GetCargo() ) do
if Cargo:IsLoaded() then
Cargo:UnBoard()
Cargo:SetDeployed( true )
self:__Unboard( 10, Cargo, Deployed )
end
end
end
end
end
@ -487,6 +551,17 @@ function AI_CARGO_HELICOPTER:onafterUnboard( Helicopter, From, Event, To, Cargo,
if not Cargo:IsUnLoaded() then
self:__Unboard( 10, Cargo, Deployed )
else
for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do
local HelicopterUnit = HelicopterUnit -- Wrapper.Unit#UNIT
for _, Cargo in pairs( HelicopterUnit:GetCargo() ) do
if Cargo:IsLoaded() then
Cargo:UnBoard()
Cargo:SetDeployed( true )
self:__Unboard( 10, Cargo, Deployed )
return
end
end
end
self:__Unloaded( 1, Cargo, Deployed )
end
end
@ -511,21 +586,16 @@ function AI_CARGO_HELICOPTER:onbeforeUnloaded( Helicopter, From, Event, To, Carg
if Helicopter and Helicopter:IsAlive() then
for _, HelicopterUnit in pairs( Helicopter:GetUnits() ) do
local CargoCheck = self.Helicopter_Cargo[HelicopterUnit] -- Cargo.Cargo#CARGO
if CargoCheck then
self:F( { CargoCheck:GetName(), IsUnLoaded = CargoCheck:IsUnLoaded() } )
if CargoCheck:IsUnLoaded() == false then
local IsEmpty = HelicopterUnit:IsCargoEmpty()
self:I({ IsEmpty = IsEmpty })
if not IsEmpty then
AllUnloaded = false
break
end
end
end
if AllUnloaded == true then
if Deployed == true then
for HelicopterUnit, Cargo in pairs( self.Helicopter_Cargo ) do
local Cargo = Cargo -- Cargo.Cargo#CARGO
end
self.Helicopter_Cargo = {}
end
self.Helicopter = Helicopter
@ -632,11 +702,11 @@ end
--- On after Deploy event.
-- @param #AI_CARGO_HELICOPTER self
-- @param Wrapper.Group#GROUP Helicopter
-- @param Wrapper.Group#GROUP Helicopter Transport helicopter.
-- @param From
-- @param Event
-- @param To
-- @param Core.Point#COORDINATE Coordinate
-- @param Core.Point#COORDINATE Coordinate Place at which the cargo is deployed.
-- @param #number Speed Speed in km/h to drive to the pickup coordinate. Default is 50% of max possible speed the unit can go.
function AI_CARGO_HELICOPTER:onafterDeploy( Helicopter, From, Event, To, Coordinate, Speed )

View File

@ -779,7 +779,8 @@ do -- CARGO
local Distance = 0
if self:IsUnLoaded() then
Distance = Coordinate:Get2DDistance( self.CargoObject:GetCoordinate() )
local CargoCoordinate = self.CargoObject:GetCoordinate()
Distance = Coordinate:Get2DDistance( CargoCoordinate )
self:T( Distance )
if Distance <= self.LoadRadius then
return true
@ -810,7 +811,7 @@ do -- CARGO
end
--- Check if CargoCarrier is near the Cargo to be Loaded.
--- Check if CargoCarrier is near the coordinate within NearRadius.
-- @param #CARGO self
-- @param Core.Point#COORDINATE Coordinate
-- @param #number NearRadius The radius when the cargo will board the Carrier (to avoid collision).
@ -875,6 +876,13 @@ do -- CARGO
return self.CargoObject:GetCoordinate()
end
--- Get the weight of the cargo.
-- @param #CARGO self
-- @return #number Weight The weight in kg.
function CARGO:GetWeight()
return self.Weight
end
--- Set the weight of the cargo.
-- @param #CARGO self
-- @param #number Weight The weight in kg.
@ -884,6 +892,22 @@ do -- CARGO
return self
end
--- Get the volume of the cargo.
-- @param #CARGO self
-- @return #number Volume The volume in kg.
function CARGO:GetVolume()
return self.Volume
end
--- Set the volume of the cargo.
-- @param #CARGO self
-- @param #number Volume The volume in kg.
-- @return #CARGO
function CARGO:SetVolume( Volume )
self.Volume = Volume
return self
end
--- Send a CC message to a @{Wrapper.Group}.
-- @param #CARGO self
-- @param #string Message
@ -997,13 +1021,27 @@ do -- CARGO_REPRESENTABLE
-- @param #CARGO_REPRESENTABLE self
-- @param #string Type
-- @param #string Name
-- @param #number Weight
-- @param #number LoadRadius (optional)
-- @param #number NearRadius (optional)
-- @return #CARGO_REPRESENTABLE
function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, Weight, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO:New( Type, Name, Weight, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE
self:F( { Type, Name, Weight, LoadRadius, NearRadius } )
function CARGO_REPRESENTABLE:New( CargoObject, Type, Name, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_REPRESENTABLE
self:F( { Type, Name, LoadRadius, NearRadius } )
local Desc = CargoObject:GetDesc()
self:I( { Desc = Desc } )
local Weight = math.random( 80, 120 )
if Desc then
Weight = Desc.massEmpty
end
self:SetWeight( Weight )
-- local Box = CargoUnit:GetBoundingBox()
-- local VolumeUnit = ( Box.max.x - Box.min.x ) * ( Box.max.y - Box.min.y ) * ( Box.max.z - Box.min.z )
-- self:I( { VolumeUnit = VolumeUnit, WeightUnit = WeightUnit } )
--self:SetVolume( VolumeUnit )
return self
end
@ -1203,6 +1241,10 @@ end
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number Speed
-- @param #number BoardDistance
-- @param #number LoadDistance
-- @param #number Angle
function CARGO_PACKAGE:onafterOnBoarded( From, Event, To, CargoCarrier, Speed, BoardDistance, LoadDistance, Angle )
self:F()
@ -1218,6 +1260,7 @@ end
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number Speed
-- @param #number UnLoadDistance
-- @param #number UnBoardDistance
@ -1261,6 +1304,7 @@ end
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number Speed
function CARGO_PACKAGE:onafterUnBoarded( From, Event, To, CargoCarrier, Speed )
self:F()
@ -1304,6 +1348,8 @@ end
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number Speed
-- @param #number Distance
-- @param #number Angle
function CARGO_PACKAGE:onafterUnLoad( From, Event, To, CargoCarrier, Speed, Distance, Angle )

View File

@ -61,8 +61,8 @@ do -- CARGO_GROUP
-- @param #number LoadRadius (optional) Distance in meters until which a cargo is loaded into the carrier. Cargo outside this radius has to be routed by other means to within the radius to be loaded.
-- @param #number NearRadius (optional) Once the units are within this radius of the carrier, they are actually loaded, i.e. disappear from the scene.
-- @return #CARGO_GROUP Cargo group object.
function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius )
local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius ) ) -- #CARGO_GROUP
function CARGO_GROUP:New( CargoGroup, Type, Name, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO_REPORTABLE:New( Type, Name, 0, LoadRadius, NearRadius ) ) -- #CARGO_GROUP
self:F( { Type, Name, LoadRadius } )
self.CargoSet = SET_CARGO:New()
@ -73,6 +73,7 @@ do -- CARGO_GROUP
self:SetDeployed( false )
local WeightGroup = 0
local VolumeGroup = 0
self.CargoGroup:Destroy()
@ -96,10 +97,7 @@ do -- CARGO_GROUP
-- And we register the spawned unit as part of the CargoSet.
local Unit = UNIT:Register( CargoUnitName )
--local WeightUnit = Unit:GetDesc().massEmpty
--WeightGroup = WeightGroup + WeightUnit
local CargoUnit = CARGO_UNIT:New( Unit, Type, CargoUnitName, 10 )
self.CargoSet:Add( CargoUnitName, CargoUnit )
end
-- Then we register the new group in the database
@ -108,8 +106,20 @@ do -- CARGO_GROUP
-- Now we spawn the new group based on the template created.
self.CargoObject = _DATABASE:Spawn( GroupTemplate )
for CargoUnitID, CargoUnit in pairs( self.CargoObject:GetUnits() ) do
local CargoUnitName = CargoUnit:GetName()
local Cargo = CARGO_UNIT:New( CargoUnit, Type, CargoUnitName, LoadRadius, NearRadius )
self.CargoSet:Add( CargoUnitName, Cargo )
WeightGroup = WeightGroup + Cargo:GetWeight()
--VolumeGroup = VolumeGroup + VolumeUnit
end
self:SetWeight( WeightGroup )
self.CargoLimit = 10
self:T( { "Weight Cargo", WeightGroup } )
@ -257,10 +267,11 @@ do -- CARGO_GROUP
--- Enter Boarding State.
-- @param #CARGO_GROUP self
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
--self:F( { CargoCarrier.UnitName, From, Event, To } )
@ -304,10 +315,11 @@ do -- CARGO_GROUP
--- Leave Boarding State.
-- @param #CARGO_GROUP self
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
--self:F( { CargoCarrier.UnitName, From, Event, To } )
@ -359,10 +371,11 @@ do -- CARGO_GROUP
--- Enter UnBoarding State.
-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
self:F( {From, Event, To, ToPointVec2, NearRadius } )
@ -401,10 +414,11 @@ do -- CARGO_GROUP
--- Leave UnBoarding State.
-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
@ -438,10 +452,11 @@ do -- CARGO_GROUP
--- UnBoard Event.
-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius If distance is smaller than this number, cargo is loaded into the carrier.
function CARGO_GROUP:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius, ... )
--self:F( { From, Event, To, ToPointVec2, NearRadius } )
@ -454,10 +469,10 @@ do -- CARGO_GROUP
--- Enter UnLoaded State.
-- @param #CARGO_GROUP self
-- @param Core.Point#POINT_VEC2
-- @param #string Event
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2
function CARGO_GROUP:onenterUnLoaded( From, Event, To, ToPointVec2, ... )
--self:F( { From, Event, To, ToPointVec2 } )
@ -467,7 +482,7 @@ do -- CARGO_GROUP
self.CargoSet:ForEach(
function( Cargo )
--Cargo:UnLoad( ToPointVec2 )
local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(10)
local RandomVec2=ToPointVec2:GetRandomPointVec2InRadius(20, 10)
Cargo:UnLoad( RandomVec2 )
end
)
@ -485,8 +500,6 @@ do -- CARGO_GROUP
-- @return Core.Point#COORDINATE The current Coordinate of the first Cargo of the CargoGroup.
-- @return #nil There is no valid Cargo in the CargoGroup.
function CARGO_GROUP:GetCoordinate()
self:F()
local Cargo = self:GetFirstAlive() -- Cargo.Cargo#CARGO
if Cargo then
@ -592,8 +605,7 @@ do -- CARGO_GROUP
-- @param #CARGO_GROUP self
-- @param Wrapper.Group#GROUP CargoCarrier
-- @param #number NearRadius
-- @return #boolean The Cargo is near to the Carrier.
-- @return #nil The Cargo is not near to the Carrier.
-- @return #boolean The Cargo is near to the Carrier or #nil if the Cargo is not near to the Carrier.
function CARGO_GROUP:IsNear( CargoCarrier, NearRadius )
self:F( {NearRadius = NearRadius } )
@ -621,12 +633,19 @@ do -- CARGO_GROUP
if Cargo then
local Distance = 0
local CargoCoordinate
if Cargo:IsLoaded() then
Distance = Coordinate:Get2DDistance( Cargo.CargoCarrier:GetCoordinate() )
CargoCoordinate = Cargo.CargoCarrier:GetCoordinate()
else
Distance = Coordinate:Get2DDistance( Cargo.CargoObject:GetCoordinate() )
CargoCoordinate = Cargo.CargoObject:GetCoordinate()
end
-- if CargoCoordinate then
Distance = Coordinate:Get2DDistance( CargoCoordinate )
-- else
-- return false
-- end
self:F( { Distance = Distance, LoadRadius = self.LoadRadius } )
if Distance <= self.LoadRadius then
return true

View File

@ -42,9 +42,9 @@ do -- CARGO_UNIT
-- @param #number LoadRadius (optional)
-- @param #number NearRadius (optional)
-- @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:I( { Type, Name, Weight, NearRadius } )
function CARGO_UNIT:New( CargoUnit, Type, Name, LoadRadius, NearRadius )
local self = BASE:Inherit( self, CARGO_REPRESENTABLE:New( CargoUnit, Type, Name, LoadRadius, NearRadius ) ) -- #CARGO_UNIT
self:I( { Type, Name, LoadRadius, NearRadius } )
self:T( CargoUnit )
self.CargoObject = CargoUnit
@ -62,6 +62,7 @@ do -- CARGO_UNIT
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius (optional) Defaut 25 m.
function CARGO_UNIT:onenterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
@ -131,6 +132,7 @@ do -- CARGO_UNIT
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius (optional) Defaut 100 m.
function CARGO_UNIT:onleaveUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
@ -158,6 +160,7 @@ do -- CARGO_UNIT
-- @param #string From
-- @param #string To
-- @param Core.Point#POINT_VEC2 ToPointVec2
-- @param #number NearRadius (optional) Defaut 100 m.
function CARGO_UNIT:onafterUnBoarding( From, Event, To, ToPointVec2, NearRadius )
self:F( { From, Event, To, ToPointVec2, NearRadius } )
@ -223,8 +226,6 @@ do -- CARGO_UNIT
function CARGO_UNIT:onafterBoard( From, Event, To, CargoCarrier, NearRadius, ... )
self:F( { From, Event, To, CargoCarrier, NearRadius } )
local NearRadius = NearRadius or 25
self.CargoInAir = self.CargoObject:InAir()
local Desc = self.CargoObject:GetDesc()
@ -236,6 +237,9 @@ do -- CARGO_UNIT
-- Only move the group to the carrier when the cargo is not in the air
-- (eg. cargo can be on a oil derrick, moving the cargo on the oil derrick will drop the cargo on the sea).
if not self.CargoInAir then
-- If NearRadius is given, then use the given NearRadius, otherwise calculate the NearRadius
-- based upon the Carrier bounding radius, which is calculated from the bounding rectangle on the Y axis.
local NearRadius = CargoCarrier:GetBoundingRadius( NearRadius )
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
self:Load( CargoCarrier, NearRadius, ... )
else
@ -247,8 +251,6 @@ do -- CARGO_UNIT
local Angle = 180
local Distance = 5
NearRadius = NearRadius or 25
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
@ -281,7 +283,7 @@ do -- CARGO_UNIT
-- @param #string From
-- @param #string To
-- @param Wrapper.Client#CLIENT CargoCarrier
-- @param #number NearRadius
-- @param #number NearRadius Default 25 m.
function CARGO_UNIT:onafterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
--self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
@ -299,8 +301,6 @@ do -- CARGO_UNIT
local Angle = 180
local Distance = 5
NearRadius = NearRadius or 25
local CargoCarrierPointVec2 = CargoCarrier:GetPointVec2()
local CargoCarrierHeading = CargoCarrier:GetHeading() -- Get Heading of object in degrees.
local CargoDeployHeading = ( ( CargoCarrierHeading + Angle ) >= 360 ) and ( CargoCarrierHeading + Angle - 360 ) or ( CargoCarrierHeading + Angle )
@ -338,6 +338,7 @@ do -- CARGO_UNIT
-- @param #string From
-- @param #string To
-- @param Wrapper.Unit#UNIT CargoCarrier
-- @param #number NearRadius Default 25 m.
function CARGO_UNIT:onenterBoarding( From, Event, To, CargoCarrier, NearRadius, ... )
--self:F( { From, Event, To, CargoCarrier.UnitName, NearRadius } )
@ -345,8 +346,6 @@ do -- CARGO_UNIT
local Angle = 180
local Distance = 5
local NearRadius = NearRadius or 25
if From == "UnLoaded" or From == "Boarding" then
end

View File

@ -799,7 +799,6 @@ end
-- @param Key The key that is used as a reference of the value. Note that the key can be a #string, but it can also be any other type!
-- @param Value The value to is stored in the object.
-- @return The Value set.
-- @return #nil The Key was not found and thus the Value could not be retrieved.
function BASE:SetState( Object, Key, Value )
local ClassNameAndID = Object:GetClassNameAndID()
@ -816,7 +815,7 @@ end
-- @param #BASE self
-- @param Object The object that holds the Value set by the Key.
-- @param Key The key that is used to retrieve the value. Note that the key can be a #string, but it can also be any other type!
-- @return The Value retrieved.
-- @return The Value retrieved or nil if the Key was not found and thus the Value could not be retrieved.
function BASE:GetState( Object, Key )
local ClassNameAndID = Object:GetClassNameAndID()
@ -829,6 +828,10 @@ function BASE:GetState( Object, Key )
return nil
end
--- Clear the state of an object.
-- @param #BASE self
-- @param Object The object that holds the Value set by the Key.
-- @param StateName The key that is should be cleared.
function BASE:ClearState( Object, StateName )
local ClassNameAndID = Object:GetClassNameAndID()

View File

@ -374,14 +374,15 @@ do -- cargo
-- @return #DATABASE self
function DATABASE:_RegisterCargos()
local Groups = UTILS.DeepCopy( self.GROUPS ) -- This is a very important statement. CARGO_GROUP:New creates a new _DATABASE.GROUP entry, which will confuse the loop. I searched 4 hours on this to find the bug!
for CargoGroupName, CargoGroup in pairs( self.GROUPS ) do
for CargoGroupName, CargoGroup in pairs( Groups ) do
self:I( { Cargo = CargoGroupName } )
if self:IsCargo( CargoGroupName ) then
local CargoInfo = CargoGroupName:match("~CARGO(.*)")
local CargoParam = CargoInfo and CargoInfo:match( "%((.*)%)")
local CargoName1 = CargoGroupName:match("(.*)~CARGO%(.*%)")
local CargoName2 = CargoGroupName:match(".*~CARGO%(.*%)(.*)")
self:E({CargoName1 = CargoName1, CargoName2 = CargoName2 })
local CargoName = CargoName1 .. ( CargoName2 or "" )
local Type = CargoParam and CargoParam:match( "T=([%a%d ]+),?")
local Name = CargoParam and CargoParam:match( "N=([%a%d]+),?") or CargoName
@ -459,7 +460,7 @@ end
function DATABASE:AddGroup( GroupName )
if not self.GROUPS[GroupName] then
self:E( { "Add GROUP:", GroupName } )
self:I( { "Add GROUP:", GroupName } )
self.GROUPS[GroupName] = GROUP:Register( GroupName )
end
@ -471,7 +472,7 @@ end
function DATABASE:AddPlayer( UnitName, PlayerName )
if PlayerName then
self:E( { "Add player for unit:", UnitName, PlayerName } )
self:I( { "Add player for unit:", UnitName, PlayerName } )
self.PLAYERS[PlayerName] = UnitName
self.PLAYERUNITS[PlayerName] = self:FindUnit( UnitName )
self.PLAYERSJOINED[PlayerName] = PlayerName
@ -483,7 +484,7 @@ end
function DATABASE:DeletePlayer( UnitName, PlayerName )
if PlayerName then
self:E( { "Clean player:", PlayerName } )
self:I( { "Clean player:", PlayerName } )
self.PLAYERS[PlayerName] = nil
self.PLAYERUNITS[PlayerName] = nil
end
@ -750,7 +751,7 @@ function DATABASE:_RegisterPlayers()
local UnitName = UnitData:getName()
local PlayerName = UnitData:getPlayerName()
if not self.PLAYERS[PlayerName] then
self:E( { "Add player for unit:", UnitName, PlayerName } )
self:I( { "Add player for unit:", UnitName, PlayerName } )
self:AddPlayer( UnitName, PlayerName )
end
end
@ -773,13 +774,13 @@ function DATABASE:_RegisterGroupsAndUnits()
if DCSGroup:isExist() then
local DCSGroupName = DCSGroup:getName()
self:E( { "Register Group:", DCSGroupName } )
self:I( { "Register Group:", DCSGroupName } )
self:AddGroup( DCSGroupName )
for DCSUnitId, DCSUnit in pairs( DCSGroup:getUnits() ) do
local DCSUnitName = DCSUnit:getName()
self:E( { "Register Unit:", DCSUnitName } )
self:I( { "Register Unit:", DCSUnitName } )
self:AddUnit( DCSUnitName )
end
else
@ -789,6 +790,11 @@ function DATABASE:_RegisterGroupsAndUnits()
end
end
self:I("Groups:")
for GroupName, Group in pairs( self.GROUPS ) do
self:I( { "Group:", GroupName } )
end
return self
end
@ -798,7 +804,7 @@ end
function DATABASE:_RegisterClients()
for ClientName, ClientTemplate in pairs( self.Templates.ClientsByName ) do
self:E( { "Register Client:", ClientName } )
self:I( { "Register Client:", ClientName } )
self:AddClient( ClientName )
end
@ -809,14 +815,14 @@ end
function DATABASE:_RegisterStatics()
local CoalitionsData = { GroupsRed = coalition.getStaticObjects( coalition.side.RED ), GroupsBlue = coalition.getStaticObjects( coalition.side.BLUE ) }
self:E( { Statics = CoalitionsData } )
self:I( { Statics = CoalitionsData } )
for CoalitionId, CoalitionData in pairs( CoalitionsData ) do
for DCSStaticId, DCSStatic in pairs( CoalitionData ) do
if DCSStatic:isExist() then
local DCSStaticName = DCSStatic:getName()
self:E( { "Register Static:", DCSStaticName } )
self:I( { "Register Static:", DCSStaticName } )
self:AddStatic( DCSStaticName )
else
self:E( { "Static does not exist: ", DCSStatic } )
@ -836,7 +842,7 @@ function DATABASE:_RegisterAirbases()
local DCSAirbaseName = DCSAirbase:getName()
self:E( { "Register Airbase:", DCSAirbaseName, DCSAirbase:getID() } )
self:I( { "Register Airbase:", DCSAirbaseName, DCSAirbase:getID() } )
self:AddAirbase( DCSAirbaseName )
end
end
@ -866,9 +872,8 @@ function DATABASE:_EventOnBirth( Event )
Event.IniUnit = self:FindUnit( Event.IniDCSUnitName )
Event.IniGroup = self:FindGroup( Event.IniDCSGroupName )
local PlayerName = Event.IniUnit:GetPlayerName()
self:E( { "PlayerName:", PlayerName } )
if PlayerName then
self:E( { "Player Joined:", PlayerName } )
self:I( { "Player Joined:", PlayerName } )
if not self.PLAYERS[PlayerName] then
self:AddPlayer( Event.IniUnitName, PlayerName )
end
@ -937,7 +942,7 @@ function DATABASE:_EventOnPlayerLeaveUnit( Event )
if Event.IniObjectCategory == 1 then
local PlayerName = Event.IniUnit:GetPlayerName()
if PlayerName and self.PLAYERS[PlayerName] then
self:E( { "Player Left:", PlayerName } )
self:I( { "Player Left:", PlayerName } )
local Settings = SETTINGS:Set( PlayerName )
Settings:RemovePlayerMenu( Event.IniUnit )
self:DeletePlayer( Event.IniUnit, PlayerName )

View File

@ -719,7 +719,7 @@ do -- Event Creation
-- @param #EVENT self
-- @param AI.AI_Cargo#AI_CARGO Cargo The Cargo created.
function EVENT:CreateEventNewCargo( Cargo )
self:F( { Cargo } )
self:I( { Cargo } )
local Event = {
id = EVENTS.NewCargo,

View File

@ -308,7 +308,7 @@ end
--- Sends a MESSAGE to all players.
-- @param #MESSAGE self
-- @param Core.Settings#Settings (Optional) Settings for message display
-- @param Core.Settings#Settings Settings (Optional) Settings for message display.
-- @return #MESSAGE
-- @usage
-- -- Send a message created to all players.

View File

@ -1096,6 +1096,37 @@ do -- COORDINATE
return RoutePoint
end
--- Gets the nearest airbase with respect to the current coordinates.
-- @param #COORDINATE self
-- @param #number AirbaseCategory Category of the airbase.
-- @return Wrapper.Airbase#AIRBASE Closest Airbase to the given coordinate.
-- @return #number Distance to the closest airbase in meters.
function COORDINATE:GetClosestAirbase(AirbaseCategory)
local airbases=AIRBASE.GetAllAirbases()
local closest=nil
local distmin=nil
-- Loop over all airbases.
for _,_airbase in pairs(airbases) do
local airbase=_airbase --Wrapper.Airbase#AIRBASE
local category=airbase:GetDesc().category
if AirbaseCategory and AirbaseCategory==category or AirbaseCategory==nil then
local dist=self:Get2DDistance(airbase:GetCoordinate())
if closest==nil then
distmin=dist
closest=airbase
else
if dist<distmin then
distmin=dist
closest=airbase
end
end
end
end
return closest,distmin
end
--- Gets the nearest parking spot.
-- @param #COORDINATE self
-- @param Wrapper.Airbase#AIRBASE airbase (Optional) Search only parking spots at this airbase.
@ -1183,18 +1214,26 @@ do -- COORDINATE
return COORDINATE:NewFromVec2(vec2)
end
--- Returns a table of coordinates to a destination using only roads.
--- Returns a table of coordinates to a destination using only roads or railroads.
-- The first point is the closest point on road of the given coordinate.
-- By default, the last point is the closest point on road of the ToCoord. Hence, the coordinate itself and the final ToCoord are not necessarily included in the path.
-- @param #COORDINATE self
-- @param #COORDINATE ToCoord Coordinate of destination.
-- @param #boolean IncludeEndpoints (Optional) Include the coordinate itself and the ToCoordinate in the path.
-- @param #boolean Railroad (Optional) If true, path on railroad is returned. Default false.
-- @return #table Table of coordinates on road. If no path on road can be found, nil is returned or just the endpoints.
-- @return #number The length of the total path.
function COORDINATE:GetPathOnRoad(ToCoord, IncludeEndpoints)
function COORDINATE:GetPathOnRoad(ToCoord, IncludeEndpoints, Railroad)
-- Set road type.
local RoadType="roads"
if Railroad==true then
RoadType="railroads"
end
-- DCS API function returning a table of vec2.
local path = land.findPathOnRoads("roads", self.x, self.z, ToCoord.x, ToCoord.z)
local path = land.findPathOnRoads(RoadType, self.x, self.z, ToCoord.x, ToCoord.z)
-- Array holding the path coordinates.
local Path={}

View File

@ -809,6 +809,16 @@ function SET_GROUP:GetAliveSet()
return AliveSet.Set or {}
end
--- Add a GROUP to SET_GROUP.
-- @param Core.Set#SET_GROUP self
-- @param Wrapper.Group#GROUP group The group which should be added to the set.
-- @return self
function SET_GROUP:AddGroup( group )
self:Add( group:GetName(), group )
return self
end
--- Add GROUP(s) to SET_GROUP.
-- @param Core.Set#SET_GROUP self
@ -3968,6 +3978,17 @@ function SET_AIRBASE:New()
return self
end
--- Add an AIRBASE object to SET_AIRBASE.
-- @param Core.Set#SET_AIRBASE self
-- @param Wrapper.Airbase#AIRBASE airbase Airbase that should be added to the set.
-- @return self
function SET_AIRBASE:AddAirbase( airbase )
self:Add( airbase:GetName(), airbase )
return self
end
--- Add AIRBASEs to SET_AIRBASE.
-- @param Core.Set#SET_AIRBASE self
-- @param #string AddAirbaseNames A single name or an array of AIRBASE names.
@ -4010,6 +4031,45 @@ function SET_AIRBASE:FindAirbase( AirbaseName )
end
--- Finds an Airbase in range of a coordinate.
-- @param #SET_AIRBASE self
-- @param Core.Point#COORDINATE Coordinate
-- @param #number Range
-- @return Wrapper.Airbase#AIRBASE The found Airbase.
function SET_AIRBASE:FindAirbaseInRange( Coordinate, Range )
local AirbaseFound = nil
for AirbaseName, AirbaseObject in pairs( self.Set ) do
local AirbaseCoordinate = AirbaseObject:GetCoordinate()
local Distance = Coordinate:Get2DDistance( AirbaseCoordinate )
self:F({Distance=Distance})
if Distance <= Range then
AirbaseFound = AirbaseObject
break
end
end
return AirbaseFound
end
--- Finds a random Airbase in the set.
-- @param #SET_AIRBASE self
-- @return Wrapper.Airbase#AIRBASE The found Airbase.
function SET_AIRBASE:GetRandomAirbase()
local RandomAirbase = self:GetRandom()
self:F( { RandomAirbase = RandomAirbase:GetName() } )
return RandomAirbase
end
--- Builds a set of airbases of coalitions.
-- Possible current coalitions are red, blue and neutral.

View File

@ -81,11 +81,11 @@ do -- world
--- Searches a defined volume of 3d space for the specified objects within it and then can run function on each returned object. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_searchObjects).
-- @function [parent=#world] searchObjects
-- @param #DCS.Object.Category objectcategory Category (can be a table) of objects to search.
-- @param #DCS word.VolumeType volume Shape of the search area/volume.
-- @param #ObjectSeachHandler handler A function that handles the search.
-- @param DCS#Object.Category objectcategory Category (can be a table) of objects to search.
-- @param DCS#word.VolumeType volume Shape of the search area/volume.
-- @param ObjectSeachHandler handler A function that handles the search.
-- @param #table any Additional data.
-- @return #DCS.unit
-- @return DCS#Unit
--- Returns a table of mark panels indexed numerically that are present within the mission. See [hoggit](https://wiki.hoggitworld.com/view/DCS_func_getMarkPanels)
-- @function [parent=#world] getMarkPanels
@ -959,6 +959,7 @@ do -- Group
-- @field HELICOPTER
-- @field GROUND
-- @field SHIP
-- @field TRAIN
-- Static Functions

View File

@ -515,6 +515,7 @@ do -- DETECTION_BASE
for DetectionGroupID, DetectionGroupData in pairs( self.DetectionSetGroup:GetSet() ) do
--self:F( { DetectionGroupData } )
self:F( {"FF", DetectionGroupData } )
self:__DetectionGroup( DetectDelay, DetectionGroupData, DetectionTimeStamp ) -- Process each detection asynchronously.
self.DetectionCount = self.DetectionCount + 1
DetectDelay = DetectDelay + 1
@ -1877,7 +1878,7 @@ do -- DETECTION_UNITS
-- @param #DETECTION_UNITS self
-- @return #DETECTION_UNITS self
function DETECTION_UNITS:CreateDetectionItems()
env.info("FF createdetectionitmes")
-- Loop the current detected items, and check if each object still exists and is detected.
for DetectedItemKey, DetectedItem in pairs( self.DetectedItems ) do

View File

@ -1,172 +0,0 @@
--- **Functional** - (R2.4) JTAC
--
-- ===
--
-- JTAC mimic
--
-- ## Features:
--
-- * Feature 1
-- * Feature 2
--
-- ====
--
-- # Demo Missions
--
-- ### [MOOSE - ALL Demo Missions](https://github.com/FlightControl-Master/MOOSE_MISSIONS)
--
-- ====
--
-- # YouTube Channel
--
-- ### [MOOSE YouTube Channel](https://www.youtube.com/channel/UCjrA9j5LQoWsG4SpS8i79Qg)
--
-- ===
--
-- ### Author: **[funkyfranky](https://forums.eagle.ru/member.php?u=115026)**
--
-- ### Contributions: [FlightControl](https://forums.eagle.ru/member.php?u=89536)
--
-- ====
-- @module Functional.Jtac
-- @image JTAC.JPG
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- JTAC class
-- @type JTAC
-- @field #string ClassName Name of the class.
--- Easy assignment of JTAC.
--
-- A new ARTY object can be created with the @{#ARTY.New}(*group*) contructor.
-- The parameter *group* has to be a MOOSE Group object and defines ARTY group.
--
-- The ARTY FSM process can be started by the @{#ARTY.Start}() command.
--
-- ## The ARTY Process
--
-- ![Process](..\Presentations\ARTY\ARTY_Process.png)
--
--
--
-- @field #JTAC
JTAC={
ClassName="JTAC",
Debug=false,
}
--- Some ID to identify who we are in output of the DCS.log file.
-- @field #string id
JTAC.id="JTAC | "
--- Arty script version.
-- @field #string version
JTAC.version="0.0.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list:
-- TODO: a lot.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Creates a new JTAC object.
-- @param #JTAC self
-- @param Wrapper.Group#GROUP group The GROUP object for which artillery tasks should be assigned.
-- @param alias (Optional) Alias name the group will be calling itself when sending messages. Default is the group name.
-- @return #JTAC JTAC object or nil if group does not exist or is not a ground or naval group.
function JTAC:New(group, alias)
BASE:F2(group)
-- Inherits from FSM_CONTROLLABLE
local self=BASE:Inherit(self, FSM_CONTROLLABLE:New()) -- #JTAC
-- Check that group is present.
if group then
self:T(JTAC.id..string.format("JTAC script version %s. Added group %s.", JTAC.version, group:GetName()))
else
self:E(JTAC.id.."ERROR: Requested JTAC group does not exist! (Has to be a MOOSE group.)")
return nil
end
-- Set the controllable for the FSM.
self:SetControllable(group)
---------------
-- Transitions:
---------------
-- Entry.
self:AddTransition("*", "Start", "Ready")
self:AddTransition("Ready", "LaserOn", "Lasing")
self:AddTransition("Lasing", "Lasing", "Lasing")
self:AddTransition("Lasing", "LaserOff", "Ready")
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Start Event
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- After "Start" event.
-- @param #JTAC self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function JTAC:onafterStart(Controllable, From, Event, To)
--self:_EventFromTo("onafterStart", Event, From, To)
-- Debug output.
local text=string.format("Started JTAC version %s for group %s.", JTAC.version, Controllable:GetName())
self:E(JTAC.id..text)
MESSAGE:New(text, 5):ToAllIf(self.Debug)
end
--- After "LaserOn" event.
-- @param #JTAC self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Unit#UNIT Target Target that should be lased.
function JTAC:onafterLaserOn(Controllable, From, Event, To, Target)
--self:_EventFromTo("onafterStart", Event, From, To)
-- Debug output.
local text=string.format("JTAC %s lasing target %s.", Controllable:GetName(), Target:GetName())
self:E(JTAC.id..text)
MESSAGE:New(text, 5):ToAllIf(self.Debug)
-- Start lasing.
Controllable:LaseUnit(Target, self.LaserCode, self.Duration)
end
--- After "LaserOff" event.
-- @param #JTAC self
-- @param Wrapper.Controllable#CONTROLLABLE Controllable Controllable of the group.
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function JTAC:onafterLaserOff(Controllable, From, Event, To)
--self:_EventFromTo("onafterStart", Event, From, To)
-- Debug output.
local text=string.format("JTAC %s stoped lasing.", Controllable:GetName())
self:E(JTAC.id..text)
MESSAGE:New(text, 5):ToAllIf(self.Debug)
-- Turn of laser.
Controllable:LaseOff()
end

View File

@ -219,6 +219,44 @@
-- Hence, the default flight plan for a RAT aircraft will be: Fly from airport A to B, get respawned at C and fly to D, get respawned at E and fly to F, ...
-- This ensures that you always have a constant number of AI aircraft on your map.
--
-- ## Parking Problems
--
-- One big issue in DCS is that not all aircraft can be spawned on every airport or airbase. In particular, bigger aircraft might not have a valid parking spot at smaller airports and
-- airstripes. This can lead to multiple problems in DCS.
--
-- * Landing: When an aircraft tries to land at an airport where it does not have a valid parking spot, it is immidiately despawned the moment its wheels touch the runway, i.e.
-- when a landing event is triggered. This leads to the loss of the RAT aircraft. On possible way to circumvent the this problem is to let another RAT aircraft spawn at landing
-- and not when it shuts down its engines. See the @{RAT.RespawnAfterLanding}() function.
-- * Spawning: When a big aircraft is dynamically spawned on a small airbase a few things can go wrong. For example, it could be spawned at a parking spot with a shelter.
-- Or it could be damaged by a scenery object when it is taxiing out to the runway, or it could overlap with other aircraft on parking spots near by.
--
-- You can check yourself if an aircraft has a valid parking spot at an airbase by dragging its group on the airport in the mission editor and set it to start from ramp.
-- If it stays at the airport, it has a valid parking spot, if it jumps to another airport, it does not have a valid parking spot on that airbase.
--
-- ### Setting the Terminal Type
-- Each parking spot has a specific type depending on its size or if a helicopter spot or a shelter etc. The classification is not perfect but it is the best we have.
-- If you encounter problems described above, you can request a specific terminal type for the RAT aircraft. This can be done by the @{#RAT.SetTerminalType}(*terminaltype*)
-- function. The parameter *terminaltype* can be set as follows
--
-- * AIRBASE.TerminalType.HelicopterOnly: Special spots for Helicopers.
-- * AIRBASE.TerminalType.Shelter: Hardened Air Shelter. Currently only on Caucaus map.
-- * AIRBASE.TerminalType.OpenMed: Open/Shelter air airplane only.
-- * AIRBASE.TerminalType.OpenBig: Open air spawn points. Generally larger but does not guarantee large aircraft are capable of spawning there.
-- * AIRBASE.TerminalType.OpenMedOrBig: Combines OpenMed and OpenBig spots.
-- * AIRBASE.TerminalType.HelicopterUnsable: Combines HelicopterOnly, OpenMed and OpenBig.
-- * AIRBASE.TerminalType.FighterAircraft: Combines Shelter, OpenMed and OpenBig spots. So effectively all spots usable by fixed wing aircraft.
--
-- So for example
-- c17=RAT:New("C-17")
-- c17:SetTerminalType(AIRBASE.TerminalType.OpenBig)
-- c17:Spawn(5)
--
-- This would randomly spawn five C-17s but only on airports which have big open air parking spots. Note that also only destination airports are allowed
-- which do have this type of parking spot. This should ensure that the aircraft is able to land at the destination without beeing despawned immidiately.
--
-- Also, the aircraft are spawned only on the requested parking spot types and not on any other type. If no parking spot of this type is availabe at the
-- moment of spawning, the group is automatically spawned in air above the selected airport.
--
-- ## Examples
--
-- Here are a few examples, how you can modify the default settings of RAT class objects.
@ -511,7 +549,7 @@ RAT.id="RAT | "
--- RAT version.
-- @list version
RAT.version={
version = "2.3.2",
version = "2.3.3",
print = true,
}
@ -983,11 +1021,11 @@ function RAT:SetCoalitionAircraft(color)
end
--- Set country of RAT group.
-- See https://wiki.hoggitworld.com/view/DCS_enum_country
-- See [DCS_enum_country](https://wiki.hoggitworld.com/view/DCS_enum_country).
--
-- This overrules the coalition settings. So if you want your group to be of a specific coalition, you have to set a country that is part of that coalition.
-- @param #RAT self
-- @param #DCS.country.id id DCS country enumerator ID. For example country.id.USA or country.id.RUSSIA.
-- @param DCS#country.id id DCS country enumerator ID. For example country.id.USA or country.id.RUSSIA.
-- @return #RAT RAT self object.
function RAT:SetCountry(id)
self:F2(id)
@ -995,10 +1033,17 @@ function RAT:SetCountry(id)
return self
end
--- Set the terminal type the aircraft use when spawning at an airbase. Cf. https://wiki.hoggitworld.com/view/DCS_func_getParking
--- Set the terminal type the aircraft use when spawning at an airbase. See [DCS_func_getParking](https://wiki.hoggitworld.com/view/DCS_func_getParking).
-- Note that some additional terminal types have been introduced. Check @{Wrapper.Airbase#AIRBASE} class for details.
-- Also note that only airports which have this kind of terminal are possible departures and/or destinations.
-- @param #RAT self
-- @param Wrapper.Airbase#AIRBASE.TerminalType termtype Type of terminal. Use enumerator AIRBASE.TerminalType.XXX.
-- @return #RAT RAT self object.
--
-- @usage
-- c17=RAT:New("C-17 BIG Plane")
-- c17:SetTerminalType(AIRBASE.TerminalType.OpenBig) -- Only very big parking spots are used.
-- c17:Spawn(5)
function RAT:SetTerminalType(termtype)
self:F2(termtype)
self.termtype=termtype
@ -3010,16 +3055,29 @@ function RAT:_PickDeparture(takeoff)
if self.random_departure then
-- Airports of friendly coalitions.
for _,airport in pairs(self.airports) do
for _,_airport in pairs(self.airports) do
local airport=_airport --Wrapper.Airbase#AIRBASE
local name=airport:GetName()
if not self:_Excluded(name) then
if takeoff==RAT.wp.air then
table.insert(departures, airport:GetZone()) -- insert zone object.
else
-- Check if airbase has the right terminals.
local nspots=1
if self.termtype~=nil then
nspots=airport:GetParkingSpotsNumber(self.termtype)
end
if nspots>0 then
table.insert(departures, airport) -- insert airport object.
end
end
end
end
@ -3034,6 +3092,14 @@ function RAT:_PickDeparture(takeoff)
dep=AIRBASE:FindByName(name):GetZone()
else
dep=AIRBASE:FindByName(name)
-- Check if the airport has a valid parking spot
if self.termtype~=nil and dep~=nil then
local _dep=dep --Wrapper.Airbase#AIRBASE
local nspots=_dep:GetParkingSpotsNumber(self.termtype)
if nspots==0 then
dep=nil
end
end
end
elseif self:_ZoneExists(name) then
if takeoff==RAT.wp.air then
@ -3098,7 +3164,8 @@ function RAT:_PickDestination(departure, q, minrange, maxrange, random, landing)
if random then
-- Airports of friendly coalitions.
for _,airport in pairs(self.airports) do
for _,_airport in pairs(self.airports) do
local airport=_airport --Wrapper.Airbase#AIRBASE
local name=airport:GetName()
if self:_IsFriendly(name) and not self:_Excluded(name) and name~=departure:GetName() then
@ -3110,11 +3177,18 @@ function RAT:_PickDestination(departure, q, minrange, maxrange, random, landing)
if landing==RAT.wp.air then
table.insert(destinations, airport:GetZone()) -- insert zone object.
else
-- Check if the requested terminal type is available.
local nspot=1
if self.termtype then
nspot=airport:GetParkingSpotsNumber(self.termtype)
end
if nspot>0 then
table.insert(destinations, airport) -- insert airport object.
end
end
end
end
end
else
@ -3130,6 +3204,14 @@ function RAT:_PickDestination(departure, q, minrange, maxrange, random, landing)
dest=AIRBASE:FindByName(name):GetZone()
else
dest=AIRBASE:FindByName(name)
-- Check if the requested terminal type is available.
local nspot=1
if self.termtype then
nspot=dest:GetParkingSpotsNumber(self.termtype)
end
if nspot==0 then
dest=nil
end
end
elseif self:_ZoneExists(name) then
if landing==RAT.wp.air then
@ -3287,16 +3369,31 @@ function RAT:_GetAirportsOfMap()
end
end
--- Get all "friendly" airports of the current map.
--- Get all "friendly" airports of the current map. Fills the self.airports{} table.
-- @param #RAT self
function RAT:_GetAirportsOfCoalition()
for _,coalition in pairs(self.ctable) do
for _,airport in pairs(self.airports_map) do
for _,_airport in pairs(self.airports_map) do
local airport=_airport --Wrapper.Airbase#AIRBASE
local category=airport:GetDesc().category
if airport:GetCoalition()==coalition then
-- Planes cannot land on FARPs.
local condition1=self.category==RAT.cat.plane and airport:GetTypeName()=="FARP"
--local condition1=self.category==RAT.cat.plane and airport:GetTypeName()=="FARP"
local condition1=self.category==RAT.cat.plane and category==Airbase.Category.HELIPAD
-- Planes cannot land on ships.
local condition2=self.category==RAT.cat.plane and airport:GetCategory()==1
--local condition2=self.category==RAT.cat.plane and airport:GetCategory()==1
local condition2=self.category==RAT.cat.plane and category==Airbase.Category.SHIP
-- Check that airport has the requested terminal types.
-- NOT good here because we would also not allow any airport zones!
--[[
local nspots=1
if self.termtype then
nspots=airport:GetParkingSpotsNumber(self.termtype)
end
local condition3 = nspots==0
]]
if not (condition1 or condition2) then
table.insert(self.airports, airport)
end
@ -3305,8 +3402,8 @@ function RAT:_GetAirportsOfCoalition()
end
if #self.airports==0 then
local text="ERROR! No possible departure/destination airports found."
MESSAGE:New(text, 30):ToAll()
local text=string.format("No possible departure/destination airports found for RAT %s.", tostring(self.alias))
MESSAGE:New(text, 10):ToAll()
self:E(RAT.id..text)
end
end
@ -5254,7 +5351,7 @@ function RAT:_ModifySpawnTemplate(waypoints, livery, spawnplace, departure, take
if spawnonground then
-- Shíps and FARPS seem to have a build in queue.
-- Sh<EFBFBD>ps and FARPS seem to have a build in queue.
if spawnonship or spawnonfarp or spawnonrunway or automatic then
self:T(RAT.id..string.format("RAT group %s spawning at farp, ship or runway %s.", self.alias, departure:GetName()))

View File

@ -68,6 +68,8 @@
-- @field #number dtBombtrack Time step [sec] used for tracking released bomb/rocket positions. Default 0.005 seconds.
-- @field #number BombtrackThreshold Bombs/rockets/missiles are only tracked if player-range distance is smaller than this threashold [m]. Default 25000 m.
-- @field #number Tmsg Time [sec] messages to players are displayed. Default 30 sec.
-- @field #string examinergroupname Name of the examiner group which should get all messages.
-- @field #boolean examinerexclusive If true, only the examiner gets messages. If false, clients and examiner get messages.
-- @field #number strafemaxalt Maximum altitude above ground for registering for a strafe run. Default is 914 m = 3000 ft.
-- @field #number ndisplayresult Number of (player) results that a displayed. Default is 10.
-- @field Utilities.Utils#SMOKECOLOR BombSmokeColor Color id used for smoking bomb targets.
@ -234,6 +236,8 @@ RANGE={
dtBombtrack=0.005,
BombtrackThreshold=25000,
Tmsg=30,
examinergroupname=nil,
examinerexclusive=nil,
strafemaxalt=914,
ndisplayresult=10,
BombSmokeColor=SMOKECOLOR.Red,
@ -279,8 +283,8 @@ RANGE.MenuF10={}
RANGE.id="RANGE | "
--- Range script version.
-- @field #number version
RANGE.version="1.2.0"
-- @field #string version
RANGE.version="1.2.1"
--TODO list:
--TODO: Add custom weapons, which can be specified by the user.
@ -434,6 +438,15 @@ function RANGE:SetMessageTimeDuration(time)
self.Tmsg=time or RANGE.Defaults.Tmsg
end
--- Set messages to examiner. The examiner will receive messages from all clients.
-- @param #RANGE self
-- @param #string examinergroupname Name of the group of the examiner.
-- @param #boolean exclusively If true, messages are send exclusively to the examiner, i.e. not to the clients.
function RANGE:SetMessageToExaminer(examinergroupname, exclusively)
self.examinergroupname=examinergroupname
self.examinerexclusive=exclusively
end
--- Set max number of player results that are displayed.
-- @param #RANGE self
-- @param #number nmax Number of results. Default is 10.
@ -2119,7 +2132,7 @@ function RANGE:_DisplayMessageToGroup(_unit, _text, _time, _clear)
-- Group ID.
local _gid=_unit:GetGroup():GetID()
if _gid then
if _gid and not self.examinerexclusive then
if _clear == true then
trigger.action.outTextForGroup(_gid, _text, _time, _clear)
else
@ -2127,6 +2140,17 @@ function RANGE:_DisplayMessageToGroup(_unit, _text, _time, _clear)
end
end
if self.examinergroupname~=nil then
local _examinerid=GROUP:FindByName(self.examinergroupname):GetID()
if _examinerid then
if _clear == true then
trigger.action.outTextForGroup(_examinerid, _text, _time, _clear)
else
trigger.action.outTextForGroup(_examinerid, _text, _time)
end
end
end
end
--- Toggle status of smoking bomb impact points.

File diff suppressed because it is too large Load Diff

View File

@ -589,6 +589,12 @@ do -- TASK_CARGO
Fsm:AddTransition( "Rejected", "Reject", "Aborted" )
Fsm:AddTransition( "Failed", "Fail", "Failed" )
for _, Group in pairs( SetGroup:GetSet() ) do
for __, Unit in pairs( Group:GetUnits() ) do
local Unit = Unit -- Wrapper.Unit#UNIT
Unit:SetCargoBayWeightLimit()
end
end
---- @param #FSM_PROCESS self
-- @param Wrapper.Unit#UNIT TaskUnit
@ -610,7 +616,6 @@ do -- TASK_CARGO
local TaskUnitName = TaskUnit:GetName()
local MenuTime = Task:InitTaskControlMenu( TaskUnit )
local MenuControl = Task:GetTaskControlMenu( TaskUnit )
local CargoItemCount = TaskUnit:CargoItemCount()
Task.SetCargo:ForEachCargo(
@ -635,7 +640,13 @@ do -- TASK_CARGO
local TaskGroup = TaskUnit:GetGroup()
if Cargo:IsUnLoaded() then
if CargoItemCount < 1 then
local CargoBayFreeWeight = TaskUnit:GetCargoBayFreeWeight()
local CargoWeight = Cargo:GetWeight()
self:F({CargoBayFreeWeight=CargoBayFreeWeight})
-- Only when there is space within the bay to load the next cargo item!
if CargoBayFreeWeight > CargoWeight then
if Cargo:IsInReportRadius( TaskUnit:GetPointVec2() ) then
local NotInDeployZones = true
for DeployZoneName, DeployZone in pairs( Task.DeployZones ) do

View File

@ -265,14 +265,14 @@ AIRBASE.PersianGulf = {
--
-- Supported types are:
--
-- * AIRBASE.TerminalType.Runway: Valid spawn points on runway.
-- * AIRBASE.TerminalType.HelicopterOnly: Special spots for Helicopers.
-- * AIRBASE.TerminalType.Shelter: Hardened Air Shelter. Currently only on Caucaus map.
-- * AIRBASE.TerminalType.OpenMed: Open/Shelter air airplane only.
-- * AIRBASE.TerminalType.OpenBig: Open air spawn points. Generally larger but does not guarantee large aircraft are capable of spawning there.
-- * AIRBASE.TerminalType.OpenMedOrBig: Combines OpenMed and OpenBig spots.
-- * AIRBASE.TerminalType.HelicopterUnsable: Combines HelicopterOnly, OpenMed and OpenBig.
-- * AIRBASE.TerminalType.FighterAircraft: Combines Shelter. OpenMed and OpenBig spots. So effectively all spots usable by fixed wing aircraft.
-- * AIRBASE.TerminalType.Runway = 16: Valid spawn points on runway.
-- * AIRBASE.TerminalType.HelicopterOnly = 40: Special spots for Helicopers.
-- * AIRBASE.TerminalType.Shelter = 68: Hardened Air Shelter. Currently only on Caucaus map.
-- * AIRBASE.TerminalType.OpenMed = 72: Open/Shelter air airplane only.
-- * AIRBASE.TerminalType.OpenBig = 104: Open air spawn points. Generally larger but does not guarantee large aircraft are capable of spawning there.
-- * AIRBASE.TerminalType.OpenMedOrBig = 176: Combines OpenMed and OpenBig spots.
-- * AIRBASE.TerminalType.HelicopterUnsable = 216: Combines HelicopterOnly, OpenMed and OpenBig.
-- * AIRBASE.TerminalType.FighterAircraft = 244: Combines Shelter. OpenMed and OpenBig spots. So effectively all spots usable by fixed wing aircraft.
-- @field TerminalType
AIRBASE.TerminalType = {
Runway=16,
@ -349,7 +349,7 @@ function AIRBASE.GetAllAirbases(coalition)
local airbases={}
for _,airbase in pairs(_DATABASE.AIRBASES) do
if (coalition~=nil and self:GetCoalition()==coalition) or coalition==nil then
if (coalition~=nil and airbase:GetCoalition()==coalition) or coalition==nil then
table.insert(airbases, airbase)
end
end

View File

@ -121,12 +121,15 @@ GROUPTEMPLATE.Takeoff = {
-- @return #GROUP self
function GROUP:NewTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID )
local GroupName = GroupTemplate.name
_DATABASE:_RegisterGroupTemplate( GroupTemplate, CoalitionSide, CategoryID, CountryID, GroupName )
self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) )
self:F2( GroupName )
local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) )
self.GroupName = GroupName
_DATABASE:AddGroup( GroupName )
if not _DATABASE.GROUPS[GroupName] then
_DATABASE.GROUPS[GroupName] = self
end
self:SetEventPriority( 4 )
return self
@ -140,7 +143,6 @@ end
-- @return #GROUP self
function GROUP:Register( GroupName )
local self = BASE:Inherit( self, CONTROLLABLE:New( GroupName ) ) -- #GROUP
self:F( GroupName )
self.GroupName = GroupName
self:SetEventPriority( 4 )
@ -335,8 +337,7 @@ end
--- Returns the country of the DCS Group.
-- @param #GROUP self
-- @return DCS#country.id The country identifier.
-- @return #nil The DCS Group is not existing or alive.
-- @return DCS#country.id The country identifier or nil if the DCS Group is not existing or alive.
function GROUP:GetCountry()
self:F2( self.GroupName )
@ -350,6 +351,40 @@ function GROUP:GetCountry()
return nil
end
--- Check if at least one (or all) unit(s) has (have) a certain attribute.
-- See [hoggit documentation](https://wiki.hoggitworld.com/view/DCS_func_hasAttribute).
-- @param #GROUP self
-- @param #string attribute The name of the attribute the group is supposed to have. Valid attributes can be found in the "db_attributes.lua" file which is located at in "C:\Program Files\Eagle Dynamics\DCS World\Scripts\Database".
-- @param #boolean all If true, all units of the group must have the attribute in order to return true. Default is only one unit of a heterogenious group needs to have the attribute.
-- @return #boolean Group has this attribute.
function GROUP:HasAttribute(attribute, all)
-- Get all units of the group.
local _units=self:GetUnits()
local _allhave=true
local _onehas=false
for _,_unit in pairs(_units) do
local _unit=_unit --Wrapper.Unit#UNIT
if _unit then
local _hastit=_unit:HasAttribute(attribute)
if _hastit==true then
_onehas=true
else
_allhave=false
end
end
end
if all==true then
return _allhave
else
return _onehas
end
end
--- Returns the maximum speed of the group.
-- If the group is heterogenious and consists of different units, the max speed of the slowest unit is returned.
-- @param #GROUP self
@ -1339,15 +1374,34 @@ function GROUP:Respawn( Template, Reset )
end
--- @param Wrapper.Group#GROUP self
function GROUP:RespawnAtAirbase( AirbaseRespawn, Takeoff, TakeoffAltitude ) -- R2.4
self:F( { AirbaseRespawn, Takeoff, TakeoffAltitude } )
--- Respawn a group at an airbase.
-- Note that the group has to be on parking spots at the airbase already in order for this to work.
-- So each unit of the group is respawned at exactly the same parking spot as it currently occupies.
-- @param Wrapper.Group#GROUP self
-- @param #table SpawnTemplate (Optional) The spawn template for the group. If no template is given it is exacted from the group.
-- @param Core.Spawn#SPAWN.Takeoff Takeoff (Optional) Takeoff type. Sould be either SPAWN.Takeoff.Cold or SPAWN.Takeoff.Hot. Default is SPAWN.Takeoff.Hot.
-- @param #boolean Uncontrolled (Optional) If true, spawn in uncontrolled state.
-- @return Wrapper.Group#GROUP Group spawned at airbase or nil if group could not be spawned.
function GROUP:RespawnAtCurrentAirbase(SpawnTemplate, Takeoff, Uncontrolled) -- R2.4
self:F2( { SpawnTemplate, Takeoff, Uncontrolled} )
local PointVec3 = AirbaseRespawn:GetPointVec3()
-- Get closest airbase. Should be the one we are currently on.
local airbase=self:GetCoordinate():GetClosestAirbase()
if airbase then
self:F2("Closest airbase = "..airbase:GetName())
else
self:E("ERROR: could not find closest airbase!")
return nil
end
-- Takeoff type. Default hot.
Takeoff = Takeoff or SPAWN.Takeoff.Hot
local SpawnTemplate = self:GetTemplate()
-- Coordinate of the airbase.
local AirbaseCoord=airbase:GetCoordinate()
-- Spawn template.
SpawnTemplate = SpawnTemplate or self:GetTemplate()
if SpawnTemplate then
@ -1358,78 +1412,62 @@ function GROUP:RespawnAtAirbase( AirbaseRespawn, Takeoff, TakeoffAltitude ) -- R
SpawnPoint.helipadId = nil
SpawnPoint.airdromeId = nil
local AirbaseID = AirbaseRespawn:GetID()
local AirbaseCategory = AirbaseRespawn:GetDesc().category
self:F( { AirbaseCategory = AirbaseCategory, Ship = Airbase.Category.SHIP, Helipad = Airbase.Category.HELIPAD, Airdrome = Airbase.Category.AIRDROME } )
-- Aibase id and category.
local AirbaseID = airbase:GetID()
local AirbaseCategory = airbase:GetDesc().category
if AirbaseCategory == Airbase.Category.SHIP then
SpawnPoint.linkUnit = AirbaseID
SpawnPoint.helipadId = AirbaseID
elseif AirbaseCategory == Airbase.Category.HELIPAD then
if AirbaseCategory == Airbase.Category.SHIP or AirbaseCategory == Airbase.Category.HELIPAD then
SpawnPoint.linkUnit = AirbaseID
SpawnPoint.helipadId = AirbaseID
elseif AirbaseCategory == Airbase.Category.AIRDROME then
SpawnPoint.airdromeId = AirbaseID
end
SpawnPoint.alt = 0
SpawnPoint.alt = AirbaseCoord:GetLandHeight()
SpawnPoint.type = GROUPTEMPLATE.Takeoff[Takeoff][1] -- type
SpawnPoint.action = GROUPTEMPLATE.Takeoff[Takeoff][2] -- action
-- Get the units of the group.
local units=self:GetUnits()
-- Translate the position of the Group Template to the Vec3.
for UnitID = 1, #SpawnTemplate.units do
self:T( 'Before Translation SpawnTemplate.units['..UnitID..'].x = ' .. SpawnTemplate.units[UnitID].x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. SpawnTemplate.units[UnitID].y )
for UnitID,_unit in pairs(units) do
-- These cause a lot of confusion.
local UnitTemplate = SpawnTemplate.units[UnitID]
local unit=_unit --Wrapper.Unit#UNIT
UnitTemplate.parking = 15
UnitTemplate.parking_id = "30"
UnitTemplate.alt = 0
-- Get closest parking spot of current unit. Note that we look for occupied spots since the unit is currently sitting on it!
local Parkingspot, TermialID, Distance=unit:GetCoordinate():GetClosestParkingSpot(airbase)
local SX = UnitTemplate.x
local SY = UnitTemplate.y
local BX = SpawnPoint.x
local BY = SpawnPoint.y
local TX = PointVec3.x + ( SX - BX )
local TY = PointVec3.z + ( SY - BY )
--Parkingspot:MarkToAll("parking spot")
self:T2(string.format("Closest parking spot distance = %s, terminal ID=%s", tostring(Distance), tostring(TermialID)))
UnitTemplate.x = TX
UnitTemplate.y = TY
-- Get unit coordinates for respawning position.
local uc=unit:GetCoordinate()
SpawnTemplate.units[UnitID].x = Parkingspot.x
SpawnTemplate.units[UnitID].y = Parkingspot.z
SpawnTemplate.units[UnitID].alt = Parkingspot.y
SpawnTemplate.units[UnitID].parking = TermialID
SpawnTemplate.units[UnitID].parking_id = nil
if Takeoff == GROUP.Takeoff.Air then
UnitTemplate.alt = PointVec3.y + ( TakeoffAltitude or 200 )
--else
-- UnitTemplate.alt = PointVec3.y + 10
end
self:T( 'After Translation SpawnTemplate.units['..UnitID..'].x = ' .. UnitTemplate.x .. ', SpawnTemplate.units['..UnitID..'].y = ' .. UnitTemplate.y )
end
SpawnPoint.x = PointVec3.x
SpawnPoint.y = PointVec3.z
SpawnPoint.x = AirbaseCoord.x
SpawnPoint.y = AirbaseCoord.z
if Takeoff == GROUP.Takeoff.Air then
SpawnPoint.alt = PointVec3.y + ( TakeoffAltitude or 200 )
--else
-- SpawnPoint.alt = PointVec3.y + 10
end
SpawnTemplate.x = AirbaseCoord.x
SpawnTemplate.y = AirbaseCoord.z
SpawnTemplate.x = PointVec3.x
SpawnTemplate.y = PointVec3.z
-- Set uncontrolled state.
SpawnTemplate.uncontrolled=Uncontrolled
local GroupSpawned = self:Respawn( SpawnTemplate )
-- Destroy and respawn.
self:Destroy()
_DATABASE:Spawn( SpawnTemplate )
-- When spawned in the air, we need to generate a Takeoff Event
-- Reset events.
self:ResetEvents()
if Takeoff == GROUP.Takeoff.Air then
for UnitID, UnitSpawned in pairs( GroupSpawned:GetUnits() ) do
SCHEDULER:New( nil, BASE.CreateEventTakeoff, { GroupSpawned, timer.getTime(), UnitSpawned:GetDCSObject() } , 1 )
end
end
return GroupSpawned
return self
end
return nil

View File

@ -216,7 +216,7 @@ end
function IDENTIFIABLE:GetDesc()
self:F2( self.IdentifiableName )
local DCSIdentifiable = self:GetDCSObject()
local DCSIdentifiable = self:GetDCSObject() -- DCS#Object
if DCSIdentifiable then
local IdentifiableDesc = DCSIdentifiable:getDesc()

View File

@ -243,7 +243,7 @@ end
--- Get the bounding box of the underlying POSITIONABLE DCS Object.
-- @param #POSITIONABLE self
-- @return DCS#Distance The bounding box of the POSITIONABLE.
-- @return DCS#Box3 The bounding box of the POSITIONABLE.
-- @return #nil The POSITIONABLE is not existing or alive.
function POSITIONABLE:GetBoundingBox() --R2.1
self:F2()
@ -264,6 +264,29 @@ function POSITIONABLE:GetBoundingBox() --R2.1
end
--- Get the bounding radius of the underlying POSITIONABLE DCS Object.
-- @param #POSITIONABLE self
-- @return DCS#Distance The bounding radius of the POSITIONABLE.
-- @return #nil The POSITIONABLE is not existing or alive.
function POSITIONABLE:GetBoundingRadius()
self:F2()
local Box = self:GetBoundingBox()
if Box then
local X = Box.max.x - Box.min.x
local Z = Box.max.z - Box.min.z
local CX = X / 2
local CZ = Z / 2
return math.max( CX, CZ )
end
BASE:E( { "Cannot GetBoundingRadius", Positionable = self, Alive = self:IsAlive() } )
return nil
end
--- Returns the altitude of the POSITIONABLE.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return DCS#Distance The altitude of the POSITIONABLE.
@ -323,7 +346,7 @@ end
--- Returns the POSITIONABLE heading in degrees.
-- @param Wrapper.Positionable#POSITIONABLE self
-- @return #number The POSTIONABLE heading
-- @return #number The POSITIONABLE heading
-- @return #nil The POSITIONABLE is not existing or alive.
function POSITIONABLE:GetHeading()
local DCSPositionable = self:GetDCSObject()
@ -347,6 +370,52 @@ function POSITIONABLE:GetHeading()
return nil
end
-- Is Methods
--- Returns if the unit is of an air category.
-- If the unit is a helicopter or a plane, then this method will return true, otherwise false.
-- @param #POSITIONABLE self
-- @return #boolean Air category evaluation result.
function POSITIONABLE:IsAir()
self:F2()
local DCSUnit = self:GetDCSObject()
if DCSUnit then
local UnitDescriptor = DCSUnit:getDesc()
self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER )
self:T3( IsAirResult )
return IsAirResult
end
return nil
end
--- Returns if the unit is of an ground category.
-- If the unit is a ground vehicle or infantry, this method will return true, otherwise false.
-- @param #POSITIONABLE self
-- @return #boolean Ground category evaluation result.
function POSITIONABLE:IsGround()
self:F2()
local DCSUnit = self:GetDCSObject()
if DCSUnit then
local UnitDescriptor = DCSUnit:getDesc()
self:T3( { UnitDescriptor.category, Unit.Category.GROUND_UNIT } )
local IsGroundResult = ( UnitDescriptor.category == Unit.Category.GROUND_UNIT )
self:T3( IsGroundResult )
return IsGroundResult
end
return nil
end
--- Returns true if the POSITIONABLE is in the air.
-- Polymorphic, is overridden in GROUP and UNIT.
@ -798,6 +867,8 @@ function POSITIONABLE:GetLaserCode() --R2.1
return self.LaserCode
end
do -- Cargo
--- Add cargo.
-- @param #POSITIONABLE self
-- @param Core.Cargo#CARGO Cargo
@ -838,6 +909,17 @@ function POSITIONABLE:ClearCargo()
self.__.Cargo = {}
end
--- Is cargo bay empty.
-- @param #POSITIONABLE self
function POSITIONABLE:IsCargoEmpty()
local IsEmpty = true
for _, Cargo in pairs( self.__.Cargo ) do
IsEmpty = false
break
end
return IsEmpty
end
--- Get cargo item count.
-- @param #POSITIONABLE self
-- @return Core.Cargo#CARGO Cargo
@ -849,6 +931,85 @@ function POSITIONABLE:CargoItemCount()
return ItemCount
end
-- --- Get Cargo Bay Free Volume in m3.
-- -- @param #POSITIONABLE self
-- -- @return #number CargoBayFreeVolume
-- function POSITIONABLE:GetCargoBayFreeVolume()
-- local CargoVolume = 0
-- for CargoName, Cargo in pairs( self.__.Cargo ) do
-- CargoVolume = CargoVolume + Cargo:GetVolume()
-- end
-- return self.__.CargoBayVolumeLimit - CargoVolume
-- end
--
--- Get Cargo Bay Free Weight in kg.
-- @param #POSITIONABLE self
-- @return #number CargoBayFreeWeight
function POSITIONABLE:GetCargoBayFreeWeight()
local CargoWeight = 0
for CargoName, Cargo in pairs( self.__.Cargo ) do
CargoWeight = CargoWeight + Cargo:GetWeight()
end
return self.__.CargoBayWeightLimit - CargoWeight
end
-- --- Get Cargo Bay Volume Limit in m3.
-- -- @param #POSITIONABLE self
-- -- @param #number VolumeLimit
-- function POSITIONABLE:SetCargoBayVolumeLimit( VolumeLimit )
-- self.__.CargoBayVolumeLimit = VolumeLimit
-- end
--- Get Cargo Bay Weight Limit in kg.
-- @param #POSITIONABLE self
-- @param #number WeightLimit
function POSITIONABLE:SetCargoBayWeightLimit( WeightLimit )
if WeightLimit then
self.__.CargoBayWeightLimit = WeightLimit
else
-- If weightlimit is not provided, we will calculate it depending on the type of unit.
-- When an airplane or helicopter, we calculate the weightlimit based on the descriptor.
if self:IsAir() then
local Desc = self:GetDesc()
self:F({Desc=Desc})
self.__.CargoBayWeightLimit = Desc.massMax - ( Desc.massEmpty + Desc.fuelMassMax )
else
local Desc = self:GetDesc()
local Weights = {
["M1126 Stryker ICV"] = 9,
["M-113"] = 9,
["AAV7"] = 25,
["M2A1_halftrack"] = 9,
["BMD-1"] = 9,
["BMP-1"] = 8,
["BMP-2"] = 7,
["BMP-3"] = 8,
["Boman"] = 25,
["BTR-80"] = 9,
["BTR_D"] = 12,
["Cobra"] = 8,
["LAV-25"] = 6,
["M-2 Bradley"] = 6,
["M1043 HMMWV Armament"] = 4,
["M1045 HMMWV TOW"] = 4,
["M1126 Stryker ICV"] = 9,
["M1134 Stryker ATGM"] = 9,
["Marder"] = 6,
["MCV-80"] = 9,
["MLRS FDDM"] = 4,
["MTLB"] = 25,
["TPZ"] = 10,
}
local CargoBayWeightLimit = ( Weights[Desc.typeName] or 0 ) * 70
self.__.CargoBayWeightLimit = CargoBayWeightLimit
end
end
end
end --- Cargo
--- Signal a flare at the position of the POSITIONABLE.
-- @param #POSITIONABLE self
-- @param Utilities.Utils#FLARECOLOR FlareColor

View File

@ -854,51 +854,7 @@ end
-- Is methods
--- Returns if the unit is of an air category.
-- If the unit is a helicopter or a plane, then this method will return true, otherwise false.
-- @param #UNIT self
-- @return #boolean Air category evaluation result.
function UNIT:IsAir()
self:F2()
local DCSUnit = self:GetDCSObject()
if DCSUnit then
local UnitDescriptor = DCSUnit:getDesc()
self:T3( { UnitDescriptor.category, Unit.Category.AIRPLANE, Unit.Category.HELICOPTER } )
local IsAirResult = ( UnitDescriptor.category == Unit.Category.AIRPLANE ) or ( UnitDescriptor.category == Unit.Category.HELICOPTER )
self:T3( IsAirResult )
return IsAirResult
end
return nil
end
--- Returns if the unit is of an ground category.
-- If the unit is a ground vehicle or infantry, this method will return true, otherwise false.
-- @param #UNIT self
-- @return #boolean Ground category evaluation result.
function UNIT:IsGround()
self:F2()
local DCSUnit = self:GetDCSObject()
if DCSUnit then
local UnitDescriptor = DCSUnit:getDesc()
self:T3( { UnitDescriptor.category, Unit.Category.GROUND_UNIT } )
local IsGroundResult = ( UnitDescriptor.category == Unit.Category.GROUND_UNIT )
self:T3( IsGroundResult )
return IsGroundResult
end
return nil
end
--- Returns if the unit is a friendly unit.
-- @param #UNIT self

View File

@ -57,6 +57,7 @@ Functional/ZoneCaptureCoalition.lua
Functional/Artillery.lua
Functional/Suppression.lua
Functional/PseudoATC.lua
Functional/Warehouse.lua
AI/AI_Balancer.lua
AI/AI_A2A.lua