Merge pull request #2565 from FlightControl-Master/master-ng

Merge from master
This commit is contained in:
Thomas
2026-03-26 06:45:10 +01:00
committed by GitHub
4 changed files with 70 additions and 12 deletions
+46 -3
View File
@@ -197,6 +197,7 @@ do
-- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack. it will be a 1 step solution. -- my_ctld.onestepmenu = false -- When set to true, the menu will create Drop and build, Get and load, Pack and remove, Pack and load, Pack. it will be a 1 step solution.
-- my_ctld.VehicleMoveFormation = AI.Task.VehicleFormation.VEE -- When a group moves to a MOVE zone, then it takes this formation. Can be a table of formations, which are then randomly chosen. Defaults to "Vee". -- my_ctld.VehicleMoveFormation = AI.Task.VehicleFormation.VEE -- When a group moves to a MOVE zone, then it takes this formation. Can be a table of formations, which are then randomly chosen. Defaults to "Vee".
-- my_ctld.validateAndRepositionUnits = false -- Uses Disposition and other logic to find better ground positions for ground units avoiding trees, water, roads, runways, map scenery, statics and other units in the area. (Default is false) -- my_ctld.validateAndRepositionUnits = false -- Uses Disposition and other logic to find better ground positions for ground units avoiding trees, water, roads, runways, map scenery, statics and other units in the area. (Default is false)
-- my_ctld.maxUnloadTroopsAllowed = -1 -- Max troops allowed to be unloaded at once. Set to -1 for unlimited (Default). This is a soft limit, that is, if you have more troops in the heli, it will still unload them. Ex. prevent players from spamming troops on the ground and causing performance issues.
-- my_ctld.loadSavedCrates = true -- Load back crates (STATIC) from the save file. Useful for mission restart cleanup. (Default is true) -- my_ctld.loadSavedCrates = true -- Load back crates (STATIC) from the save file. Useful for mission restart cleanup. (Default is true)
-- my_ctld.UseC130LoadAndUnload = false -- When set to true, forces the C-130 player to use the C-130J built system to load the cargo onboard and to unload. (Default is false) -- my_ctld.UseC130LoadAndUnload = false -- When set to true, forces the C-130 player to use the C-130J built system to load the cargo onboard and to unload. (Default is false)
-- my_ctld.UseC130DynamicCargoAutoBuild = false -- When true (and UseC130LoadAndUnload is true), C-130 DynamicCargo unload completion is bridged to CTLD engineer-path auto-build. -- my_ctld.UseC130DynamicCargoAutoBuild = false -- When true (and UseC130LoadAndUnload is true), C-130 DynamicCargo unload completion is bridged to CTLD engineer-path auto-build.
@@ -1028,6 +1029,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
self.FixedMaxSpeed = 77 -- 280 kph or 150kn eq 77 mps self.FixedMaxSpeed = 77 -- 280 kph or 150kn eq 77 mps
self.validateAndRepositionUnits = false -- 280 kph or 150kn eq 77 mps self.validateAndRepositionUnits = false -- 280 kph or 150kn eq 77 mps
self.maxUnloadTroopsAllowed = -1
-- message suppression -- message suppression
self.suppressmessages = false self.suppressmessages = false
@@ -4994,6 +4996,18 @@ function CTLD:_GetUnitPositions(Coordinate,Radius,Heading,Template)
return Positions return Positions
end end
--- Override this function to check if troops can be unloaded. This does not prevent returning troops to base.
-- @param #CTLD self
-- @param Wrapper.Group#GROUP The group trying to unload
-- @param Wrapper.Unit#UNIT The unit trying to unload
-- @param #table LoadedCargo Table of loaded cargo, see #CTLD.LoadedCargo
-- @param #boolean IsGrounded Is the unit on the ground
-- @param #boolean IsHoverUnload Is the unit hovering in parameters for hover unload
-- @return #boolean True if troops can be unloaded, false to prevent unloading
function CTLD:CanUnloadAllTroops(Group, Unit, LoadedCargo, IsGrounded, IsHoverUnload)
return true
end
--- (Internal) Function to unload troops from heli. --- (Internal) Function to unload troops from heli.
-- @param #CTLD self -- @param #CTLD self
-- @param Wrapper.Group#GROUP Group -- @param Wrapper.Group#GROUP Group
@@ -5029,8 +5043,13 @@ function CTLD:_UnloadTroops(Group, Unit)
-- Get what we have loaded -- Get what we have loaded
local unitname = Unit:GetName() local unitname = Unit:GetName()
if self.Loaded_Cargo[unitname] and (grounded or hoverunload) then if self.Loaded_Cargo[unitname] and (grounded or hoverunload) then
local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo
if not self:CanUnloadAllTroops(Group, Unit, loadedcargo, grounded, hoverunload) then
-- User can post their own message in the function
return self
end
if not droppingatbase or self.debug then if not droppingatbase or self.debug then
local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo
-- looking for troops -- looking for troops
local cargotable = loadedcargo.Cargo local cargotable = loadedcargo.Cargo
local deployedTroopsByName = {} local deployedTroopsByName = {}
@@ -6374,8 +6393,11 @@ function CTLD:_RefreshF10Menus()
end end
end end
local dropTroopsMenu=MENU_GROUP:New(_group,self.gettext:GetEntry("MENU_DROP_TROOPS",self.locale),toptroops):Refresh() local dropTroopsMenu=MENU_GROUP:New(_group,self.gettext:GetEntry("MENU_DROP_TROOPS",self.locale),toptroops):Refresh()
MENU_GROUP_COMMAND:New(_group,self.gettext:GetEntry("MENU_DROP_ALL_TROOPS",self.locale),dropTroopsMenu,self._UnloadTroops,self,_group,_unit):Refresh() if self.maxUnloadTroopsAllowed == -1 then
MENU_GROUP_COMMAND:New(_group,self.gettext:GetEntry("MENU_DROP_ALL_TROOPS",self.locale),dropTroopsMenu,self._UnloadTroops,self,_group,_unit):Refresh()
end
MENU_GROUP_COMMAND:New(_group,self.gettext:GetEntry("MENU_EXTRACT_TROOPS",self.locale),toptroops,self._ExtractTroops,self,_group,_unit):Refresh() MENU_GROUP_COMMAND:New(_group,self.gettext:GetEntry("MENU_EXTRACT_TROOPS",self.locale),toptroops,self._ExtractTroops,self,_group,_unit):Refresh()
local uName=_unit:GetName() local uName=_unit:GetName()
local loadedData=self.Loaded_Cargo[uName] local loadedData=self.Loaded_Cargo[uName]
if loadedData and loadedData.Cargo then if loadedData and loadedData.Cargo then
@@ -7300,6 +7322,19 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
end end
end end
--- Override this function to check if we can unload a single Troop group by ID.
-- @param #CTLD self
-- @param Wrapper.Group#GROUP Group The aircraft group.
-- @param Wrapper.Unit#UNIT Unit The aircraft unit.
-- @param #number ChunkID the Cargo ID
-- @param #number Quantity the quantity to unload
-- @param #table LoadedCargo the current loaded cargo table for this unit
-- @param #boolean IsGrounded whether the unit is currently grounded
-- @param #boolean IsHoverUnload whether the unit is currently in hover-unload state
-- @return #boolean true if we can unload, false if not
function CTLD:CanUnloadSingleTroopByID(Group, Unit, ChunkID, Quantity, LoadedCargo, IsGrounded, IsHoverUnload)
return true
end
--- (Internal) Function to unload a single Troop group by ID. --- (Internal) Function to unload a single Troop group by ID.
-- @param #CTLD self -- @param #CTLD self
@@ -7338,6 +7373,11 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID, qty)
local unitName = Unit:GetName() local unitName = Unit:GetName()
if self.Loaded_Cargo[unitName] and (grounded or hoverunload) then if self.Loaded_Cargo[unitName] and (grounded or hoverunload) then
local loadedcargo = self.Loaded_Cargo[unitName] or {} -- #CTLD.LoadedCargo
if not self:CanUnloadSingleTroopByID(Group, Unit, chunkID, qty, loadedcargo, grounded, hoverunload) then
-- User can post their own message in the function
return self
end
if not droppingatbase or self.debug then if not droppingatbase or self.debug then
if not self.TroopsIDToChunk or not self.TroopsIDToChunk[chunkID] then if not self.TroopsIDToChunk or not self.TroopsIDToChunk[chunkID] then
local msg = self.gettext:GetEntry("NO_TROOP_CHUNK",self.locale) local msg = self.gettext:GetEntry("NO_TROOP_CHUNK",self.locale)
@@ -7532,7 +7572,9 @@ function CTLD:_RefreshDropTroopsMenu(Group, Unit)
dropTroopsMenu = MENU_GROUP:New(theGroup, self.gettext:GetEntry("MENU_DROP_TROOPS",self.locale), topTroops) dropTroopsMenu = MENU_GROUP:New(theGroup, self.gettext:GetEntry("MENU_DROP_TROOPS",self.locale), topTroops)
topTroops.DropTroopsMenu = dropTroopsMenu topTroops.DropTroopsMenu = dropTroopsMenu
end end
MENU_GROUP_COMMAND:New(theGroup, self.gettext:GetEntry("MENU_DROP_ALL_TROOPS",self.locale), dropTroopsMenu, self._UnloadTroops, self, theGroup, theUnit) if self.maxUnloadTroopsAllowed == -1 then
MENU_GROUP_COMMAND:New(theGroup, self.gettext:GetEntry("MENU_DROP_ALL_TROOPS",self.locale), dropTroopsMenu, self._UnloadTroops, self, theGroup, theUnit)
end
local loadedData = self.Loaded_Cargo[theUnit:GetName()] local loadedData = self.Loaded_Cargo[theUnit:GetName()]
if not loadedData or not loadedData.Cargo then return end if not loadedData or not loadedData.Cargo then return end
@@ -7565,6 +7607,7 @@ function CTLD:_RefreshDropTroopsMenu(Group, Unit)
else else
local parentMenu = MENU_GROUP:New(theGroup, label, dropTroopsMenu) local parentMenu = MENU_GROUP:New(theGroup, label, dropTroopsMenu)
for q = 1, count do for q = 1, count do
if q > self.maxUnloadTroopsAllowed then break end
MENU_GROUP_COMMAND:New(theGroup, string.format(self.gettext:GetEntry("MENU_DROP_N_TROOPS",self.locale), q, tName), parentMenu, self._UnloadSingleTroopByID, self, theGroup, theUnit, chunkID, q) MENU_GROUP_COMMAND:New(theGroup, string.format(self.gettext:GetEntry("MENU_DROP_N_TROOPS",self.locale), q, tName), parentMenu, self._UnloadSingleTroopByID, self, theGroup, theUnit, chunkID, q)
--MENU_GROUP_COMMAND:New(theGroup, string.format("Drop (%d) %s", q, tName), parentMenu, self._UnloadSingleTroopByID, self, theGroup, theUnit, chunkID, q) --MENU_GROUP_COMMAND:New(theGroup, string.format("Drop (%d) %s", q, tName), parentMenu, self._UnloadSingleTroopByID, self, theGroup, theUnit, chunkID, q)
end end
+12 -2
View File
@@ -257,6 +257,7 @@ CHIEF = {
tacview = false, tacview = false,
Nsuccess = 0, Nsuccess = 0,
Nfailure = 0, Nfailure = 0,
LegionRecruitMinRange = {}
} }
--- Defence condition. --- Defence condition.
@@ -2465,9 +2466,9 @@ function CHIEF:CheckTargetQueue()
-- Debug info. -- Debug info.
self:T2(self.lid..string.format("Recruiting assets for mission type %s [performance=%d] of target %s", mp.MissionType, mp.Performance, target:GetName())) self:T2(self.lid..string.format("Recruiting assets for mission type %s [performance=%d] of target %s", mp.MissionType, mp.Performance, target:GetName()))
local minRange = self.LegionRecruitMinRange[target.category]
-- Recruit assets. -- Recruit assets.
local recruited, assets, legions=self.commander:RecruitAssetsForTarget(target, mp.MissionType, NassetsMin, NassetsMax) local recruited, assets, legions=self.commander:RecruitAssetsForTarget(target, mp.MissionType, NassetsMin, NassetsMax, minRange)
if recruited then if recruited then
@@ -3369,6 +3370,15 @@ function CHIEF:CanMission(Mission)
return self.commander and self.commander:CanMission(Mission) return self.commander and self.commander:CanMission(Mission)
end end
--- Exclude legion recruitment that are below a minimum range to target based on the target category.
--- Ex. Prevent intercepts from spawning too close to the target.
-- @param #CHIEF self
-- @param #string TargetCategory The target category.
-- @param #number MinRange Minimum range in meters.
function CHIEF:AddLegionRecruitMinRange(TargetCategory, MinRange)
self.LegionRecruitMinRange[TargetCategory] = MinRange
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+3 -2
View File
@@ -1914,10 +1914,11 @@ end
-- @param #string MissionType Mission Type. -- @param #string MissionType Mission Type.
-- @param #number NassetsMin Min number of required assets. -- @param #number NassetsMin Min number of required assets.
-- @param #number NassetsMax Max number of required assets. -- @param #number NassetsMax Max number of required assets.
-- @param #number (optional) RangeMin Minimum range to target. (Default is 0, which means no minimum range)
-- @return #boolean If `true` enough assets could be recruited. -- @return #boolean If `true` enough assets could be recruited.
-- @return #table Assets that have been recruited from all legions. -- @return #table Assets that have been recruited from all legions.
-- @return #table Legions that have recruited assets. -- @return #table Legions that have recruited assets.
function COMMANDER:RecruitAssetsForTarget(Target, MissionType, NassetsMin, NassetsMax) function COMMANDER:RecruitAssetsForTarget(Target, MissionType, NassetsMin, NassetsMax, RangeMin)
-- Cohorts. -- Cohorts.
local Cohorts=self:_GetCohorts() local Cohorts=self:_GetCohorts()
@@ -1926,7 +1927,7 @@ function COMMANDER:RecruitAssetsForTarget(Target, MissionType, NassetsMin, Nasse
local TargetVec2=Target:GetVec2() local TargetVec2=Target:GetVec2()
-- Recruite assets. -- Recruite assets.
local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, MissionType, nil, NassetsMin, NassetsMax, TargetVec2) local recruited, assets, legions=LEGION.RecruitCohortAssets(Cohorts, MissionType, nil, NassetsMin, NassetsMax, TargetVec2, nil, nil, nil , nil, nil, nil, nil, nil, nil, nil, RangeMin)
return recruited, assets, legions return recruited, assets, legions
+9 -5
View File
@@ -2577,8 +2577,11 @@ end
-- @param #number RefuelSystem Refueling system (boom or probe). -- @param #number RefuelSystem Refueling system (boom or probe).
-- @param #number CargoWeight Cargo weight [kg]. This checks the cargo bay of the cohort assets and ensures that it is large enough to carry the given cargo weight. -- @param #number CargoWeight Cargo weight [kg]. This checks the cargo bay of the cohort assets and ensures that it is large enough to carry the given cargo weight.
-- @param #number MaxWeight Max weight [kg]. This checks whether the cohort asset group is not too heavy. -- @param #number MaxWeight Max weight [kg]. This checks whether the cohort asset group is not too heavy.
-- @param RangeMin Min range in meters. (Default is 0, i.e. no minimum range.)
-- @return #boolean Returns `true` if given cohort can meet all requirements. -- @return #boolean Returns `true` if given cohort can meet all requirements.
function LEGION._CohortCan(Cohort, MissionType, Categories, Attributes, Properties, WeaponTypes, TargetVec2, RangeMax, RefuelSystem, CargoWeight, MaxWeight) function LEGION._CohortCan(Cohort, MissionType, Categories, Attributes, Properties, WeaponTypes, TargetVec2, RangeMax, RefuelSystem, CargoWeight, MaxWeight, RangeMin)
RangeMin = RangeMin or 0
--- Function to check category. --- Function to check category.
local function CheckCategory(_cohort) local function CheckCategory(_cohort)
@@ -2656,8 +2659,8 @@ function LEGION._CohortCan(Cohort, MissionType, Categories, Attributes, Properti
-- Is in range? -- Is in range?
local Rmax=cohort:GetMissionRange(WeaponTypes) local Rmax=cohort:GetMissionRange(WeaponTypes)
local RangeMax = RangeMax or 0 local RangeMax = RangeMax or 0
local InRange=(RangeMax and math.max(RangeMax, Rmax) or Rmax) >= TargetDistance local InRange=(RangeMax and math.max(RangeMax, Rmax) or Rmax) >= TargetDistance and TargetDistance > RangeMin
--env.info(string.format("Range TargetDist=%.1f Rmax=%.1f RangeMax=%.1f InRange=%s", TargetDistance, Rmax, RangeMax, tostring(InRange))) --env.info(string.format("Range TargetDist=%.1f Rmax=%.1f RangeMax=%.1f InRange=%s", TargetDistance, Rmax, RangeMax, tostring(InRange)))
return InRange return InRange
@@ -2803,10 +2806,11 @@ end
-- @param #table Attributes Group attributes. See `GROUP.Attribute.` -- @param #table Attributes Group attributes. See `GROUP.Attribute.`
-- @param #table Properties DCS attributes. -- @param #table Properties DCS attributes.
-- @param #table WeaponTypes Bit of weapon types. -- @param #table WeaponTypes Bit of weapon types.
-- @param #number RangeMin Min range in meters. (Default is 0, i.e. no minimum range.)
-- @return #boolean If `true` enough assets could be recruited. -- @return #boolean If `true` enough assets could be recruited.
-- @return #table Recruited assets. **NOTE** that we set the `asset.isReserved=true` flag so it cant be recruited by anyone else. -- @return #table Recruited assets. **NOTE** that we set the `asset.isReserved=true` flag so it cant be recruited by anyone else.
-- @return #table Legions of recruited assets. -- @return #table Legions of recruited assets.
function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt, NreqMin, NreqMax, TargetVec2, Payloads, RangeMax, RefuelSystem, CargoWeight, TotalWeight, MaxWeight, Categories, Attributes, Properties, WeaponTypes) function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt, NreqMin, NreqMax, TargetVec2, Payloads, RangeMax, RefuelSystem, CargoWeight, TotalWeight, MaxWeight, Categories, Attributes, Properties, WeaponTypes, RangeMin)
-- The recruited assets. -- The recruited assets.
local Assets={} local Assets={}
@@ -2824,7 +2828,7 @@ function LEGION.RecruitCohortAssets(Cohorts, MissionTypeRecruit, MissionTypeOpt,
local cohort=_cohort --Ops.Cohort#COHORT local cohort=_cohort --Ops.Cohort#COHORT
-- Check if cohort can do the mission. -- Check if cohort can do the mission.
local can=LEGION._CohortCan(cohort, MissionTypeRecruit, Categories, Attributes, Properties, WeaponTypes, TargetVec2, RangeMax, RefuelSystem, CargoWeight, MaxWeight) local can=LEGION._CohortCan(cohort, MissionTypeRecruit, Categories, Attributes, Properties, WeaponTypes, TargetVec2, RangeMax, RefuelSystem, CargoWeight, MaxWeight, RangeMin)
--env.info(string.format("RecruitCohortAssets %s Cohort=%s can=%s", MissionTypeRecruit, cohort:GetName(), tostring(can))) --env.info(string.format("RecruitCohortAssets %s Cohort=%s can=%s", MissionTypeRecruit, cohort:GetName(), tostring(can)))