Update CTLD.lua

Reworked the logic of the menu.
Now it will Show be shown :
1. Ammo truck
2. Humvee
3. Ammo truck 1/2 -- 1/2 due to incomplete set.

And for the troops

Squad 8 (2) -- 2 set of squad 8, Selecting this will only deploy 1 set.
Squad 16

Changed so when loading troops, it will state 
Squad 8 boarded. same for the extraction.

I have tested it and it works
Heart8reaker also tested it and no issues so far.
This commit is contained in:
leka1986 2025-02-09 23:41:16 +01:00 committed by GitHub
parent 1d08bcf2e0
commit cad8f15b61
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -2355,7 +2355,7 @@ function CTLD:_LoadTroops(Group, Unit, Cargotype, Inject)
loaded.Troopsloaded = loaded.Troopsloaded + troopsize loaded.Troopsloaded = loaded.Troopsloaded + troopsize
table.insert(loaded.Cargo,loadcargotype) table.insert(loaded.Cargo,loadcargotype)
self.Loaded_Cargo[unitname] = loaded self.Loaded_Cargo[unitname] = loaded
self:_SendMessage("Troops boarded!", 10, false, Group) self:_SendMessage(string.format("%s boarded!", cgoname), 10, false, Group)
self:_RefreshDropTroopsMenu(Group,Unit) self:_RefreshDropTroopsMenu(Group,Unit)
self:__TroopsPickedUp(1,Group, Unit, Cargotype) self:__TroopsPickedUp(1,Group, Unit, Cargotype)
self:_UpdateUnitCargoMass(Unit) self:_UpdateUnitCargoMass(Unit)
@ -2589,8 +2589,8 @@ end
loaded.Troopsloaded = loaded.Troopsloaded + troopsize loaded.Troopsloaded = loaded.Troopsloaded + troopsize
table.insert(loaded.Cargo,loadcargotype) table.insert(loaded.Cargo,loadcargotype)
self.Loaded_Cargo[unitname] = loaded self.Loaded_Cargo[unitname] = loaded
self:ScheduleOnce(running,self._SendMessage,self,"Troops boarded!", 10, false, Group) self:ScheduleOnce(running, self._SendMessage, self, string.format("%s boarded!", Cargotype.Name), 10, false, Group)
self:_SendMessage("Troops boarding!", 10, false, Group) self:_SendMessage(string.format("%s boarding!", Cargotype.Name), 10, false, Group)
self:_RefreshDropTroopsMenu(Group,Unit) self:_RefreshDropTroopsMenu(Group,Unit)
self:_UpdateUnitCargoMass(Unit) self:_UpdateUnitCargoMass(Unit)
local groupname = nearestGroup:GetName() local groupname = nearestGroup:GetName()
@ -3104,7 +3104,6 @@ function CTLD:_LoadCratesNearby(Group, Unit)
-- see if this heli can load crates -- see if this heli can load crates
local unittype = unit:GetTypeName() local unittype = unit:GetTypeName()
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
--local capabilities = self.UnitTypeCapabilities[unittype] -- #CTLD.UnitTypeCapabilities
local cancrates = capabilities.crates -- #boolean local cancrates = capabilities.crates -- #boolean
local cratelimit = capabilities.cratelimit -- #number local cratelimit = capabilities.cratelimit -- #number
local grounded = not self:IsUnitInAir(Unit) local grounded = not self:IsUnitInAir(Unit)
@ -3115,7 +3114,6 @@ function CTLD:_LoadCratesNearby(Group, Unit)
self:_SendMessage("You need to open the door(s) to load cargo!", 10, false, Group) self:_SendMessage("You need to open the door(s) to load cargo!", 10, false, Group)
if not self.debug then return self end if not self.debug then return self end
end end
--- cases ------------------------------- --- cases -------------------------------
-- Chopper can\'t do crates - bark & return -- Chopper can\'t do crates - bark & return
-- Chopper can do crates - -- Chopper can do crates -
@ -3131,53 +3129,54 @@ function CTLD:_LoadCratesNearby(Group, Unit)
else else
-- have we loaded stuff already? -- have we loaded stuff already?
local numberonboard = 0 local numberonboard = 0
local massonboard = 0
local loaded = {} local loaded = {}
if self.Loaded_Cargo[unitname] then if self.Loaded_Cargo[unitname] then
loaded = self.Loaded_Cargo[unitname] -- #CTLD.LoadedCargo loaded = self.Loaded_Cargo[unitname] -- #CTLD.LoadedCargo
numberonboard = loaded.Cratesloaded or 0 numberonboard = loaded.Cratesloaded or 0
massonboard = self:_GetUnitCargoMass(Unit)
else else
loaded = {} -- #CTLD.LoadedCargo loaded = {}
loaded.Troopsloaded = 0 loaded.Troopsloaded = 0
loaded.Cratesloaded = 0 loaded.Cratesloaded = 0
loaded.Cargo = {} loaded.Cargo = {}
end end
-- get nearby crates -- get nearby crates
local finddist = self.CrateDistance or 35 local finddist = self.CrateDistance or 35
local nearcrates,number = self:_FindCratesNearby(Group,Unit,finddist,false,false) -- #table local nearcrates, number = self:_FindCratesNearby(Group,Unit,finddist,false,false)
self:T(self.lid .. " Crates found: " .. number) self:T(self.lid .. " Crates found: " .. number)
if number == 0 and self.hoverautoloading then if number == 0 and self.hoverautoloading then
return self -- exit return self
elseif number == 0 then elseif number == 0 then
self:_SendMessage("Sorry, no loadable crates nearby or max cargo weight reached!", 10, false, Group) self:_SendMessage("Sorry, no loadable crates nearby or max cargo weight reached!", 10, false, Group)
return self -- exit return self
elseif numberonboard == cratelimit then elseif numberonboard == cratelimit then
self:_SendMessage("Sorry, we are fully loaded!", 10, false, Group) self:_SendMessage("Sorry, we are fully loaded!", 10, false, Group)
return self -- exit return self
else else
-- go through crates and load
local capacity = cratelimit - numberonboard local capacity = cratelimit - numberonboard
local crateidsloaded = {} local crateidsloaded = {}
local loops = 0 local crateMap = {}
while loaded.Cratesloaded < cratelimit and loops < number do
loops = loops + 1 for _, cObj in pairs(nearcrates) do
local crateind = 0 if not cObj:HasMoved() or self.allowcratepickupagain then
-- get crate with largest index local cName = cObj:GetName() or "Unknown"
for _ind,_crate in pairs (nearcrates) do crateMap[cName] = crateMap[cName] or {}
if self.allowcratepickupagain then table.insert(crateMap[cName], cObj)
if _crate:GetID() > crateind and _crate.Positionable ~= nil then
crateind = _crate:GetID()
end
else
if not _crate:HasMoved() and not _crate:WasDropped() and _crate:GetID() > crateind then
crateind = _crate:GetID()
end end
end end
end for cName, crateList in pairs(crateMap) do
-- load one if we found one if capacity <= 0 then break end
if crateind > 0 then
local crate = nearcrates[crateind] -- #CTLD_CARGO table.sort(crateList, function(a, b) return a:GetID() > b:GetID() end)
local needed = crateList[1]:GetCratesNeeded() or 1
local totalFound = #crateList
local loadedHere = 0
while loaded.Cratesloaded < cratelimit and loadedHere < totalFound do
loadedHere = loadedHere + 1
local crate = crateList[loadedHere]
if crate and crate.Positionable then
loaded.Cratesloaded = loaded.Cratesloaded + 1 loaded.Cratesloaded = loaded.Cratesloaded + 1
crate:SetHasMoved(true) crate:SetHasMoved(true)
crate:SetWasDropped(false) crate:SetWasDropped(false)
@ -3186,9 +3185,28 @@ function CTLD:_LoadCratesNearby(Group, Unit)
-- destroy crate -- destroy crate
crate:GetPositionable():Destroy(false) crate:GetPositionable():Destroy(false)
crate.Positionable = nil crate.Positionable = nil
self:_SendMessage(string.format("Crate ID %d for %s loaded!",crate:GetID(),crate:GetName()), 10, false, Group) else
table.remove(nearcrates,crate:GetID()) loadedHere = loadedHere - 1
self:__CratesPickedUp(1, Group, Unit, crate) break
end
end
capacity = cratelimit - loaded.Cratesloaded
if loadedHere > 0 then
local fullSets = math.floor(loadedHere / needed)
local leftover = loadedHere % needed
if needed > 1 then
if fullSets > 0 and leftover == 0 then
self:_SendMessage(string.format("Loaded %d %s.", fullSets, cName), 10, false, Group)
elseif fullSets > 0 and leftover > 0 then
self:_SendMessage(string.format("Loaded %d %s(s), with %d leftover crate(s).", fullSets, cName, leftover), 10, false, Group)
else
self:_SendMessage(string.format("Loaded only %d/%d crate(s) of %s.", loadedHere, needed, cName), 15, false, Group)
end
else
self:_SendMessage(string.format("Loaded %d %s(s).", loadedHere, cName), 10, false, Group)
end
end end
end end
self.Loaded_Cargo[unitname] = loaded self.Loaded_Cargo[unitname] = loaded
@ -3201,6 +3219,7 @@ function CTLD:_LoadCratesNearby(Group, Unit)
return self return self
end end
--- (Internal) Function to clean up tracked cargo crates --- (Internal) Function to clean up tracked cargo crates
-- @param #CTLD self -- @param #CTLD self
-- @param #list crateIdsToRemove Table of IDs -- @param #list crateIdsToRemove Table of IDs
@ -3858,6 +3877,7 @@ end
-- @param #CTLD self -- @param #CTLD self
-- @param Wrapper.Group#GROUP Group -- @param Wrapper.Group#GROUP Group
-- @param Wrapper.Unit#UNIT Unit -- @param Wrapper.Unit#UNIT Unit
function CTLD:_PackCratesNearby(Group, Unit) function CTLD:_PackCratesNearby(Group, Unit)
self:T(self.lid .. " _PackCratesNearby") self:T(self.lid .. " _PackCratesNearby")
----------------------------------------- -----------------------------------------
@ -4294,7 +4314,7 @@ function CTLD:_RefreshF10Menus()
end end
for name, info in pairs(cargoByName) do for name, info in pairs(cargoByName) do
local line = string.format("Drop %s (%d/%d)", name, info.count, info.needed) local line = string.format("Drop %s (%d/%d)", name, info.count, info.needed)
MENU_GROUP_COMMAND:New(_group, line, dropCratesMenu, self._UnloadSingleCrate, self, _group, _unit, name) MENU_GROUP_COMMAND:New(_group, line, dropCratesMenu, self._UnloadSingleCrateSet, self, _group, _unit, name)
end end
end end
@ -4344,9 +4364,12 @@ end
-- @param #CTLD self -- @param #CTLD self
-- @param Wrapper.Group#GROUP Group The calling group. -- @param Wrapper.Group#GROUP Group The calling group.
-- @param Wrapper.Unit#UNIT Unit The calling unit. -- @param Wrapper.Unit#UNIT Unit The calling unit.
-- @param #string CrateName The name of the crate to unload -- @param #string setIndex The name of the crate to unload
-- @return #CTLD self -- @return #CTLD self
function CTLD:_UnloadSingleCrate(Group, Unit, CrateName) function CTLD:_UnloadSingleCrateSet(Group, Unit, setIndex)
self:T(self.lid .. " _UnloadSingleCrateSet")
-- Check if we are in a drop zone (unless we drop anywhere)
if not self.dropcratesanywhere then if not self.dropcratesanywhere then
local inzone, zoneName, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.DROP) local inzone, zoneName, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.DROP)
if not inzone then if not inzone then
@ -4356,10 +4379,37 @@ function CTLD:_UnloadSingleCrate(Group, Unit, CrateName)
end end
end end
end end
-- Check if doors must be open
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
self:_SendMessage("You need to open the door(s) to drop cargo!", 10, false, Group) self:_SendMessage("You need to open the door(s) to drop cargo!", 10, false, Group)
if not self.debug then return self end if not self.debug then return self end
end end
-- Check if the crate grouping data is available
local unitName = Unit:GetName()
if not self.CrateGroupList or not self.CrateGroupList[unitName] then
self:_SendMessage("No crate groups found for this unit!", 10, false, Group)
if not self.debug then return self end
return self
end
-- Find the selected chunk/set by index
local chunk = self.CrateGroupList[unitName][setIndex]
if not chunk then
self:_SendMessage("No crate set found or index invalid!", 10, false, Group)
if not self.debug then return self end
return self
end
-- Check if the chunk is empty
if #chunk == 0 then
self:_SendMessage("No crate found in that set!", 10, false, Group)
if not self.debug then return self end
return self
end
-- Check hover/airdrop/landed logic
local grounded = not self:IsUnitInAir(Unit) local grounded = not self:IsUnitInAir(Unit)
local hoverunload = self:IsCorrectHover(Unit) local hoverunload = self:IsCorrectHover(Unit)
local isHerc = self:IsHercules(Unit) local isHerc = self:IsHercules(Unit)
@ -4373,51 +4423,34 @@ function CTLD:_UnloadSingleCrate(Group, Unit, CrateName)
else else
self:_SendMessage("Nothing loaded or not hovering within parameters!", 10, false, Group) self:_SendMessage("Nothing loaded or not hovering within parameters!", 10, false, Group)
end end
if not self.debug then return self end
return self return self
end end
local unitName = Unit:GetName()
local loadedData = self.Loaded_Cargo[unitName] -- Get the first crate from this set
if not loadedData or not loadedData.Cargo then local crateObj = chunk[1]
self:_SendMessage("Nothing loaded!", 10, false, Group) if not crateObj then
self:_SendMessage("No crate found in that set!", 10, false, Group)
if not self.debug then return self end
return self return self
end end
local cargoList = loadedData.Cargo
local needed = 0 -- Perform the actual "drop" spawn
for _, cObj in ipairs(cargoList) do local needed = crateObj:GetCratesNeeded() or 1
if cObj:GetName() == CrateName and not cObj:WasDropped() then self:_GetCrates(Group, Unit, crateObj, #chunk, true)
needed = cObj:GetCratesNeeded() or 1
break -- Mark all crates in the chunk as dropped
end for _, cObj in ipairs(chunk) do
end
if needed < 1 then
self:_SendMessage(string.format("No %s crate found or already dropped!", CrateName), 10, false, Group)
return self
end
local matched = {}
for _, cObj in ipairs(cargoList) do
local t = cObj:GetType()
if t ~= CTLD_CARGO.Enum.TROOPS
and t ~= CTLD_CARGO.Enum.ENGINEERS
and t ~= CTLD_CARGO.Enum.GCLOADABLE
and (not cObj:WasDropped() or self.allowcratepickupagain)
and cObj:GetName() == CrateName
then
table.insert(matched, cObj)
end
end
local crateToUse = matched[1]
self:_GetCrates(Group, Unit, crateToUse, needed, true)
local used = 0
for _, cObj in ipairs(matched) do
if used < needed then
used = used + 1
cObj:SetWasDropped(true) cObj:SetWasDropped(true)
cObj:SetHasMoved(true) cObj:SetHasMoved(true)
end end
end
-- Rebuild the cargo list to remove the dropped crates
local loadedData = self.Loaded_Cargo[unitName]
if loadedData and loadedData.Cargo then
local newList = {} local newList = {}
local newCratesCount = 0 local newCratesCount = 0
for _, cObj in ipairs(cargoList) do for _, cObj in ipairs(loadedData.Cargo) do
if not cObj:WasDropped() then if not cObj:WasDropped() then
table.insert(newList, cObj) table.insert(newList, cObj)
local ct = cObj:GetType() local ct = cObj:GetType()
@ -4429,8 +4462,12 @@ function CTLD:_UnloadSingleCrate(Group, Unit, CrateName)
loadedData.Cargo = newList loadedData.Cargo = newList
loadedData.Cratesloaded = newCratesCount loadedData.Cratesloaded = newCratesCount
self.Loaded_Cargo[unitName] = loadedData self.Loaded_Cargo[unitName] = loadedData
end
-- Update cargo mass, refresh menu
self:_UpdateUnitCargoMass(Unit) self:_UpdateUnitCargoMass(Unit)
self:_RefreshDropCratesMenu(Group, Unit) self:_RefreshDropCratesMenu(Group, Unit)
return self return self
end end
@ -4445,29 +4482,67 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
if not theGroup.CTLDTopmenu then return end if not theGroup.CTLDTopmenu then return end
local topCrates = theGroup.MyTopCratesMenu local topCrates = theGroup.MyTopCratesMenu
if not topCrates then return end if not topCrates then return end
if topCrates.DropCratesMenu then topCrates.DropCratesMenu:Remove() end if topCrates.DropCratesMenu then
topCrates.DropCratesMenu:Remove()
end
local dropCratesMenu = MENU_GROUP:New(theGroup, "Drop Crates", topCrates) local dropCratesMenu = MENU_GROUP:New(theGroup, "Drop Crates", topCrates)
topCrates.DropCratesMenu = dropCratesMenu topCrates.DropCratesMenu = dropCratesMenu
MENU_GROUP_COMMAND:New(theGroup, "Drop ALL crates", dropCratesMenu, self._UnloadCrates, self, theGroup, theUnit) MENU_GROUP_COMMAND:New(theGroup, "Drop ALL crates", dropCratesMenu, self._UnloadCrates, self, theGroup, theUnit)
local loadedData = self.Loaded_Cargo[Unit:GetName()] local loadedData = self.Loaded_Cargo[Unit:GetName()]
if loadedData and loadedData.Cargo then if not loadedData or not loadedData.Cargo then return end
local cargoByName = {} local cargoByName = {}
for _, cargoObj in pairs(loadedData.Cargo) do for _, cObj in ipairs(loadedData.Cargo) do
if cargoObj and not cargoObj:WasDropped() then if cObj and not cObj:WasDropped() then
local ctype = cargoObj:GetType() local cType = cObj:GetType()
if ctype ~= CTLD_CARGO.Enum.TROOPS and ctype ~= CTLD_CARGO.Enum.ENGINEERS and ctype ~= CTLD_CARGO.Enum.GCLOADABLE then if cType ~= CTLD_CARGO.Enum.TROOPS and cType ~= CTLD_CARGO.Enum.ENGINEERS and cType ~= CTLD_CARGO.Enum.GCLOADABLE then
local cName = cargoObj:GetName() local name = cObj:GetName() or "Unknown"
local needed = cargoObj:GetCratesNeeded() or 1 cargoByName[name] = cargoByName[name] or {}
if not cargoByName[cName] then table.insert(cargoByName[name], cObj)
cargoByName[cName] = {count = 0, needed = needed}
end
cargoByName[cName].count = cargoByName[cName].count + 1
end end
end end
end end
for name, info in pairs(cargoByName) do
local line = string.format("Drop %s (%d/%d)", name, info.count, info.needed) self.CrateGroupList = self.CrateGroupList or {}
MENU_GROUP_COMMAND:New(theGroup, line, dropCratesMenu, self._UnloadSingleCrate, self, theGroup, theUnit, name) self.CrateGroupList[Unit:GetName()] = {}
-- A single global line index for ALL crate names
local lineIndex = 1
for cName, list in pairs(cargoByName) do
local needed = list[1]:GetCratesNeeded() or 1
table.sort(list, function(a,b) return a:GetID() < b:GetID() end)
local i = 1
while i <= #list do
local left = (#list - i + 1)
if left >= needed then
local chunk = {}
for n = i, i + needed - 1 do
table.insert(chunk, list[n])
end
-- Now label uses the global lineIndex and increments after each chunk
local label = string.format("%d. %s", lineIndex, cName)
table.insert(self.CrateGroupList[Unit:GetName()], chunk)
local setIndex = #self.CrateGroupList[Unit:GetName()]
MENU_GROUP_COMMAND:New(theGroup, label, dropCratesMenu, self._UnloadSingleCrateSet, self, theGroup, theUnit, setIndex)
i = i + needed
else
local chunk = {}
for n = i, #list do
table.insert(chunk, list[n])
end
local label = string.format("%d. %s %d/%d", lineIndex, cName, left, needed)
table.insert(self.CrateGroupList[Unit:GetName()], chunk)
local setIndex = #self.CrateGroupList[Unit:GetName()]
MENU_GROUP_COMMAND:New(theGroup, label, dropCratesMenu, self._UnloadSingleCrateSet, self, theGroup, theUnit, setIndex)
i = #list + 1
end
lineIndex = lineIndex + 1
end end
end end
end end
@ -4476,21 +4551,12 @@ end
-- @param #CTLD self -- @param #CTLD self
-- @param Wrapper.Group#GROUP Group The calling group. -- @param Wrapper.Group#GROUP Group The calling group.
-- @param Wrapper.Unit#UNIT Unit The calling unit. -- @param Wrapper.Unit#UNIT Unit The calling unit.
-- @param #number cargoId the Cargo ID -- @param #number chunkID the Cargo ID
-- @return #CTLD self -- @return #CTLD self
function CTLD:_UnloadSingleTroopByID(Group, Unit, cargoID) function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
self:T(self.lid .. " _UnloadSingleTroopByID for cargo ID " .. tostring(cargoID)) self:T(self.lid .. " _UnloadSingleTroopByID chunkID=" .. tostring(chunkID))
-- check if we are in LOAD zone
local droppingatbase = false local droppingatbase = false
local canunload = true
-- Door check
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
self:_SendMessage("You need to open the door(s) to unload troops!", 10, false, Group)
if not self.debug then return self end
end
local inzone, zonename, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.LOAD) local inzone, zonename, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.LOAD)
if not inzone then if not inzone then
inzone, zonename, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.SHIP) inzone, zonename, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.SHIP)
@ -4499,63 +4565,67 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, cargoID)
droppingatbase = true droppingatbase = true
end end
-- check for hover unload if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
local hoverunload = self:IsCorrectHover(Unit) -- if true we\'re hovering in parameters self:_SendMessage("You need to open the door(s) to unload troops!", 10, false, Group)
local IsHerc = self:IsHercules(Unit) if not self.debug then return self end
local IsHook = self:IsHook(Unit) end
if IsHerc and (not IsHook) then
-- no hover but airdrop here local hoverunload = self:IsCorrectHover(Unit)
local isHerc = self:IsHercules(Unit)
local isHook = self:IsHook(Unit)
if isHerc and not isHook then
hoverunload = self:IsCorrectFlightParameters(Unit) hoverunload = self:IsCorrectFlightParameters(Unit)
end end
-- check if we\'re landed
local grounded = not self:IsUnitInAir(Unit) local grounded = not self:IsUnitInAir(Unit)
-- 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
if not droppingatbase or self.debug then if not droppingatbase or self.debug then
if not self.TroopsIDToChunk or not self.TroopsIDToChunk[chunkID] then
------------------------------------------------------------------------ self:_SendMessage(string.format("No troop cargo chunk found for ID %d!", chunkID), 10, false, Group)
-- (NEW CODE FOR SINGLE DROP) if not self.debug then return self end
-- Instead of dropping ALL troop cargo, we only drop the one matching cargoID. return self
------------------------------------------------------------------------ end
local loadedCargoData = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo
local cargoList = loadedCargoData.Cargo or {} local chunk = self.TroopsIDToChunk[chunkID]
if not chunk or #chunk == 0 then
local foundCargo = nil self:_SendMessage(string.format("Troop chunk is empty for ID %d!", chunkID), 10, false, Group)
for _, cargoObj in ipairs(cargoList) do if not self.debug then return self end
if (cargoObj:GetType() == CTLD_CARGO.Enum.TROOPS or cargoObj:GetType() == CTLD_CARGO.Enum.ENGINEERS) return self
and not cargoObj:WasDropped() end
and (cargoObj:GetID() == cargoID)
then -- Drop ONLY the FIRST cargo in that chunk
foundCargo = cargoObj local foundCargo = chunk[1]
break if not foundCargo then
end self:_SendMessage(string.format("No troop cargo at chunk %d!", chunkID), 10, false, Group)
if not self.debug then return self end
return self
end end
if foundCargo then
local cType = foundCargo:GetType() local cType = foundCargo:GetType()
local name = foundCargo:GetName() or "none" local name = foundCargo:GetName() or "none"
local temptable = foundCargo:GetTemplates() or {} local tmpl = foundCargo:GetTemplates() or {}
local zoneradius = self.troopdropzoneradius or 100 -- drop zone radius local zoneradius = self.troopdropzoneradius or 100
local factor = 1 local factor = 1
if IsHerc then if isHerc then
factor = foundCargo:GetCratesNeeded() or 1 -- spread a bit more if airdropping factor = foundCargo:GetCratesNeeded() or 1
zoneradius = Unit:GetVelocityMPS() or 100 zoneradius = Unit:GetVelocityMPS() or 100
end end
local zone = ZONE_GROUP:New(string.format("Unload zone-%s",unitname), Group, zoneradius * factor) local zone = ZONE_GROUP:New(string.format("Unload zone-%s", unitName), Group, zoneradius * factor)
local randomcoord = zone:GetRandomCoordinate(10, 30 * factor) local randomcoord = zone:GetRandomCoordinate(10, 30 * factor)
local heading = Group:GetHeading() or 0 local heading = Group:GetHeading() or 0
-- Spawn troops left from us, closer when hovering, further off when landed
if hoverunload or grounded then if grounded or hoverunload then
randomcoord = Group:GetCoordinate() randomcoord = Group:GetCoordinate()
-- slightly left from us
local Angle = (heading + 270) % 360 local Angle = (heading + 270) % 360
if IsHerc or IsHook then Angle = (heading + 180) % 360 end if isHerc or isHook then
Angle = (heading + 180) % 360
end
local offset = hoverunload and self.TroopUnloadDistHover or self.TroopUnloadDistGround local offset = hoverunload and self.TroopUnloadDistHover or self.TroopUnloadDistGround
if IsHerc then offset = self.TroopUnloadDistGroundHerc or 25 end if isHerc then
if IsHook then offset = self.TroopUnloadDistGroundHerc or 25
end
if isHook then
offset = self.TroopUnloadDistGroundHook or 15 offset = self.TroopUnloadDistGroundHook or 15
if hoverunload and self.TroopUnloadDistHoverHook then if hoverunload and self.TroopUnloadDistHoverHook then
offset = self.TroopUnloadDistHoverHook or 5 offset = self.TroopUnloadDistHoverHook or 5
@ -4565,54 +4635,46 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, cargoID)
end end
local tempcount = 0 local tempcount = 0
if IsHook then tempcount = self.ChinookTroopCircleRadius or 5 end -- 10m circle for the Chinook if isHook then
for _, _template in pairs(temptable) do tempcount = self.ChinookTroopCircleRadius or 5
end
for _, _template in pairs(tmpl) do
self.TroopCounter = self.TroopCounter + 1 self.TroopCounter = self.TroopCounter + 1
tempcount = tempcount + 1 tempcount = tempcount + 1
local alias = string.format("%s-%d", _template, math.random(1,100000)) local alias = string.format("%s-%d", _template, math.random(1,100000))
local rad = 2.5 + (tempcount * 2) local rad = 2.5 + (tempcount * 2)
local Positions = self:_GetUnitPositions(randomcoord, rad, heading, _template) local Positions = self:_GetUnitPositions(randomcoord, rad, heading, _template)
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template, alias) self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template, alias)
:InitDelayOff() :InitDelayOff()
:InitSetUnitAbsolutePositions(Positions) :InitSetUnitAbsolutePositions(Positions)
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end) :OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
:SpawnFromVec2(randomcoord:GetVec2()) :SpawnFromVec2(randomcoord:GetVec2())
self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter], cType) self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter], cType)
end end
foundCargo:SetWasDropped(true) foundCargo:SetWasDropped(true)
if cType == CTLD_CARGO.Enum.ENGINEERS then if cType == CTLD_CARGO.Enum.ENGINEERS then
self.Engineers = self.Engineers + 1 self.Engineers = self.Engineers + 1
local grpname = self.DroppedTroops[self.TroopCounter]:GetName()
self.EngineersInField[self.Engineers] = CTLD_ENGINEERING:New(name, grpname)
self:_SendMessage(string.format("Dropped Engineers %s into action!", name), 10, false, Group) self:_SendMessage(string.format("Dropped Engineers %s into action!", name), 10, false, Group)
else else
self:_SendMessage(string.format("Dropped Troops %s into action!", name), 10, false, Group) self:_SendMessage(string.format("Dropped Troops %s into action!", name), 10, false, Group)
end end
else
-- We did not find any troop cargo with that ID table.remove(chunk, 1)
self:_SendMessage(string.format("No troop cargo with ID %d found or already dropped!", cargoID), 10, false, Group) if #chunk == 0 then
self.TroopsIDToChunk[chunkID] = nil
end end
else else
-- droppingatbase logic -- Return to base logic, remove ONLY the first cargo
self:_SendMessage("Troops have returned to base!", 10, false, Group) self:_SendMessage("Troops have returned to base!", 10, false, Group)
self:__TroopsRTB(1, Group, Unit, zonename, zone) self:__TroopsRTB(1, Group, Unit, zonename, zone)
-------------------------------------------------------------------- if self.TroopsIDToChunk and self.TroopsIDToChunk[chunkID] then
-- (NEW CODE FOR SINGLE DROP AT BASE) local chunk = self.TroopsIDToChunk[chunkID]
-- If you want to return only the single cargo item with cargoID to stock if #chunk > 0 then
-- instead of returning all, you can do something similar here: local firstObj = chunk[1]
-------------------------------------------------------------------- local cName = firstObj:GetName()
local loadedCargoData = self.Loaded_Cargo[unitname] or {}
local cargoList = loadedCargoData.Cargo or {}
for _, cObj in ipairs(cargoList) do
if (cObj:GetType() == CTLD_CARGO.Enum.TROOPS or cObj:GetType() == CTLD_CARGO.Enum.ENGINEERS)
and (cObj:GetID() == cargoID)
then
-- Return this one cargo to stock
local cName = cObj:GetName()
local gentroops = self.Cargo_Troops local gentroops = self.Cargo_Troops
for _id, _troop in pairs(gentroops) do for _id, _troop in pairs(gentroops) do
if _troop.Name == cName then if _troop.Name == cName then
@ -4622,53 +4684,42 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, cargoID)
end end
end end
end end
-- Mark it as dropped so we remove it from the loaded cargo firstObj:SetWasDropped(true)
cObj:SetWasDropped(true) table.remove(chunk, 1)
if #chunk == 0 then
self.TroopsIDToChunk[chunkID] = nil
end
end end
end end
end end
------------------------------------------------------------------------ local cargoList = self.Loaded_Cargo[unitName].Cargo
-- cleanup load list
------------------------------------------------------------------------
local cargoList = self.Loaded_Cargo[unitname].Cargo
-- 1) Remove all dropped cargo (iterate backward for table.remove)
for i = #cargoList, 1, -1 do for i = #cargoList, 1, -1 do
if cargoList[i]:WasDropped() then if cargoList[i]:WasDropped() then
table.remove(cargoList, i) table.remove(cargoList, i)
end end
end end
-- 2) Recount
local troopsLoaded = 0 local troopsLoaded = 0
local cratesLoaded = 0 local cratesLoaded = 0
for _, cargo in ipairs(cargoList) do for _, cargo in ipairs(cargoList) do
local cType = cargo:GetType() local cT = cargo:GetType()
if cType == CTLD_CARGO.Enum.TROOPS or cType == CTLD_CARGO.Enum.ENGINEERS then if cT == CTLD_CARGO.Enum.TROOPS or cT == CTLD_CARGO.Enum.ENGINEERS then
-- If each cargo item represents just 1 group (or “1 load of troops”):
troopsLoaded = troopsLoaded + 1 troopsLoaded = troopsLoaded + 1
-- If you track “troops loaded” by `CratesNeeded()`,
-- then do: troopsLoaded = troopsLoaded + cargo:GetCratesNeeded()
else else
cratesLoaded = cratesLoaded + 1 cratesLoaded = cratesLoaded + 1
end end
end end
self.Loaded_Cargo[unitName].Troopsloaded = troopsLoaded
self.Loaded_Cargo[unitname].Troopsloaded = troopsLoaded self.Loaded_Cargo[unitName].Cratesloaded = cratesLoaded
self.Loaded_Cargo[unitname].Cratesloaded = cratesLoaded
self:_RefreshDropTroopsMenu(Group, Unit) self:_RefreshDropTroopsMenu(Group, Unit)
else else
if IsHerc then local isHerc = self:IsHercules(Unit)
if isHerc then
self:_SendMessage("Nothing loaded or not within airdrop parameters!", 10, false, Group) self:_SendMessage("Nothing loaded or not within airdrop parameters!", 10, false, Group)
else else
self:_SendMessage("Nothing loaded or not hovering within parameters!", 10, false, Group) self:_SendMessage("Nothing loaded or not hovering within parameters!", 10, false, Group)
end end
end end
return self return self
end end
@ -4683,26 +4734,41 @@ function CTLD:_RefreshDropTroopsMenu(Group, Unit)
if not theGroup.CTLDTopmenu then return end if not theGroup.CTLDTopmenu then return end
local topTroops = theGroup.MyTopTroopsMenu local topTroops = theGroup.MyTopTroopsMenu
if not topTroops then return end if not topTroops then return end
if topTroops.DropTroopsMenu then topTroops.DropTroopsMenu:Remove() end if topTroops.DropTroopsMenu then
topTroops.DropTroopsMenu:Remove()
end
local dropTroopsMenu = MENU_GROUP:New(theGroup, "Drop Troops", topTroops) local dropTroopsMenu = MENU_GROUP:New(theGroup, "Drop Troops", topTroops)
topTroops.DropTroopsMenu = dropTroopsMenu topTroops.DropTroopsMenu = dropTroopsMenu
MENU_GROUP_COMMAND:New(theGroup, "Drop ALL troops", dropTroopsMenu, self._UnloadTroops, self, theGroup, theUnit) MENU_GROUP_COMMAND:New(theGroup, "Drop ALL troops", dropTroopsMenu, self._UnloadTroops, self, theGroup, theUnit)
local loadedData = self.Loaded_Cargo[theUnit:GetName()] local loadedData = self.Loaded_Cargo[theUnit:GetName()]
if loadedData and loadedData.Cargo then if not loadedData or not loadedData.Cargo then return end
for i,cargoObj in ipairs(loadedData.Cargo) do
if cargoObj and (cargoObj:GetType()==CTLD_CARGO.Enum.TROOPS or cargoObj:GetType()==CTLD_CARGO.Enum.ENGINEERS) -- Gather troop cargo by name
local troopsByName = {}
for _, cargoObj in ipairs(loadedData.Cargo) do
if cargoObj
and (cargoObj:GetType() == CTLD_CARGO.Enum.TROOPS or cargoObj:GetType() == CTLD_CARGO.Enum.ENGINEERS)
and not cargoObj:WasDropped() and not cargoObj:WasDropped()
then then
local name = cargoObj:GetName() or "Unknown" local name = cargoObj:GetName() or "Unknown"
local size=cargoObj:GetCratesNeeded()or 1 troopsByName[name] = troopsByName[name] or {}
local cID=cargoObj:GetID() table.insert(troopsByName[name], cargoObj)
local index = i
local line = string.format("Drop: %s (#%d)", name, index)
MENU_GROUP_COMMAND:New(theGroup,line,dropTroopsMenu,self._UnloadSingleTroopByID,self,theGroup,theUnit,cID)
end end
end end
self.TroopsIDToChunk = self.TroopsIDToChunk or {}
for tName, objList in pairs(troopsByName) do
table.sort(objList, function(a,b) return a:GetID() < b:GetID() end)
local count = #objList
local chunkID = objList[1]:GetID()
self.TroopsIDToChunk[chunkID] = objList
local label = string.format("Drop %s (%d)", tName, count)
MENU_GROUP_COMMAND:New(theGroup, label, dropTroopsMenu, self._UnloadSingleTroopByID, self, theGroup, theUnit, chunkID)
end end
return self
end end
--- [Internal] Function to check if a template exists in the mission. --- [Internal] Function to check if a template exists in the mission.