From f3f0dd0ec524036161bcb98cd42cab82a928d48d Mon Sep 17 00:00:00 2001 From: leka1986 <83298840+leka1986@users.noreply.github.com> Date: Sun, 6 Sep 2026 10:45:54 +0200 Subject: [PATCH] Refactor cargo handling logic and parameters in CTLD **CTLD improvements** - Changed cargo, hover, zone, repair, and menu checks to reuse existing data and skip unnecessary work. - Fixed spacing between simultaneous builds of different cargo types. - Added `NoMoveToZone` support by passing true at the end in `AddTroopsCargo` - Other fixes and tweaks. --- Moose Development/Moose/Ops/CTLD.lua | 278 +++++++++++++++------------ 1 file changed, 151 insertions(+), 127 deletions(-) diff --git a/Moose Development/Moose/Ops/CTLD.lua b/Moose Development/Moose/Ops/CTLD.lua index 44ab8a1de..69a028676 100644 --- a/Moose Development/Moose/Ops/CTLD.lua +++ b/Moose Development/Moose/Ops/CTLD.lua @@ -841,7 +841,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 = 2, trooplimit = 2, length = 16, cargoweightlimit = 3000}, -- 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 = 3500}, -- 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 @@ -3132,12 +3132,14 @@ function CTLD:_FindRepairNearby(Group, Unit, Repairtype) local nearestDistance = 10000 for k,v in pairs(self.DroppedTroops) do local distance = self:_GetDistance(v:GetCoord(),unitcoord) - local unit = v:GetUnit(1) -- Wrapper.Unit#UNIT - local desc = unit:GetDesc() or nil - if distance < nearestDistance and distance ~= -1 and not desc.attributes.Infantry then - nearestGroup = v - nearestGroupIndex = k - nearestDistance = distance + if distance < nearestDistance and distance ~= -1 and distance <= self.EngineerSearch then + local unit = v:GetUnit(1) -- Wrapper.Unit#UNIT + local desc = unit:GetDesc() or nil + if not desc.attributes.Infantry then + nearestGroup = v + nearestGroupIndex = k + nearestDistance = distance + end end end @@ -3566,8 +3568,9 @@ function CTLD:_AddCrateQuantityMenus(Group, Unit, parentMenu, cargoObj, stockSum end local capacitySets = nil local capacityCrates = nil + local capabilities if Unit then - local capabilities = self:_GetUnitCapabilities(Unit) + capabilities = self:_GetUnitCapabilities(Unit) local capacity = capabilities and capabilities.cratelimit or 0 if capacity > 0 then local loadedData = nil @@ -3602,7 +3605,7 @@ function CTLD:_AddCrateQuantityMenus(Group, Unit, parentMenu, cargoObj, stockSum local maxMassSets = nil local maxMassCrates = nil if Unit then - local maxload = self:_GetMaxLoadableMass(Unit) + local maxload = self:_GetMaxLoadableMass(Unit, nil, capabilities) local perCrateMass = (cargoObj.GetMass and cargoObj:GetMass()) or cargoObj.PerCrateMass or 0 local setMass = perCrateMass * (needed > 0 and needed or 1) if type(maxload) == "number" and maxload > 0 and setMass > 0 then @@ -4009,8 +4012,8 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress container_cargo = 2.5, } local FW_WIDTH_BY_TYPE = { -- spacing between crates in the set. - cds_crate = 0.8, - cds_barrels = 0.8, + cds_crate = 0.7, + cds_barrels = 0.7, ammo_cargo = 0.4, iso_container_small = 2.0, iso_container = 2.0, @@ -4055,9 +4058,10 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack, quiet, suppress 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 + local step = (IsHerc or IsHelo) and (FW_STEP_BY_TYPE[basetype] or 2.6) or 1.5 if (IsHerc or IsHelo) and not drop then - local safeDistance = capabilities.length * 0.9 + -- Keep Chinook crates closer to the ramp; other aircraft keep their existing offset. + local safeDistance = capabilities.length * (IsHook and 0.75 or 0.9) local maxDist = self.CrateDistance or 35 if safeDistance > maxDist then safeDistance = maxDist end @@ -4503,10 +4507,11 @@ function CTLD:_GetDistance(_point1, _point2) self:T(self.lid .. " _GetDistance") if _point1 and _point2 then local distance1 = _point1:Get2DDistance(_point2) - local distance2 = _point1:DistanceFromPointVec2(_point2) if distance1 and type(distance1) == "number" then return distance1 - elseif distance2 and type(distance2) == "number" then + end + local distance2 = _point1:DistanceFromPointVec2(_point2) + if distance2 and type(distance2) == "number" then return distance2 else self:E("*****Cannot calculate distance!") @@ -4527,15 +4532,17 @@ end -- @param #number _dist Distance -- @param #boolean _ignoreweight Find everything in range, ignore loadable weight -- @param #boolean ignoretype Find everything in range, ignore loadable type name +-- @param #boolean ignoreHercInner Exclude crates close to the aircraft; C-130 exclusion requires UseC130LoadAndUnload. -- @return #table Crates Table of crates -- @return #number Number Number of crates found -- @return #table CratesGC Table of crates possibly loaded by GC -- @return #number NumberGC Number of crates possibly loaded by GC function CTLD:_FindCratesNearby( _group, _unit, _dist, _ignoreweight, ignoretype, ignoreHercInner) self:T(self.lid .. " _FindCratesNearby") + local existingcrates = self.Spawned_Cargo -- #table + if not next(existingcrates) then return {}, 0, {}, 0 end local finddist = _dist local location = _group:GetCoord() - local existingcrates = self.Spawned_Cargo -- #table -- cycle local index = 0 local indexg = 0 @@ -4543,7 +4550,7 @@ function CTLD:_FindCratesNearby( _group, _unit, _dist, _ignoreweight, ignoretype local LoadedbyGC = {} local loadedmass = 0 local unittype = "none" - local capabilities = {} + local innerDist --local maxmass = 2000 local maxloadable = 2000 local IsHook = self:IsHook(_unit) @@ -4565,18 +4572,25 @@ function CTLD:_FindCratesNearby( _group, _unit, _dist, _ignoreweight, ignoretype local restricted = cargoisstatic and restricthooktononstatics self:T(self.lid .. " Loading restricted: " .. tostring(restricted)) local staticpos = static:GetCoordinate() --or dcsunitpos - local cando = cargo:UnitCanCarry(_unit) - if ignoretype == true then cando = true restricted = false end + local cando = ignoretype == true or cargo:UnitCanCarry(_unit) + if ignoretype == true then restricted = false end self:T(self.lid .. " Unit can carry: " .. tostring(cando)) --- Testing local distance=self:_GetDistance(location,staticpos) local hercInnerBlocked=false - if self.UseC130LoadAndUnload and ignoreHercInner and _unit and self:IsC130J(_unit) then - local capabilities=self:_GetUnitCapabilities(_unit) -- #CTLD.UnitTypeCapabilities - local innerDist= capabilities.length and (capabilities.length/2) or 4 - if distance 0 then @@ -6640,19 +6670,17 @@ function CTLD:_RefreshQuantityMenusForGroup(_group, _unit) local g = u:GetGroup() if g then local caps = self:_GetUnitCapabilities(u) + local loaded = self.Loaded_Cargo[name] local needCrate, needTroop = false, false if g.CTLD_CrateMenus then local cap = caps.cratelimit or 0 + local avail = math.max(0, cap - ((loaded and loaded.Cratesloaded) or 0)) for item,_ in pairs(g.CTLD_CrateMenus) do local obj = self:_FindCratesCargoObject(item) if obj then local per = obj:GetCratesNeeded() or 1 if per < 1 then per = 1 end - local uname = u:GetName() or "none" - local cap = caps.cratelimit or 0 - local loaded = (self.Loaded_Cargo[uname] and self.Loaded_Cargo[uname].Cratesloaded) or 0 - local avail = math.max(0, cap - loaded) local unitAvail = math.max(0, math.min(self.maxCrateMenuQuantity or 1, math.floor(avail/per))) local s = obj:GetStock() if type(s)=="number" and s>=0 and s=0 and s= minheight then - return true + return true, aheight else - return false + return false, aheight end end @@ -9378,9 +9395,7 @@ end function CTLD:AutoHoverLoad(Unit) self:T(self.lid .. " AutoHoverLoad") -- get capabilities and current load - local unittype = Unit:GetTypeName() local unitname = Unit:GetName() - local Group = Unit:GetGroup() local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities local cancrates = capabilities.crates -- #boolean local cratelimit = capabilities.cratelimit -- #number @@ -9393,9 +9408,11 @@ end numberonboard = loaded.Cratesloaded or 0 end local load = cratelimit - numberonboard - local canload = self:CanHoverLoad(Unit) - if canload and load > 0 then - self:_LoadCratesNearby(Group,Unit) + if load > 0 then + local canload = self:CanHoverLoad(Unit) + if canload then + self:_LoadCratesNearby(Unit:GetGroup(),Unit,canload,capabilities,unitname) + end end end return self @@ -9408,7 +9425,7 @@ end if self.hoverautoloading then for _,_pilot in pairs (self.CtldUnits) do local Unit = UNIT:FindByName(_pilot) - if self:CanHoverLoad(Unit) then self:AutoHoverLoad(Unit) end + self:AutoHoverLoad(Unit) end end return self @@ -10149,7 +10166,8 @@ end :InitDelayOff() :OnSpawnGroup(function(grp,TimeStamp) grp.spawntime = TimeStamp or timer.getTime() end,TimeStamp) :SpawnFromVec2(randomcoord) - if self.movetroopstowpzone and type ~= CTLD_CARGO.Enum.ENGINEERS then + -- Saved cargo is recreated on load; reuse the registered cargo setting found above. + if self.movetroopstowpzone and type ~= CTLD_CARGO.Enum.ENGINEERS and not (CargoObject or cargo).NoMoveToZone then self:_MoveGroupToZone(self.DroppedTroops[self.TroopCounter]) end end -- template loop @@ -10624,7 +10642,11 @@ end function CTLD:onafterTroopsDeployed(From, Event, To, Group, Unit, Troops, Type) self:T({From, Event, To}) if self.movetroopstowpzone and Type ~= CTLD_CARGO.Enum.ENGINEERS then - self:_MoveGroupToZone(Troops) + -- Resolve the registered cargo through the existing template cache. + local cg = self:GetGenericCargoObjectFromGroupName(Troops:GetName()) + if not (cg and cg.NoMoveToZone) then + self:_MoveGroupToZone(Troops) + end if not Group or not Unit then self:_RefreshQuantityMenusForGroup() end end return self @@ -10871,7 +10893,7 @@ end --local data = "LoadedData = {\n" - local data = "Group,x,y,z,CargoName,CargoTemplates,CargoType,CratesNeeded,CrateMass,Structure,StaticCategory,StaticType,StaticShape,SpawnTime\n" + local data = "Group,x,y,z,CargoName,CargoTemplates,CargoType,CratesNeeded,CrateMass,Structure,StaticCategory,StaticType,StaticShape,SpawnTime,Latitude,Longitude\n" local n = 0 for _,_grp in pairs(grouptable) do local group = _grp -- Wrapper.Group#GROUP @@ -10916,8 +10938,10 @@ end end local location = group:GetVec3() - local txt = string.format("%s,%d,%d,%d,%s,%s,%s,%d,%d,%s,%s,%s,%s,%f\n" - ,template,location.x,location.y,location.z,cgoname,cgotemp,cgotype,cgoneed,cgomass,strucdata,scat,stype,sshape or "none",spawntime) + -- Append geographic coordinates for export; x/y/z remain the saved position used on load. + local lat,lon = coord.LOtoLL(location) + local txt = string.format("%s,%d,%d,%d,%s,%s,%s,%d,%d,%s,%s,%s,%s,%f,%f,%f\n" + ,template,location.x,location.y,location.z,cgoname,cgotemp,cgotype,cgoneed,cgomass,strucdata,scat,stype,sshape or "none",spawntime,lat,lon) data = data .. txt end end