Merge pull request #2515 from FlightControl-Master/leka1986-patch-1

Added a new function: CTLD:CanGetTroops, this is a final check for outside hooks, if player have conditions.

Reworked cargo placement in the case of none ship. Cargo will be placed and sizes are depended on the cargo type, this can be further tweaked under the function GetCrates. This is applied to all types of cargo and all type of units.

Removed "Get" from the menu if the UseC130LoadAndUnload is true, player choose now the amount of cargo, then they will spawn. Same is for the Chinook if GCLoading is enabled.

Increased the UH-60L_DAP crate limit to 2 and the weight limit to 3500.

C130basetype is now independent of UseC130LoadAndUnload true / false. It will always be cds_crate for the C-130, and players can change it to whatever.
This commit is contained in:
leka1986
2026-02-22 13:44:10 +01:00
committed by GitHub
+358 -137
View File
@@ -1514,7 +1514,7 @@ CTLD.UnitTypeCapabilities = {
["C-130J-30"] = {type="C-130J-30", crates=true, troops=true, cratelimit = 7, trooplimit = 64, length = 35, cargoweightlimit = 21500}, -- 19t cargo, 64 paratroopers.
--Actually it's longer, but the center coord is off-center of the model.
["UH-60L"] = {type="UH-60L", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
["UH-60L_DAP"] = {type="UH-60L_DAP", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 16, cargoweightlimit = 500}, -- UH-60L DAP is an attack helo but can do limited CSAR and CTLD
["UH-60L_DAP"] = {type="UH-60L_DAP", crates=false, troops=true, cratelimit = 2, trooplimit = 2, length = 16, cargoweightlimit = 3000}, -- UH-60L DAP is an attack helo but can do limited CSAR and CTLD
["MH-60R"] = {type="MH-60R", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
["SH-60B"] = {type="SH-60B", crates=true, troops=true, cratelimit = 2, trooplimit = 20, length = 16, cargoweightlimit = 3500}, -- 4t cargo, 20 (unsec) seats
["AH-64D_BLK_II"] = {type="AH-64D_BLK_II", crates=false, troops=true, cratelimit = 0, trooplimit = 2, length = 17, cargoweightlimit = 200}, -- 2 ppl **outside** the helo
@@ -1647,6 +1647,9 @@ function CTLD:New(Coalition, Prefixes, Alias)
self.Cargo_Crates = {}
self.Cargo_Troops = {}
self.Cargo_Statics = {}
self._troopsByName = {}
self._crateOrStaticByName = {}
self._cargoByTemplate = {}
self.Loaded_Cargo = {}
self.Spawned_Crates = {}
self.Spawned_Cargo = {}
@@ -2419,9 +2422,9 @@ end
--- (Internal) Function to check if a unit is a C-130J
-- @param #CTLD self
function CTLD:IsC130J(Unit)
function CTLD:IsC130J(Unit, IgnoreUseC130Flag)
if not Unit then return false end
if not self.UseC130LoadAndUnload then return false end
if not IgnoreUseC130Flag and not self.UseC130LoadAndUnload then return false end
self.C130JUnits = self.C130JUnits or {}
local unitname = Unit:GetName() or "none"
return self.C130JUnits[unitname] == true
@@ -2447,10 +2450,16 @@ end
-- @return #CTLD_CARGO Cargo object, nil if it cannot be found
function CTLD:_FindTroopsCargoObject(Name)
self:T(self.lid .. " _FindTroopsCargoObject")
self._troopsByName = self._troopsByName or {}
local cached = self._troopsByName[Name]
if cached then
return cached
end
local cargo = nil
for _,_cargo in pairs(self.Cargo_Troops)do
local cargo = _cargo -- #CTLD_CARGO
if cargo.Name == Name then
self._troopsByName[Name] = cargo
return cargo
end
end
@@ -2463,16 +2472,23 @@ end
-- @return #CTLD_CARGO Cargo object, nil if it cannot be found
function CTLD:_FindCratesCargoObject(Name)
self:T(self.lid .. " _FindCratesCargoObject")
self._crateOrStaticByName = self._crateOrStaticByName or {}
local cached = self._crateOrStaticByName[Name]
if cached then
return cached
end
local cargo = nil
for _,_cargo in pairs(self.Cargo_Crates)do
local cargo = _cargo -- #CTLD_CARGO
if cargo.Name == Name then
self._crateOrStaticByName[Name] = cargo
return cargo
end
end
for _,_cargo in pairs(self.Cargo_Statics)do
local cargo = _cargo -- #CTLD_CARGO
if cargo.Name == Name then
self._crateOrStaticByName[Name] = cargo
return cargo
end
end
@@ -2598,6 +2614,20 @@ function CTLD:PreloadCrates(Unit,Cratesname,NumberOfCrates)
return self
end
--- (User) Hook to allow mission-specific troop restrictions.
-- Override this in your mission to perform custom checks (e.g. warehouse stock, role limits) before troops are loaded.
-- Return true to allow the request, or false to block it. When blocked, _LoadTroops and _LoadTroopsQuantity exit silently.
-- @param #CTLD self
-- @param Wrapper.Group#GROUP Group Requesting player group.
-- @param Wrapper.Unit#UNIT Unit Requesting unit.
-- @param #CTLD_CARGO Cargo Troop cargo type being requested.
-- @param #number quantity Number of troop sets requested.
-- @param #boolean Inject If true, this call originates from an inject/preload path.
-- @return #boolean Allow troop loading.
function CTLD:CanGetTroops(Group, Unit, Cargo, quantity, Inject)
return true
end
--- (Internal) Function to load troops into a heli.
-- @param #CTLD self
-- @param Wrapper.Group#GROUP Group
@@ -2668,6 +2698,9 @@ function CTLD:_LoadTroops(Group, Unit, Cargotype, Inject)
self:_SendMessage("Sorry, that\'s too heavy to load!", 10, false, Group)
return
else
if not self:CanGetTroops(Group, Unit, Cargotype, 1, Inject) then
return self
end
self.CargoCounter = self.CargoCounter + 1
local loadcargotype = CTLD_CARGO:New(self.CargoCounter, Cargotype.Name, Cargotype.Templates, cgotype, true, true, Cargotype.CratesNeeded,nil,nil,Cargotype.PerCrateMass)
self:T({cargotype=loadcargotype})
@@ -2987,6 +3020,8 @@ function CTLD:_LoadTroopsQuantity(Group, Unit, Cargo, quantity)
if not self.debug then return self end
end
if not self:CanGetTroops(Group, Unit, Cargo, n, false) then return self end
local prevSuppress = self.suppressmessages
self.suppressmessages = true
for i = 1, n do
@@ -3141,26 +3176,40 @@ function CTLD:_AddCrateQuantityMenus(Group, Unit, parentMenu, cargoObj, stockSum
maxQuantity = maxMassSets
end
end
if type(maxload)=="number"and maxload>0 and perCrateMass>0 then
maxMassCrates=math.floor(maxload/perCrateMass)
if type(maxload) == "number" and maxload > 0 and perCrateMass > 0 then
maxMassCrates = math.floor(maxload / perCrateMass)
end
end
self:T("_AddCrateQuantityMenus maxQuantity "..maxQuantity.." allowLoad "..tostring(allowLoad))
self:T("_AddCrateQuantityMenus maxQuantity "..maxQuantity.." allowLoad "..tostring(allowLoad))
if maxQuantity < 1 then
return self
end
if maxQuantity == 1 then
self:T("_AddCrateQuantityMenus maxQuantity "..maxQuantity.." Menu for MaxQ=1 ".."parentMenu.MenuText = "..parentMenu.MenuText)
--parentMenu.MenuText
MENU_GROUP_COMMAND:New(Group, "Get", parentMenu, self._GetCrateQuantity, self, Group, Unit, cargoObj, 1)
local canLoad = (allowLoad and (not capacitySets or capacitySets >= 1) and (not maxMassSets or maxMassSets >= 1))
local isHerc = self:IsC130J(Unit)
local isHook = self:IsHook(Unit)
local cgotype = cargoObj:GetType() or nil
local suppressGetAndLoad = (self.enableChinookGCLoading == true) and isHook and (cgotype == CTLD_CARGO.Enum.STATIC)
local canPartiallyLoad=((not capacityCrates or capacityCrates>=1)and(not maxMassCrates or maxMassCrates>=1))
local suppressGetAndLoad = (self.enableChinookGCLoading == true) and (cgotype == CTLD_CARGO.Enum.STATIC)
local canPartiallyLoad = ((not capacityCrates or capacityCrates >= 1) and (not maxMassCrates or maxMassCrates >= 1))
if suppressGetAndLoad or isHerc then
if canLoad then
MENU_GROUP_COMMAND:New(Group, "1", parentMenu, self._GetCrateQuantity, self, Group, Unit, cargoObj, 1)
else
local msg
if maxMassSets and (not capacitySets or capacitySets >= 1) and maxMassSets < 1 then
msg = "Weight limit reached"
else
msg = "Crate limit reached"
end
MENU_GROUP_COMMAND:New(Group, msg, parentMenu, self._SendMessage, self, msg, 10, false, Group)
end
return self
end
if canLoad and not isHerc and not suppressGetAndLoad then
MENU_GROUP_COMMAND:New(Group, "Get", parentMenu, self._GetCrateQuantity, self, Group, Unit, cargoObj, 1)
MENU_GROUP_COMMAND:New(Group, "Get and Load", parentMenu, self._GetAndLoad, self, Group, Unit, cargoObj, 1)
else
local msg
@@ -3171,13 +3220,14 @@ function CTLD:_AddCrateQuantityMenus(Group, Unit, parentMenu, cargoObj, stockSum
msg = "Crate limit reached"
end
MENU_GROUP_COMMAND:New(Group, msg, parentMenu, self._SendMessage, self, msg, 10, false, Group)
if canPartiallyLoad and (cgotype ~= CTLD_CARGO.Enum.STATIC) and (not suppressGetAndLoad) then
MENU_GROUP_COMMAND:New(Group, "Partially load", parentMenu, self._GetAndLoad, self, Group, Unit, cargoObj, 1,true)
MENU_GROUP_COMMAND:New(Group, "Get anyway", parentMenu, self._GetCrateQuantity, self, Group, Unit, cargoObj, 1)
MENU_GROUP_COMMAND:New(Group, "Partially load", parentMenu, self._GetAndLoad, self, Group, Unit, cargoObj, 1, true)
end
end
end
return self
end
@@ -3185,29 +3235,17 @@ function CTLD:_AddCrateQuantityMenus(Group, Unit, parentMenu, cargoObj, stockSum
self:T("_AddCrateQuantityMenus maxQuantity "..maxQuantity.." Menu for MaxQ>1")
local label = tostring(quantity)
self:T("_AddCrateQuantityMenus Label "..label)
local qMenu = MENU_GROUP:New(Group, label, parentMenu)
MENU_GROUP_COMMAND:New(Group, "Get", qMenu, self._GetCrateQuantity, self, Group, Unit, cargoObj, quantity)
local canLoad = (allowLoad and (not capacitySets or capacitySets >= quantity) and (not maxMassSets or maxMassSets >= quantity))
local isHerc = self:IsC130J(Unit)
local isHook = self:IsHook(Unit)
local cgotype = cargoObj:GetType() or nil
local suppressGetAndLoad = (self.enableChinookGCLoading == true) and isHook and (cgotype == CTLD_CARGO.Enum.STATIC)
local canPartiallyLoad=((not capacityCrates or capacityCrates>=1)and(not maxMassCrates or maxMassCrates>=1))
if canLoad and not isHerc and not suppressGetAndLoad then
local suppressGetAndLoad = (self.enableChinookGCLoading == true) and (cgotype == CTLD_CARGO.Enum.STATIC)
if canLoad and not isHerc and not suppressGetAndLoad then
local qMenu = MENU_GROUP:New(Group, label, parentMenu)
MENU_GROUP_COMMAND:New(Group, "Get", qMenu, self._GetCrateQuantity, self, Group, Unit, cargoObj, quantity)
MENU_GROUP_COMMAND:New(Group, "Get and Load", qMenu, self._GetAndLoad, self, Group, Unit, cargoObj, quantity)
else
local msg
if not isHerc and not suppressGetAndLoad then
if maxMassSets and (not capacitySets or capacitySets >= quantity) and maxMassSets < quantity then
msg = "Weight limit reached"
else
msg = "Crate limit reached"
end
MENU_GROUP_COMMAND:New(Group, msg, qMenu, self._SendMessage, self, msg, 10, false, Group)
if canPartiallyLoad and (cgotype ~= CTLD_CARGO.Enum.STATIC) and (not suppressGetAndLoad) then
MENU_GROUP_COMMAND:New(Group, "Partially load", qMenu, self._GetAndLoad, self, Group, Unit, cargoObj, quantity, true)
end
end
MENU_GROUP_COMMAND:New(Group, label, parentMenu, self._GetCrateQuantity, self, Group, Unit, cargoObj, quantity)
end
end
return self
@@ -3374,7 +3412,6 @@ end
function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppressGetEvent)
self:T(self.lid .. " _GetCrates")
-- check if we have stock
local perSet = Cargo:GetCratesNeeded() or 1
if perSet < 1 then perSet = 1 end
local requestNumber = tonumber(number)
@@ -3387,39 +3424,37 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress
local requestedSets = math.floor((requestNumber + perSet - 1) / perSet)
if requestedSets < 1 then requestedSets = 1 end
if not drop and not pack then
local cgoname = self:_GetCargoDisplayName(Cargo)
local cgoname = Cargo:GetName()
local instock = Cargo:GetStock()
if type(instock) == "number" and tonumber(instock) <= 0 and tonumber(instock) ~= -1 then
-- nothing left over
self:_SendMessage(string.format("Sorry, we ran out of %s", cgoname), 10, false, Group)
return false
end
end
-- check if we are in LOAD zone
local inzone = false
local inzone = false
local drop = drop or false
local suppressGetEvent = suppressGetEvent or false
local ship = nil
local width = 20
local distance = nil
local zone = nil
if not drop and not pack then
inzone = self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD)
if not drop and not pack then
inzone = self:IsUnitInZone(Unit, CTLD.CargoZoneType.LOAD)
if not inzone then
---@diagnostic disable-next-line: cast-local-type
inzone, ship, zone, distance, width = self:IsUnitInZone(Unit,CTLD.CargoZoneType.SHIP)
inzone, ship, zone, distance, width = self:IsUnitInZone(Unit, CTLD.CargoZoneType.SHIP)
end
elseif drop and not pack then
if self.dropcratesanywhere then -- #1570
inzone = true
else
inzone = self:IsUnitInZone(Unit,CTLD.CargoZoneType.DROP)
inzone = self:IsUnitInZone(Unit, CTLD.CargoZoneType.DROP)
end
elseif pack and not drop then
inzone = true
end
if not inzone then
self:_SendMessage("You are not close enough to a logistics zone!", 10, false, Group)
if not self.debug then return self end
@@ -3442,7 +3477,7 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
local canloadcratesno = capabilities.cratelimit
local loaddist = self.CrateDistance or 35
local nearcrates, numbernearby = self:_FindCratesNearby(Group,Unit,loaddist,true,true,true) -- to ignore what's inside
local nearcrates, numbernearby = self:_FindCratesNearby(Group, Unit, loaddist, true, true, true)
if numbernearby >= canloadcratesno and not drop then
self:_SendMessage("There are enough crates nearby already! Take care of those first!", 10, false, Group)
return false
@@ -3454,6 +3489,7 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress
-- spawn crates in front of helicopter
local IsHerc = self:IsFixedWing(Unit) -- Herc, Bronco and Hook load from behind
local IsHook = self:IsHook(Unit) -- Herc, Bronco and Hook load from behind
local IsHelo = Unit and Unit.IsHelicopter and Unit:IsHelicopter() or false
local IsTruck = Unit:IsGround()
local cargotype = Cargo -- Ops.CTLD#CTLD_CARGO
local number = requestNumber --#number
@@ -3483,89 +3519,204 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress
-- spawn behind the Herc
addon = 180
end
heading = (heading+addon)%360
heading = (heading + addon) % 360
local row = 1
local column = 1
local initialdist = IsHerc and 16 or (capabilities.length+2) -- initial spacing of the first crates
local startpos = position:Translate(initialdist,heading)
local initialdist = IsHerc and 16 or (capabilities.length + 2)
local startpos = position:Translate(initialdist, heading)
if self.placeCratesAhead == true then
cratedistance = initialdist
end
-- loop crates needed
local cratecoord = nil -- Core.Point#COORDINATE
for i=1,number do
local cratealias = string.format("%s-%s-%d", cratename, cratetemplate, math.random(1,100000))
if not self.placeCratesAhead or drop == true then
cratedistance = (i-1)*2.5 + capabilities.length
if cratedistance > self.CrateDistance then cratedistance = self.CrateDistance end
-- altered heading logic
-- DONE: right standard deviation?
if self:IsUnitInAir(Unit) and self:IsFixedWing(Unit) then
rheading = math.random(20,60)
else
rheading = UTILS.RandomGaussian(0, 30, -90, 90, 100)
end
rheading=math.fmod((heading+rheading),360)
cratecoord = position:Translate(cratedistance,rheading)
else
cratedistance = (row-1)*6
rheading = 90
row = row+1
cratecoord = startpos:Translate(cratedistance,rheading)
if row > 4 then
row = 1
startpos:Translate(6,heading,nil,true)
end
local cratecoord = nil
local shipdist = nil
local shipoffset = nil
local FW_STEP_BY_TYPE = {
cds_crate = 2.0,
cds_barrels = 2.0,
ammo_cargo = 1.0,
iso_container_small = 3.5,
iso_container = 3.5,
uh1h_cargo = 2.0,
container_cargo = 2.5,
}
local FW_WIDTH_BY_TYPE = { -- spacing between crates in the set.
cds_crate = 0.8,
cds_barrels = 0.8,
ammo_cargo = 0.4,
iso_container_small = 2.0,
iso_container = 2.0,
uh1h_cargo = 0.6,
container_cargo = 1.3,
}
local FW_ROW_GAP = 0.6
local FW_BATCH_ANGLE_PATTERN = { 0, -20, 20, -40, 40, -60, 60, -80, 80 }
local fwBatchState = nil
local fwBatchIndex = 0
local fwBatchKey = nil
if IsHerc or IsHelo then
self._fwBatchState = self._fwBatchState or {}
fwBatchKey = (Unit and Unit.GetName and Unit:GetName()) or "FW"
fwBatchState = self._fwBatchState[fwBatchKey] or { batch = 0 }
if (tonumber(numbernearby) or 0) <= 0 then
fwBatchState.batch = 0
end
--local cratevec2 = cratecoord:GetVec2()
self.CrateCounter = self.CrateCounter + 1
fwBatchIndex = fwBatchState.batch or 0
end
local fwZeroAngleSetHeading = nil
local fwNonZeroAngleSetHeading = nil
for i = 1, number do
local currentAngleOffset = 0
local cratealias = string.format("%s-%d", cratename, math.random(1, 100000))
local CCat, CType, CShape = Cargo:GetStaticTypeAndShape()
local basetype = CType or self.basetype or "container_cargo"
CCat = CCat or "Cargos"
if not isstatic and self:IsC130J(Unit) then
if not isstatic and self:IsC130J(Unit, true) then
if Cargo.C130TypeName then
basetype = Cargo.C130TypeName
elseif self.C130basetype and (not CType or CType == self.basetype) then
basetype = self.C130basetype
end
end
if not self.placeCratesAhead or drop == true then
local step = (IsHerc or IsHelo) and (FW_STEP_BY_TYPE[basetype] or 2.6) or 1.6
if (IsHerc or IsHelo) and not drop then
local safeDistance = capabilities.length * 0.9
local maxDist = self.CrateDistance or 35
if safeDistance > maxDist then safeDistance = maxDist end
local angleIndex = (fwBatchIndex % #FW_BATCH_ANGLE_PATTERN) + 1
currentAngleOffset = FW_BATCH_ANGLE_PATTERN[angleIndex] or 0
local centerHeading = math.fmod((heading + currentAngleOffset), 360)
if math.abs(currentAngleOffset) >= 0.01 and not fwNonZeroAngleSetHeading then
fwNonZeroAngleSetHeading = centerHeading
end
local baseDistance = safeDistance
local crateWidth = FW_WIDTH_BY_TYPE[basetype] or step
local zeroAngle = math.abs(currentAngleOffset) < 0.01
local lateral = nil
local lateralHeading = nil
if zeroAngle then
local totalRowWidth = (number * crateWidth) + (math.max(0, number - 1) * FW_ROW_GAP)
local leftEdge = -(totalRowWidth / 2)
lateral = leftEdge + ((i - 1) * (crateWidth + FW_ROW_GAP)) + (crateWidth / 2)
if lateral >= 0 then
lateralHeading = math.fmod(centerHeading + 90, 360)
else
lateral = -lateral
lateralHeading = math.fmod(centerHeading + 270, 360)
end
else
lateral = (i - 1) * (crateWidth + FW_ROW_GAP)
if currentAngleOffset < 0 then
lateralHeading = math.fmod(centerHeading + 270, 360)
else
lateralHeading = math.fmod(centerHeading + 90, 360)
end
end
local maxLateralSq = (maxDist * maxDist) - (baseDistance * baseDistance)
if maxLateralSq < 0 then maxLateralSq = 0 end
local maxLateral = math.sqrt(maxLateralSq)
if lateral > maxLateral then
lateral = maxLateral
end
local baseCoord = position:Translate(baseDistance, centerHeading)
cratecoord = baseCoord:Translate(lateral, lateralHeading)
cratedistance = baseDistance
rheading = centerHeading
else
cratedistance = (i - 1) * step + capabilities.length
if cratedistance > self.CrateDistance then cratedistance = self.CrateDistance end
rheading = UTILS.RandomGaussian(0, 18, -55, 55, 100)
rheading = math.fmod((heading + rheading), 360)
cratecoord = position:Translate(cratedistance, rheading)
end
else
cratedistance = (row - 1) * 6
rheading = 90
row = row + 1
cratecoord = startpos:Translate(cratedistance, rheading)
if row > 4 then
row = 1
startpos:Translate(6, heading, nil, true)
end
end
self.CrateCounter = self.CrateCounter + 1
local crateSpawnHeading = 270
if (IsHerc or IsHelo) and not drop and cratecoord and type(ship) ~= "string" then
if math.abs(currentAngleOffset) < 0.01 then
if not fwZeroAngleSetHeading then
fwZeroAngleSetHeading = heading
end
crateSpawnHeading = fwZeroAngleSetHeading
else
crateSpawnHeading = fwNonZeroAngleSetHeading
end
end
if type(ship) == "string" then
self:T("Spawning on ship "..ship)
local Ship = UNIT:FindByName(ship)
local shipcoord = Ship:GetCoordinate()
local unitcoord = Unit:GetCoordinate()
local dist = shipcoord:Get2DDistance(unitcoord)
dist = dist - (20 + math.random(1,10))
local width = width / 2
local Offy = math.random(-width,width)
local spawnstatic = SPAWNSTATIC:NewFromType(basetype,CCat,self.cratecountry)
:InitCargoMass(cgomass)
:InitCargo(self.enableslingload)
:InitLinkToUnit(Ship,dist,Offy,0)
dist = dist - (20 + math.random(1, 10))
local halfwidth = (width or 20) / 2
local Offy = nil
if i == 1 or shipdist == nil or shipoffset == nil then
Offy = math.random(-halfwidth, halfwidth)
shipoffset = Offy
shipdist = dist
else
dist = shipdist
local step = math.max(1, math.min(3, halfwidth * 0.2))
local slot = i - 1
local ring = math.floor((slot + 1) / 2)
local sign = (slot % 2 == 1) and 1 or -1
Offy = shipoffset + (sign * ring * step)
if Offy > halfwidth then
Offy = halfwidth
elseif Offy < -halfwidth then
Offy = -halfwidth
end
end
local spawnstatic = SPAWNSTATIC:NewFromType(basetype, CCat, self.cratecountry)
:InitCargoMass(cgomass)
:InitCargo(self.enableslingload)
:InitLinkToUnit(Ship, dist, Offy, 0)
if CShape then
spawnstatic:InitShape(CShape)
end
end
if isstatic then
local map=cargotype:GetStaticResourceMap()
local map = cargotype:GetStaticResourceMap()
spawnstatic.TemplateStaticUnit.resourcePayload = map
end
self.Spawned_Crates[self.CrateCounter] = spawnstatic:Spawn(270,cratealias)
else
local spawnstatic = SPAWNSTATIC:NewFromType(basetype,CCat,self.cratecountry)
self.Spawned_Crates[self.CrateCounter] = spawnstatic:Spawn(crateSpawnHeading, cratealias)
else
local spawnstatic = SPAWNSTATIC:NewFromType(basetype, CCat, self.cratecountry)
:InitCoordinate(cratecoord)
:InitCargoMass(cgomass)
:InitCargo(self.enableslingload)
if CShape then
spawnstatic:InitShape(CShape)
end
end
if isstatic then
local map=cargotype:GetStaticResourceMap()
local map = cargotype:GetStaticResourceMap()
spawnstatic.TemplateStaticUnit.resourcePayload = map
end
self.Spawned_Crates[self.CrateCounter] = spawnstatic:Spawn(270,cratealias)
self.Spawned_Crates[self.CrateCounter] = spawnstatic:Spawn(crateSpawnHeading, cratealias)
end
local templ = cargotype:GetTemplates()
local sorte = cargotype:GetType()
local subcat = cargotype.Subcategory
@@ -3573,43 +3724,50 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress
local realcargo = nil
if drop then
--CTLD_CARGO:New(ID, Name, Templates, Sorte, HasBeenMoved, LoadDirectly, CratesNeeded, Positionable, Dropped, PerCrateMass, Stock, Subcategory)
realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,true,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],true,cargotype.PerCrateMass,nil,subcat) -- #CTLD_CARGO
realcargo = CTLD_CARGO:New(self.CargoCounter, cratename, templ, sorte, true, false, cratesneeded, self.Spawned_Crates[self.CrateCounter], true, cargotype.PerCrateMass, nil, subcat)
realcargo:SetDisplayName(cargotype:GetDisplayName())
local map=cargotype:GetStaticResourceMap()
local map = cargotype:GetStaticResourceMap()
realcargo:SetStaticResourceMap(map)
local CCat3, CType3, CShape3 = cargotype:GetStaticTypeAndShape()
realcargo:SetStaticTypeAndShape(CCat3,CType3,CShape3)
realcargo:SetStaticTypeAndShape(CCat3, CType3, CShape3)
if cargotype.TypeNames then
realcargo.TypeNames = UTILS.DeepCopy(cargotype.TypeNames)
end
table.insert(droppedcargo,realcargo)
table.insert(droppedcargo, realcargo)
else
realcargo = CTLD_CARGO:New(self.CargoCounter,cratename,templ,sorte,false,false,cratesneeded,self.Spawned_Crates[self.CrateCounter],false,cargotype.PerCrateMass,nil,subcat)
realcargo = CTLD_CARGO:New(self.CargoCounter, cratename, templ, sorte, false, false, cratesneeded, self.Spawned_Crates[self.CrateCounter], false, cargotype.PerCrateMass, nil, subcat)
realcargo:SetDisplayName(cargotype:GetDisplayName())
local map=cargotype:GetStaticResourceMap()
realcargo:SetStaticResourceMap(map)
local map = cargotype:GetStaticResourceMap()
realcargo:SetStaticResourceMap(map)
if cargotype.TypeNames then
realcargo.TypeNames = UTILS.DeepCopy(cargotype.TypeNames)
end
if self.UseC130LoadAndUnload and self:IsC130J(Unit) then
realcargo:SetWasDropped(true,true) -- we mark here that the crates was dropped even though we just got them because of the herc.
realcargo:SetWasDropped(true, true)
end
end
if not drop and not pack then
table.insert(obtainedcargo, realcargo)
end
local CCat4, CType4, CShape4 = cargotype:GetStaticTypeAndShape()
realcargo:SetStaticTypeAndShape(CCat4,CType4,CShape4)
realcargo:SetStaticTypeAndShape(CCat4, CType4, CShape4)
table.insert(self.Spawned_Cargo, realcargo)
end
if (IsHerc or IsHelo) and fwBatchState and fwBatchKey and not drop then
local maxBatches = #FW_BATCH_ANGLE_PATTERN
fwBatchState.batch = (fwBatchIndex + 1) % maxBatches
self._fwBatchState[fwBatchKey] = fwBatchState
end
if not (drop or pack) then
Cargo:RemoveStock(requestedSets)
self:_RefreshCrateQuantityMenus(Group, Unit, Cargo)
end
local text = string.format("%d crates for %s have been positioned near you!",number,cratedisplayname)
local text = string.format("%d crates for %s have been positioned near you!", number, cratedisplayname)
if drop then
text = string.format("%d crates for %s have been dropped!",number,cratedisplayname)
text = string.format("%d crates for %s have been dropped!", number, cratedisplayname)
self:__CratesDropped(1, Group, Unit, droppedcargo)
else
if not quiet then
@@ -3930,11 +4088,11 @@ function CTLD:_FindCratesNearby( _group, _unit, _dist, _ignoreweight, ignoretype
end
end
self:T(self.lid..string.format("Dist %dm/%dm | weight %dkg | maxloadable %dkg",distance,finddist,weight,maxloadable))
if distance<=finddist and(weight<=maxloadable or _ignoreweight)and restricted==false and cando==true and not hercInnerBlocked then
index = index + 1
table.insert(found, staticid, cargo)
maxloadable = maxloadable - weight
end
if distance<=finddist and(weight<=maxloadable or _ignoreweight)and restricted==false and cando==true and not hercInnerBlocked then
index = index + 1
found[#found+1] = cargo
maxloadable = maxloadable - weight
end
end
end
@@ -4081,22 +4239,21 @@ end
function CTLD:_CleanupTrackedCrates(crateIdsToRemove)
local existingcrates = self.Spawned_Cargo -- #table
local newexcrates = {}
local remove = {}
for _,_ID in pairs(crateIdsToRemove or {}) do
remove[_ID] = true
end
for _,_crate in pairs(existingcrates) do
local excrate = _crate -- #CTLD_CARGO
local ID = excrate:GetID()
local keep = true
for _,_ID in pairs(crateIdsToRemove) do
if ID == _ID then
keep = false
end
end
local keep = not remove[ID]
-- remove destroyed crates here too
local static = _crate:GetPositionable() -- Wrapper.Static#STATIC -- crates
if not static or not static:IsAlive() then
keep = false
end
if keep then
table.insert(newexcrates,_crate)
newexcrates[#newexcrates+1] = _crate
end
end
self.Spawned_Cargo = nil
@@ -6819,6 +6976,16 @@ function CTLD:AddTroopsCargo(Name,Templates,Type,NoTroops,PerTroopMass,Stock,Sub
-- Troops are directly loadable
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,Templates,Type,false,true,NoTroops,nil,nil,PerTroopMass,Stock, SubCategory)
table.insert(self.Cargo_Troops,cargo)
self._troopsByName = self._troopsByName or {}
self._troopsByName[cargo.Name] = cargo
self._cargoByTemplate = self._cargoByTemplate or {}
local _template = cargo.Templates
if type(_template) == "table" then
_template = _template[1]
end
if type(_template) == "string" and _template ~= "" then
self._cargoByTemplate[_template] = cargo
end
if SubCategory and self.usesubcats ~= true then self.usesubcats=true end
return self
end
@@ -6916,6 +7083,16 @@ function CTLD:AddCratesCargo(Name,Templates,Type,NoCrates,PerCrateMass,Stock,Sub
end
cargo.C130TypeName = C130TypeName
table.insert(self.Cargo_Crates,cargo)
self._crateOrStaticByName = self._crateOrStaticByName or {}
self._crateOrStaticByName[cargo.Name] = cargo
self._cargoByTemplate = self._cargoByTemplate or {}
local _template = cargo.Templates
if type(_template) == "table" then
_template = _template[1]
end
if type(_template) == "string" and _template ~= "" then
self._cargoByTemplate[_template] = cargo
end
if SubCategory and self.usesubcats ~= true then self.usesubcats=true end
return self
end
@@ -6956,6 +7133,16 @@ function CTLD:AddCratesCargoNoMove(Name,Templates,Type,NoCrates,PerCrateMass,Sto
end
cargo.C130TypeName = C130TypeName
table.insert(self.Cargo_Crates,cargo)
self._crateOrStaticByName = self._crateOrStaticByName or {}
self._crateOrStaticByName[cargo.Name] = cargo
self._cargoByTemplate = self._cargoByTemplate or {}
local _template = cargo.Templates
if type(_template) == "table" then
_template = _template[1]
end
if type(_template) == "string" and _template ~= "" then
self._cargoByTemplate[_template] = cargo
end
self.templateToCargoName = self.templateToCargoName or {}
if type(Templates)=="table" then
for _,t in pairs(Templates) do self.templateToCargoName[t] = Name end
@@ -6982,7 +7169,7 @@ end
function CTLD:AddStaticsCargo(Name,Mass,Stock,SubCategory,DontShowInMenu,Location,UnitTypes,DisplayName)
self:T(self.lid .. " AddStaticsCargo")
self.CargoCounter = self.CargoCounter + 1
local type = CTLD_CARGO.Enum.STATIC
local cargotype = CTLD_CARGO.Enum.STATIC
local template = STATIC:FindByName(Name,true):GetTypeName()
local unittemplate = _DATABASE:GetStaticUnitTemplate(Name)
local ResourceMap = nil
@@ -6990,13 +7177,23 @@ function CTLD:AddStaticsCargo(Name,Mass,Stock,SubCategory,DontShowInMenu,Locatio
ResourceMap = UTILS.DeepCopy(unittemplate.resourcePayload)
end
-- Crates are not directly loadable
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,Stock,SubCategory,DontShowInMenu,Location)
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,cargotype,false,false,1,nil,nil,Mass,Stock,SubCategory,DontShowInMenu,Location)
if UnitTypes then
cargo:AddUnitTypeName(UnitTypes)
end
cargo:SetDisplayName(DisplayName or Name)
cargo:SetStaticResourceMap(ResourceMap)
table.insert(self.Cargo_Statics,cargo)
self._crateOrStaticByName = self._crateOrStaticByName or {}
self._crateOrStaticByName[cargo.Name] = cargo
self._cargoByTemplate = self._cargoByTemplate or {}
local _template = cargo.Templates
if type(_template) == "table" then
_template = _template[1]
end
if type(_template) == "string" and _template ~= "" then
self._cargoByTemplate[_template] = cargo
end
if SubCategory and self.usesubcats ~= true then self.usesubcats=true end
return cargo
end
@@ -7020,9 +7217,9 @@ end
function CTLD:AddStaticsCargoFromType(Name,TypeName,Mass,Stock,SubCategory,DontShowInMenu,Location,UnitTypes,Category,ShapeName,ResourceMap,DisplayName)
self:T(self.lid .. " AddStaticsCargoFromType")
self.CargoCounter = self.CargoCounter + 1
local type = CTLD_CARGO.Enum.STATIC
local cargotype = CTLD_CARGO.Enum.STATIC
local template = TypeName or self.basetype or "container_cargo"
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,Stock,SubCategory,DontShowInMenu,Location)
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,cargotype,false,false,1,nil,nil,Mass,Stock,SubCategory,DontShowInMenu,Location)
if UnitTypes then
cargo:AddUnitTypeName(UnitTypes)
end
@@ -7033,6 +7230,16 @@ function CTLD:AddStaticsCargoFromType(Name,TypeName,Mass,Stock,SubCategory,DontS
end
cargo:SetStaticResourceMap(ResourceMap)
table.insert(self.Cargo_Statics,cargo)
self._crateOrStaticByName = self._crateOrStaticByName or {}
self._crateOrStaticByName[cargo.Name] = cargo
self._cargoByTemplate = self._cargoByTemplate or {}
local _template = cargo.Templates
if type(_template) == "table" then
_template = _template[1]
end
if type(_template) == "string" and _template ~= "" then
self._cargoByTemplate[_template] = cargo
end
if SubCategory and self.usesubcats ~= true then self.usesubcats=true end
return cargo
end
@@ -7046,7 +7253,7 @@ end
function CTLD:GetStaticsCargoFromTemplate(Name,Mass,DisplayName)
self:T(self.lid .. " GetStaticsCargoFromTemplate")
self.CargoCounter = self.CargoCounter + 1
local type = CTLD_CARGO.Enum.STATIC
local cargotype = CTLD_CARGO.Enum.STATIC
local template = STATIC:FindByName(Name,true):GetTypeName()
local unittemplate = _DATABASE:GetStaticUnitTemplate(Name)
local ResourceMap = nil
@@ -7054,7 +7261,7 @@ function CTLD:GetStaticsCargoFromTemplate(Name,Mass,DisplayName)
ResourceMap = UTILS.DeepCopy(unittemplate.resourcePayload)
end
-- Crates are not directly loadable
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,1)
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,cargotype,false,false,1,nil,nil,Mass,1)
cargo:SetDisplayName(DisplayName or Name)
cargo:SetStaticResourceMap(ResourceMap)
--table.insert(self.Cargo_Statics,cargo)
@@ -7074,9 +7281,9 @@ end
function CTLD:GetStaticsCargoFromType(Name,TypeName,Mass,Category,ShapeName,ResourceMap,DisplayName)
self:T(self.lid .. " GetStaticsCargoFromType")
self.CargoCounter = self.CargoCounter + 1
local type = CTLD_CARGO.Enum.STATIC
local cargotype = CTLD_CARGO.Enum.STATIC
local template = TypeName or self.basetype or "container_cargo"
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,type,false,false,1,nil,nil,Mass,1)
local cargo = CTLD_CARGO:New(self.CargoCounter,Name,template,cargotype,false,false,1,nil,nil,Mass,1)
cargo:SetStaticTypeAndShape(Category or "Cargos", template, ShapeName)
cargo:SetDisplayName(DisplayName or Name)
if ResourceMap then
@@ -7119,6 +7326,16 @@ function CTLD:AddCratesRepair(Name,Template,Type,NoCrates, PerCrateMass,Stock,Su
cargo:SetStaticTypeAndShape(Category,TypeName,ShapeName)
end
table.insert(self.Cargo_Crates,cargo)
self._crateOrStaticByName = self._crateOrStaticByName or {}
self._crateOrStaticByName[cargo.Name] = cargo
self._cargoByTemplate = self._cargoByTemplate or {}
local _template = cargo.Templates
if type(_template) == "table" then
_template = _template[1]
end
if type(_template) == "string" and _template ~= "" then
self._cargoByTemplate[_template] = cargo
end
return self
end
@@ -8556,11 +8773,17 @@ end
template = string.gsub(GroupName,"#(%d+)$","")
end
template = string.gsub(template,"-(%d+)$","")
self._cargoByTemplate = self._cargoByTemplate or {}
local cached = self._cargoByTemplate[template]
if cached and cached.CargoType ~= CTLD_CARGO.Enum.REPAIR then
return cached
end
for k,v in pairs(self.Cargo_Troops) do
local comparison = ""
if type(v.Templates) == "string" then comparison = v.Templates else comparison = v.Templates[1] end
if comparison == template then
Cargotype = v
self._cargoByTemplate[template] = v
break
end
end
@@ -8570,6 +8793,7 @@ end
if type(v.Templates) == "string" then comparison = v.Templates else comparison = v.Templates[1] end
if comparison == template and v.CargoType ~= CTLD_CARGO.Enum.REPAIR then
Cargotype = v
self._cargoByTemplate[template] = v
break
end
end
@@ -8994,23 +9218,20 @@ end
-- @return #CTLD self
function CTLD:onafterStatus(From, Event, To)
self:T({From, Event, To})
-- gather some stats
-- pilots
local pilots = 0
for _,_pilot in pairs (self.CtldUnits) do
pilots = pilots + 1
end
-- spawned cargo boxes curr in field
local boxes = 0
for _,_pilot in pairs (self.Spawned_Cargo) do
boxes = boxes + 1
end
local cc = self.CargoCounter
local tc = self.TroopCounter
if self.debug or self.verbose > 0 then
-- gather stats only when logging is enabled
local pilots = 0
for _,_pilot in pairs (self.CtldUnits) do
pilots = pilots + 1
end
local boxes = 0
for _,_pilot in pairs (self.Spawned_Cargo) do
boxes = boxes + 1
end
local cc = self.CargoCounter
local tc = self.TroopCounter
local text = string.format("%s Pilots %d | Live Crates %d |\nCargo Counter %d | Troop Counter %d", self.lid, pilots, boxes, cc, tc)
local m = MESSAGE:New(text,10,"CTLD"):ToAll()
if self.verbose > 0 then