mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
Merge branch 'develop' into FF/Develop
This commit is contained in:
commit
3ec2d525a9
@ -23,11 +23,13 @@
|
||||
--
|
||||
-- ## Cargo loading.
|
||||
--
|
||||
-- The module will load automatically cargo when the APCs are within boarding or loading range.
|
||||
-- The boarding or loading range is specified when the cargo is created in the simulation, and therefore, this range depends on the type of cargo
|
||||
-- and the specified boarding range.
|
||||
-- The module will load automatically cargo when the APCs are within boarding or loading radius.
|
||||
-- The boarding or loading radius is specified when the cargo is created in the simulation, and therefore, this radius depends on the type of cargo
|
||||
-- and the specified boarding radius.
|
||||
--
|
||||
-- ## Enemies nearby.
|
||||
-- ## **Defending** the APCs when enemies nearby.
|
||||
--
|
||||
-- Cargo will defend the carrier with its available arms, and to avoid cargo being lost within the battlefield.
|
||||
--
|
||||
-- When the APCs are approaching enemy units, something special is happening.
|
||||
-- The APCs will stop moving, and the loaded infantry will unboard and follow the APCs and will help to defend the group.
|
||||
@ -35,13 +37,17 @@
|
||||
-- to ensure that the APCs are not too far away from the following running infantry.
|
||||
-- Once all enemies are cleared, the infantry will board again automatically into the APCs. Once boarded, the APCs will follow its pre-defined route.
|
||||
--
|
||||
-- A combat range needs to be specified in meters at the @{#AI_CARGO_APC.New}() method.
|
||||
-- This combat range will trigger the unboarding of troops when enemies are within the combat range around the APCs.
|
||||
-- During my tests, I've noticed that there is a balance between ensuring that the infantry is within sufficient hit range (effectiveness) versus
|
||||
-- A combat radius needs to be specified in meters at the @{#AI_CARGO_APC.New}() method.
|
||||
-- This combat radius will trigger the unboarding of troops when enemies are within the combat radius around the APCs.
|
||||
-- During my tests, I've noticed that there is a balance between ensuring that the infantry is within sufficient hit radius (effectiveness) versus
|
||||
-- vulnerability of the infantry. It all depends on the kind of enemies that are expected to be encountered.
|
||||
-- A combat range of 350 meters to 500 meters has been proven to be the most effective and efficient.
|
||||
-- A combat radius of 350 meters to 500 meters has been proven to be the most effective and efficient.
|
||||
--
|
||||
-- ## Infantry health.
|
||||
-- However, when the defense of the carrier, is not required, it must be switched off.
|
||||
-- This is done by disabling the defense of the carrier using the method @{#AI_CARGO_APC.SetCombatRadius}(), and providing a combat radius of 0 meters.
|
||||
-- It can be switched on later when required by reenabling the defense using the method and providing a combat radius larger than 0.
|
||||
--
|
||||
-- ## Infantry or cargo **health**.
|
||||
--
|
||||
-- When infantry is unboarded from the APCs, the infantry is actually respawned into the battlefield.
|
||||
-- As a result, the unboarding infantry is very _healthy_ every time it unboards.
|
||||
@ -79,16 +85,14 @@ AI_CARGO_APC = {
|
||||
|
||||
--- Creates a new AI_CARGO_APC object.
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param Wrapper.Group#GROUP APC
|
||||
-- @param Core.Set#SET_CARGO CargoSet
|
||||
-- @param #number CombatRadius
|
||||
-- @param Wrapper.Group#GROUP APC The carrier APC group.
|
||||
-- @param Core.Set#SET_CARGO CargoSet The set of cargo to be transported.
|
||||
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby. When the combat radius is 0, no defense will happen of the carrier.
|
||||
-- @return #AI_CARGO_APC
|
||||
function AI_CARGO_APC:New( APC, CargoSet, CombatRadius )
|
||||
|
||||
local self = BASE:Inherit( self, AI_CARGO:New( APC, CargoSet ) ) -- #AI_CARGO_APC
|
||||
|
||||
self.CombatRadius = CombatRadius
|
||||
|
||||
self:AddTransition( "*", "Monitor", "*" )
|
||||
self:AddTransition( "*", "Follow", "Following" )
|
||||
self:AddTransition( "*", "Guard", "Unloaded" )
|
||||
@ -96,7 +100,7 @@ function AI_CARGO_APC:New( APC, CargoSet, CombatRadius )
|
||||
|
||||
self:AddTransition( "*", "Destroyed", "Destroyed" )
|
||||
|
||||
self:__Monitor( 1 )
|
||||
self:SetCombatRadius( CombatRadius )
|
||||
|
||||
self:SetCarrier( APC )
|
||||
|
||||
@ -123,7 +127,7 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier )
|
||||
if AICargoTroops then
|
||||
self:F({})
|
||||
if not AICargoTroops:Is( "Loaded" ) then
|
||||
-- There are enemies within combat range. Unload the CargoCarrier.
|
||||
-- There are enemies within combat radius. Unload the CargoCarrier.
|
||||
AICargoTroops:Destroyed()
|
||||
end
|
||||
end
|
||||
@ -135,7 +139,7 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier )
|
||||
if AICargoTroops then
|
||||
self:F( { OnHitLoaded = AICargoTroops:Is( "Loaded" ) } )
|
||||
if AICargoTroops:Is( "Loaded" ) or AICargoTroops:Is( "Boarding" ) then
|
||||
-- There are enemies within combat range. Unload the CargoCarrier.
|
||||
-- There are enemies within combat radius. Unload the CargoCarrier.
|
||||
AICargoTroops:Unload( false )
|
||||
end
|
||||
end
|
||||
@ -152,7 +156,7 @@ function AI_CARGO_APC:SetCarrier( CargoCarrier )
|
||||
end
|
||||
|
||||
|
||||
--- Find a free Carrier within a range.
|
||||
--- Find a free Carrier within a radius.
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param Core.Point#COORDINATE Coordinate
|
||||
-- @param #number Radius
|
||||
@ -177,6 +181,30 @@ function AI_CARGO_APC:FindCarrier( Coordinate, Radius )
|
||||
|
||||
end
|
||||
|
||||
--- Enable/Disable unboarding of cargo (infantry) when enemies are nearby (to help defend the carrier).
|
||||
-- This is only valid for APCs and trucks etc, thus ground vehicles.
|
||||
-- @param #AI_CARGO_APC self
|
||||
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby.
|
||||
-- When the combat radius is 0, no defense will happen of the carrier.
|
||||
-- When the combat radius is not provided, no defense will happen!
|
||||
-- @return #AI_CARGO_APC
|
||||
-- @usage
|
||||
--
|
||||
-- -- Disembark the infantry when the carrier is under attack.
|
||||
-- AICargoAPC:SetCombatRadius( true )
|
||||
--
|
||||
-- -- Keep the cargo in the carrier when the carrier is under attack.
|
||||
-- AICargoAPC:SetCombatRadius( false )
|
||||
function AI_CARGO_APC:SetCombatRadius( CombatRadius )
|
||||
|
||||
self.CombatRadius = CombatRadius or 0
|
||||
|
||||
if self.CombatRadius > 0 then
|
||||
self:__Monitor( -5 )
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Follow Infantry to the Carrier.
|
||||
@ -243,38 +271,40 @@ end
|
||||
function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
|
||||
self:F( { APC, From, Event, To } )
|
||||
|
||||
if APC and APC:IsAlive() then
|
||||
if self.CarrierCoordinate then
|
||||
if self:IsTransporting() == true then
|
||||
local Coordinate = APC:GetCoordinate()
|
||||
self.Zone:Scan( { Object.Category.UNIT } )
|
||||
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
|
||||
if self:Is( "Unloaded" ) or self:Is( "Following" ) then
|
||||
-- There are no enemies within combat range. Load the CargoCarrier.
|
||||
self:Load()
|
||||
end
|
||||
else
|
||||
if self:Is( "Loaded" ) then
|
||||
-- There are enemies within combat range. Unload the CargoCarrier.
|
||||
self:__Unload( 1 )
|
||||
else
|
||||
if self:Is( "Unloaded" ) then
|
||||
self:Follow()
|
||||
if self.CombatRadius > 0 then
|
||||
if APC and APC:IsAlive() then
|
||||
if self.CarrierCoordinate then
|
||||
if self:IsTransporting() == true then
|
||||
local Coordinate = APC:GetCoordinate()
|
||||
self.Zone:Scan( { Object.Category.UNIT } )
|
||||
if self.Zone:IsAllInZoneOfCoalition( self.Coalition ) then
|
||||
if self:Is( "Unloaded" ) or self:Is( "Following" ) then
|
||||
-- There are no enemies within combat radius. Load the CargoCarrier.
|
||||
self:Load()
|
||||
end
|
||||
self:F( "I am here" .. self:GetCurrentState() )
|
||||
if self:Is( "Following" ) then
|
||||
for Cargo, APCUnit in pairs( self.Carrier_Cargo ) do
|
||||
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
|
||||
if Cargo:IsAlive() then
|
||||
if not Cargo:IsNear( APCUnit, 40 ) then
|
||||
APCUnit:RouteStop()
|
||||
self.CarrierStopped = true
|
||||
else
|
||||
if self.CarrierStopped then
|
||||
if Cargo:IsNear( APCUnit, 25 ) then
|
||||
APCUnit:RouteResume()
|
||||
self.CarrierStopped = nil
|
||||
else
|
||||
if self:Is( "Loaded" ) then
|
||||
-- There are enemies within combat radius. Unload the CargoCarrier.
|
||||
self:__Unload( 1 )
|
||||
else
|
||||
if self:Is( "Unloaded" ) then
|
||||
self:Follow()
|
||||
end
|
||||
self:F( "I am here" .. self:GetCurrentState() )
|
||||
if self:Is( "Following" ) then
|
||||
for Cargo, APCUnit in pairs( self.Carrier_Cargo ) do
|
||||
local Cargo = Cargo -- Cargo.Cargo#CARGO
|
||||
local APCUnit = APCUnit -- Wrapper.Unit#UNIT
|
||||
if Cargo:IsAlive() then
|
||||
if not Cargo:IsNear( APCUnit, 40 ) then
|
||||
APCUnit:RouteStop()
|
||||
self.CarrierStopped = true
|
||||
else
|
||||
if self.CarrierStopped then
|
||||
if Cargo:IsNear( APCUnit, 25 ) then
|
||||
APCUnit:RouteResume()
|
||||
self.CarrierStopped = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -283,14 +313,14 @@ function AI_CARGO_APC:onafterMonitor( APC, From, Event, To )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.CarrierCoordinate = APC:GetCoordinate()
|
||||
end
|
||||
self.CarrierCoordinate = APC:GetCoordinate()
|
||||
|
||||
self:__Monitor( -5 )
|
||||
end
|
||||
|
||||
self:__Monitor( -5 )
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
@ -141,12 +141,6 @@ function AI_CARGO_AIRPLANE:New( Airplane, CargoSet )
|
||||
-- Set carrier.
|
||||
self:SetCarrier( Airplane )
|
||||
|
||||
for _, AirplaneUnit in pairs( Airplane:GetUnits() ) do
|
||||
AirplaneUnit:SetCargoBayWeightLimit()
|
||||
end
|
||||
|
||||
self.Relocating = true
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@ -115,18 +115,39 @@ function AI_CARGO_DISPATCHER_APC:New( APCSet, CargoSet, PickupZoneSet, DeployZon
|
||||
|
||||
local self = BASE:Inherit( self, AI_CARGO_DISPATCHER:NewWithZones( APCSet, CargoSet, PickupZoneSet, DeployZoneSet ) ) -- #AI_CARGO_DISPATCHER_APC
|
||||
|
||||
self.CombatRadius = CombatRadius or 500
|
||||
|
||||
self:SetDeploySpeed( 120, 70 )
|
||||
self:SetPickupSpeed( 120, 70 )
|
||||
self:SetPickupRadius( 0, 0 )
|
||||
self:SetDeployRadius( 0, 0 )
|
||||
|
||||
self:SetCombatRadius( CombatRadius )
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
function AI_CARGO_DISPATCHER_APC:AICargo( APC, CargoSet )
|
||||
|
||||
return AI_CARGO_APC:New( APC, CargoSet, self.CombatRadius )
|
||||
end
|
||||
|
||||
--- Enable/Disable unboarding of cargo (infantry) when enemies are nearby (to help defend the carrier).
|
||||
-- This is only valid for APCs and trucks etc, thus ground vehicles.
|
||||
-- @param #AI_CARGO_DISPATCHER_APC self
|
||||
-- @param #number CombatRadius Provide the combat radius to defend the carrier by unboarding the cargo when enemies are nearby.
|
||||
-- When the combat radius is 0, no defense will happen of the carrier.
|
||||
-- When the combat radius is not provided, no defense will happen!
|
||||
-- @return #AI_CARGO_DISPATCHER_APC
|
||||
-- @usage
|
||||
--
|
||||
-- -- Disembark the infantry when the carrier is under attack.
|
||||
-- AICargoDispatcher:SetCombatRadius( true )
|
||||
--
|
||||
-- -- Keep the cargo in the carrier when the carrier is under attack.
|
||||
-- AICargoDispatcher:SetCombatRadius( false )
|
||||
function AI_CARGO_DISPATCHER_APC:SetCombatRadius( CombatRadius )
|
||||
|
||||
self.CombatRadius = CombatRadius or 0
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
@ -171,13 +171,6 @@ 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
|
||||
|
||||
@ -69,25 +69,25 @@ do -- CARGO_GROUP
|
||||
local WeightGroup = 0
|
||||
local VolumeGroup = 0
|
||||
|
||||
self.CargoGroup:Destroy()
|
||||
self.CargoGroup:Destroy( true ) -- generate the crash events, so that the database gets cleaned, and the linked sets get properly cleaned.
|
||||
|
||||
local GroupName = CargoGroup:GetName()
|
||||
self.CargoName = Name
|
||||
self.CargoTemplate = UTILS.DeepCopy( _DATABASE:GetGroupTemplate( GroupName ) )
|
||||
|
||||
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
||||
GroupTemplate.name = self.CargoName .. "#CARGO"
|
||||
GroupTemplate.groupId = nil
|
||||
self.GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
||||
self.GroupTemplate.name = self.CargoName .. "#CARGO"
|
||||
self.GroupTemplate.groupId = nil
|
||||
|
||||
GroupTemplate.units = {}
|
||||
self.GroupTemplate.units = {}
|
||||
|
||||
for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do
|
||||
UnitTemplate.name = UnitTemplate.name .. "#CARGO"
|
||||
local CargoUnitName = UnitTemplate.name
|
||||
self.CargoUnitTemplate[CargoUnitName] = UnitTemplate
|
||||
|
||||
GroupTemplate.units[#GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName]
|
||||
GroupTemplate.units[#GroupTemplate.units].unitId = nil
|
||||
self.GroupTemplate.units[#self.GroupTemplate.units+1] = self.CargoUnitTemplate[CargoUnitName]
|
||||
self.GroupTemplate.units[#self.GroupTemplate.units].unitId = nil
|
||||
|
||||
-- And we register the spawned unit as part of the CargoSet.
|
||||
local Unit = UNIT:Register( CargoUnitName )
|
||||
@ -95,10 +95,10 @@ do -- CARGO_GROUP
|
||||
end
|
||||
|
||||
-- Then we register the new group in the database
|
||||
self.CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID )
|
||||
self.CargoGroup = GROUP:NewTemplate( self.GroupTemplate, self.GroupTemplate.CoalitionID, self.GroupTemplate.CategoryID, self.GroupTemplate.CountryID )
|
||||
|
||||
-- Now we spawn the new group based on the template created.
|
||||
self.CargoObject = _DATABASE:Spawn( GroupTemplate )
|
||||
self.CargoObject = _DATABASE:Spawn( self.GroupTemplate )
|
||||
|
||||
for CargoUnitID, CargoUnit in pairs( self.CargoObject:GetUnits() ) do
|
||||
|
||||
@ -109,7 +109,6 @@ do -- CARGO_GROUP
|
||||
self.CargoSet:Add( CargoUnitName, Cargo )
|
||||
|
||||
WeightGroup = WeightGroup + Cargo:GetWeight()
|
||||
--VolumeGroup = VolumeGroup + VolumeUnit
|
||||
|
||||
end
|
||||
|
||||
@ -129,6 +128,35 @@ do -- CARGO_GROUP
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- Respawn the CargoGroup.
|
||||
-- @param #CARGO_GROUP self
|
||||
function CARGO_GROUP:Respawn()
|
||||
|
||||
self:F( { "Respawning" } )
|
||||
|
||||
for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do
|
||||
local Cargo = CargoData -- Cargo.Cargo#CARGO
|
||||
Cargo:Destroy()
|
||||
Cargo:SetStartState( "UnLoaded" )
|
||||
end
|
||||
|
||||
-- Now we spawn the new group based on the template created.
|
||||
_DATABASE:Spawn( self.GroupTemplate )
|
||||
|
||||
for CargoUnitID, CargoUnit in pairs( self.CargoObject:GetUnits() ) do
|
||||
|
||||
local CargoUnitName = CargoUnit:GetName()
|
||||
|
||||
local Cargo = CARGO_UNIT:New( CargoUnit, self.Type, CargoUnitName, self.LoadRadius )
|
||||
self.CargoSet:Add( CargoUnitName, Cargo )
|
||||
|
||||
end
|
||||
|
||||
self:SetDeployed( false )
|
||||
self:SetStartState( "UnLoaded" )
|
||||
|
||||
end
|
||||
|
||||
--- Ungroup the cargo group into individual groups with one unit.
|
||||
-- This is required because by default a group will move in formation and this is really an issue for group control.
|
||||
@ -678,53 +706,6 @@ do -- CARGO_GROUP
|
||||
|
||||
end
|
||||
|
||||
--- Respawn the CargoGroup.
|
||||
-- @param #CARGO_GROUP self
|
||||
function CARGO_GROUP:Respawn()
|
||||
|
||||
self:F( { "Respawning" } )
|
||||
|
||||
for CargoID, CargoData in pairs( self.CargoSet:GetSet() ) do
|
||||
local Cargo = CargoData -- Cargo.Cargo#CARGO
|
||||
Cargo:Destroy()
|
||||
Cargo:SetStartState( "UnLoaded" )
|
||||
end
|
||||
|
||||
|
||||
-- We iterate through the group template and for each unit in the template, we create a new group with one unit.
|
||||
for UnitID, UnitTemplate in pairs( self.CargoTemplate.units ) do
|
||||
|
||||
local GroupTemplate = UTILS.DeepCopy( self.CargoTemplate )
|
||||
local GroupName = env.getValueDictByKey( GroupTemplate.name )
|
||||
|
||||
-- We create a new group object with one unit...
|
||||
-- First we prepare the template...
|
||||
GroupTemplate.name = GroupName .. "#CARGO#" .. UnitID
|
||||
GroupTemplate.groupId = nil
|
||||
GroupTemplate.units = {}
|
||||
GroupTemplate.units[1] = UnitTemplate
|
||||
local UnitName = UnitTemplate.name .. "#CARGO"
|
||||
GroupTemplate.units[1].name = UnitTemplate.name .. "#CARGO"
|
||||
|
||||
|
||||
-- Then we register the new group in the database
|
||||
local CargoGroup = GROUP:NewTemplate( GroupTemplate, GroupTemplate.CoalitionID, GroupTemplate.CategoryID, GroupTemplate.CountryID)
|
||||
|
||||
-- Now we spawn the new group based on the template created.
|
||||
_DATABASE:Spawn( GroupTemplate )
|
||||
|
||||
-- And we register the spawned unit as part of the CargoSet.
|
||||
local Unit = UNIT:FindByName( UnitName )
|
||||
--local WeightUnit = Unit:GetDesc().massEmpty
|
||||
--WeightGroup = WeightGroup + WeightUnit
|
||||
local CargoUnit = CARGO_UNIT:New( Unit, Type, UnitName, 10 )
|
||||
self.CargoSet:Add( UnitName, CargoUnit )
|
||||
end
|
||||
|
||||
self:SetDeployed( false )
|
||||
self:SetStartState( "UnLoaded" )
|
||||
|
||||
end
|
||||
|
||||
--- Signal a flare at the position of the CargoGroup.
|
||||
-- @param #CARGO_GROUP self
|
||||
|
||||
@ -297,7 +297,7 @@ do -- CARGO_UNIT
|
||||
if self:IsNear( CargoCarrier:GetPointVec2(), NearRadius ) then
|
||||
self:__Load( 1, CargoCarrier, ... )
|
||||
else
|
||||
self:__Boarding( -5, CargoCarrier, NearRadius, ... )
|
||||
self:__Boarding( -1, CargoCarrier, NearRadius, ... )
|
||||
self.RunCount = self.RunCount + 1
|
||||
if self.RunCount >= 40 then
|
||||
self.RunCount = 0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user