#CTLD - Additional features by Lekaa to drop and build one/many in one go and pack/load or get/load in one go

This commit is contained in:
Applevangelist 2025-05-03 17:01:02 +02:00
parent f1af3a50b8
commit a6b622ed31

View File

@ -20,11 +20,12 @@
--
-- ### Author: **Applevangelist** (Moose Version), ***Ciribob*** (original), Thanks to: Shadowze, Cammel (testing), bbirchnz (additional code!!)
-- ### Repack addition for crates: **Raiden**
-- ### Additional cool features: **Lekaa**
--
-- @module Ops.CTLD
-- @image OPS_CTLD.jpg
-- Last Update April 2025
-- Last Update May 2025
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -865,6 +866,7 @@ do
-- my_ctld.TroopUnloadDistGroundHook = 15 -- On the ground, unload troops this far behind the Chinook
-- my_ctld.TroopUnloadDistHoverHook = 5 -- When hovering, unload troops this far behind the Chinook
-- my_ctld.showstockinmenuitems = false -- When set to true, the menu lines will also show the remaining items in stock (that is, if you set any), downside is that the menu for all will be build every 30 seconds anew.
-- 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 only. it will be a 1 step solution.
--
-- ## 2.1 CH-47 Chinook support
--
@ -1412,7 +1414,7 @@ CTLD.FixedWingTypes = {
--- CTLD class version.
-- @field #string version
CTLD.version="1.2.33"
CTLD.version="1.3.34"
--- Instantiate a new CTLD.
-- @param #CTLD self
@ -1591,6 +1593,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
self.subcats = {}
self.subcatsTroop = {}
self.showstockinmenuitems = false
self.onestepmenu = false
-- disallow building in loadzones
self.nobuildinloadzones = true
@ -2913,10 +2916,10 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack)
if drop then
text = string.format("Crates for %s have been dropped!",cratename)
self:__CratesDropped(1, Group, Unit, droppedcargo)
end
else
self:_SendMessage(text, 10, false, Group)
end
self:_RefreshLoadCratesMenu(Group, Unit)
return self
end
@ -3576,7 +3579,10 @@ end
-- @param Wrapper.Unit#UNIT Unit
-- @return #boolean Outcome
function CTLD:IsHook(Unit)
if Unit and string.find(Unit:GetTypeName(),"CH.47") then
if not Unit then return false end
local typeName = Unit:GetTypeName()
if not typeName then return false end
if string.find(typeName, "CH.47") then
return true
else
return false
@ -3766,7 +3772,6 @@ function CTLD:_UnloadCrates(Group, Unit)
self:T(self.lid .. " _UnloadCrates")
if not self.dropcratesanywhere then -- #1570
-- check if we are in DROP zone
local inzone, zonename, zone, distance = self:IsUnitInZone(Unit,CTLD.CargoZoneType.DROP)
if not inzone then
self:_SendMessage("You are not close enough to a drop zone!", 10, false, Group)
@ -3775,46 +3780,60 @@ function CTLD:_UnloadCrates(Group, Unit)
end
end
end
-- Door check
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)
if not self.debug then return self end
end
-- check for hover unload
local hoverunload = self:IsCorrectHover(Unit) --if true we\'re hovering in parameters
local hoverunload = self:IsCorrectHover(Unit)
local IsHerc = self:IsFixedWing(Unit)
local IsHook = self:IsHook(Unit)
if IsHerc and (not IsHook) then
-- no hover but airdrop here
hoverunload = self:IsCorrectFlightParameters(Unit)
end
-- check if we\'re landed
local grounded = not self:IsUnitInAir(Unit)
-- Get what we have loaded
local unitname = Unit:GetName()
if self.Loaded_Cargo[unitname] and (grounded or hoverunload) then
local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo
-- looking for crate
local loadedcargo = self.Loaded_Cargo[unitname] or {}
local cargotable = loadedcargo.Cargo
local droppedCount = {}
local neededMap = {}
for _,_cargo in pairs (cargotable) do
local cargo = _cargo -- #CTLD_CARGO
local type = cargo:GetType() -- #CTLD_CARGO.Enum
local cargo = _cargo
local type = cargo:GetType()
if type ~= CTLD_CARGO.Enum.TROOPS and type ~= CTLD_CARGO.Enum.ENGINEERS and type ~= CTLD_CARGO.Enum.GCLOADABLE and (not cargo:WasDropped() or self.allowcratepickupagain) then
-- unload crates
self:_GetCrates(Group, Unit, cargo, 1, true)
cargo:SetWasDropped(true)
cargo:SetHasMoved(true)
local cname = cargo:GetName() or "Unknown"
droppedCount[cname] = (droppedCount[cname] or 0) + 1
if not neededMap[cname] then
neededMap[cname] = cargo:GetCratesNeeded() or 1
end
end
-- cleanup load list
local loaded = {} -- #CTLD.LoadedCargo
end
for cname,count in pairs(droppedCount) do
local needed = neededMap[cname] or 1
if needed > 1 then
local full = math.floor(count/needed)
local left = count % needed
if full > 0 and left == 0 then
self:_SendMessage(string.format("Dropped %d %s.",full,cname),10,false,Group)
elseif full > 0 and left > 0 then
self:_SendMessage(string.format("Dropped %d %s(s), with %d leftover crate(s).",full,cname,left),10,false,Group)
else
self:_SendMessage(string.format("Dropped %d/%d crate(s) of %s.",count,needed,cname),15,false,Group)
end
else
self:_SendMessage(string.format("Dropped %d %s(s).",count,cname),10,false,Group)
end
end
local loaded = {}
loaded.Troopsloaded = 0
loaded.Cratesloaded = 0
loaded.Cargo = {}
for _,_cargo in pairs (cargotable) do
local cargo = _cargo -- #CTLD_CARGO
local type = cargo:GetType() -- #CTLD_CARGO.Enum
local cargo = _cargo
local type = cargo:GetType()
local size = cargo:GetCratesNeeded()
if type == CTLD_CARGO.Enum.TROOPS or type == CTLD_CARGO.Enum.ENGINEERS then
table.insert(loaded.Cargo,_cargo)
@ -3845,7 +3864,8 @@ end
-- @param Wrapper.Group#GROUP Group
-- @param Wrapper.Unit#UNIT Unit
-- @param #boolean Engineering If true build is by an engineering team.
function CTLD:_BuildCrates(Group, Unit,Engineering)
-- @param #boolean MultiDrop If true and not engineering or FOB, vary position a bit.
function CTLD:_BuildCrates(Group, Unit,Engineering,MultiDrop)
self:T(self.lid .. " _BuildCrates")
-- avoid users trying to build from flying Hercs
if self:IsFixedWing(Unit) and self.enableFixedWing and not Engineering then
@ -3939,12 +3959,13 @@ function CTLD:_BuildCrates(Group, Unit,Engineering)
if build.CanBuild then
self:_CleanUpCrates(crates,build,number)
if self.buildtime and self.buildtime > 0 then
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate())
local buildtimer = TIMER:New(self._BuildObjectFromCrates,self,Group,Unit,build,false,Group:GetCoordinate(),MultiDrop)
buildtimer:Start(self.buildtime)
self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group)
self:__CratesBuildStarted(1,Group,Unit)
self:_RefreshDropTroopsMenu(Group,Unit)
else
self:_BuildObjectFromCrates(Group,Unit,build)
self:_BuildObjectFromCrates(Group,Unit,build,false,nil,MultiDrop)
end
end
end
@ -3983,13 +4004,14 @@ function CTLD:_PackCratesNearby(Group, Unit)
_Group:Destroy() -- if a match is found destroy the Wrapper.Group#GROUP near the player
self:_GetCrates(Group, Unit, _entry, nil, false, true) -- spawn the appropriate crates near the player
self:_RefreshLoadCratesMenu(Group,Unit) -- call the refresher to show the crates in the menu
return self
return true
end
end
end
end
end
return self
self:_SendMessage("Nothing to pack at this distance pilot!",10,false,Group)
return false
end
--- (Internal) Function to repair nearby vehicles / FOBs
@ -4082,7 +4104,8 @@ end
-- @param #CTLD.Buildable Build
-- @param #boolean Repair If true this is a repair and not a new build
-- @param Core.Point#COORDINATE RepairLocation Location for repair (e.g. where the destroyed unit was)
function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation)
-- @param #boolean MultiDrop if true and not a repair, vary location a bit if not a FOB
function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation,MultiDrop)
self:T(self.lid .. " _BuildObjectFromCrates")
-- Spawn-a-crate-content
if Group and Group:IsAlive() or (RepairLocation and not Repair) then
@ -4099,7 +4122,7 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation)
if type(temptable) == "string" then
temptable = {temptable}
end
local zone = nil
local zone = nil -- Core.Zone#ZONE_RADIUS
if RepairLocation and not Repair then
-- timed build
zone = ZONE_RADIUS:New(string.format("Build zone-%d",math.random(1,10000)),RepairLocation:GetVec2(),100)
@ -4108,6 +4131,10 @@ function CTLD:_BuildObjectFromCrates(Group,Unit,Build,Repair,RepairLocation)
end
--local randomcoord = zone:GetRandomCoordinate(35):GetVec2()
local randomcoord = Build.Coord or zone:GetRandomCoordinate(35):GetVec2()
if MultiDrop and (not Repair) and canmove then
-- coordinate may be the same, avoid
local randomcoord = zone:GetRandomCoordinate(35):GetVec2()
end
if Repair then
randomcoord = RepairLocation:GetVec2()
end
@ -4199,11 +4226,91 @@ function CTLD:_CleanUpCrates(Crates,Build,Number)
return self
end
--- (Internal) Helper - Drop **all** loaded crates nearby and build them.
-- @param Wrapper.Group#GROUP Group The calling group
-- @param Wrapper.Unit#UNIT Unit The calling unit
function CTLD:_DropAndBuild(Group,Unit)
if self.nobuildinloadzones then
if self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD) then
self:_SendMessage("You cannot build in a loading area, Pilot!",10,false,Group)
return self
end
end
self:_UnloadCrates(Group,Unit)
timer.scheduleFunction(function() self:_BuildCrates(Group,Unit,false,true) end,{},timer.getTime()+1)
end
--- (Internal) Helper - Drop a **single** crate set and build it.
-- @param Wrapper.Group#GROUP Group The calling group
-- @param Wrapper.Unit#UNIT Unit The calling unit
-- @param number setIndex Index of the crate-set to drop
function CTLD:_DropSingleAndBuild(Group,Unit,setIndex)
if self.nobuildinloadzones then
if self:IsUnitInZone(Unit,CTLD.CargoZoneType.LOAD) then
self:_SendMessage("You cannot build in a loading area, Pilot!",10,false,Group)
return self
end
end
self:_UnloadSingleCrateSet(Group,Unit,setIndex)
timer.scheduleFunction(function() self:_BuildCrates(Group,Unit,false) end,{},timer.getTime()+1)
end
--- (Internal) Helper - Pack crates near the unit and load them.
-- @param Wrapper.Group#GROUP Group The calling group
-- @param Wrapper.Unit#UNIT Unit The calling unit
function CTLD:_PackAndLoad(Group,Unit)
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group)
return self
end
if not self:_PackCratesNearby(Group,Unit) then
return self
end
timer.scheduleFunction(function() self:_LoadCratesNearby(Group,Unit) end,{},timer.getTime()+1)
return self
end
--- (Internal) Helper - Pack crates near the unit and then remove them.
-- @param Wrapper.Group#GROUP Group The calling group
-- @param Wrapper.Unit#UNIT Unit The calling unit
function CTLD:_PackAndRemove(Group,Unit)
if not self:_PackCratesNearby(Group,Unit) then
return self
end
timer.scheduleFunction(function() self:_RemoveCratesNearby(Group,Unit) end,{},timer.getTime()+1)
return self
end
--- (Internal) Helper - get and load in one step
-- @param Wrapper.Group#GROUP Group The calling group
-- @param Wrapper.Unit#UNIT Unit The calling unit
function CTLD:_GetAndLoad(Group,Unit,cargoObj)
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group)
return self
end
self:_GetCrates(Group,Unit,cargoObj)
timer.scheduleFunction(function() self:_LoadSingleCrateSet(Group,Unit,cargoObj.Name) end,{},timer.getTime()+1)
end
-- @param Wrapper.Group#GROUP Group The players group that triggered the action
-- @param Wrapper.Unit#UNIT Unit The unit performing the pack-and-load
function CTLD:_GetAllAndLoad(Group,Unit)
if self.pilotmustopendoors and not UTILS.IsLoadingDoorOpen(Unit:GetName()) then
self:_SendMessage("You need to open the door(s) to load cargo!",10,false,Group)
return self
end
timer.scheduleFunction(function() self:_LoadCratesNearby(Group,Unit) end,{},timer.getTime()+1)
end
--- (Internal) Housekeeping - Function to refresh F10 menus.
-- @param #CTLD self
-- @return #CTLD self
function CTLD:_RefreshF10Menus()
self:T(self.lid .. " _RefreshF10Menus")
self.onestepmenu = self.onestepmenu or false -- hybrid toggle (default = false)
-- 1) Gather all the pilot groups from our Set
local PlayerSet = self.PilotGroups
@ -4314,7 +4421,6 @@ function CTLD:_RefreshF10Menus()
local menutext = cargoObj.Name
if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end
MENU_GROUP_COMMAND:New(_group, menutext, troopsmenu, self._LoadTroops, self, _group, _unit, cargoObj)
end
end
end
@ -4341,11 +4447,65 @@ function CTLD:_RefreshF10Menus()
-- Build the “Get Crates” sub-menu items
local cratesmenu = MENU_GROUP:New(_group,"Get Crates",topcrates)
if self.onestepmenu then
if self.usesubcats then
local subcatmenus = {}
for catName,_ in pairs(self.subcats) do
subcatmenus[catName] = MENU_GROUP:New(_group,catName,cratesmenu)
end
for _,cargoObj in pairs(self.Cargo_Crates) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory])
MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj)
MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj)
end
end
for _,cargoObj in pairs(self.Cargo_Statics) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
local mSet = MENU_GROUP:New(_group,txt,subcatmenus[cargoObj.Subcategory])
MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj)
MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj)
end
end
else
for _,cargoObj in pairs(self.Cargo_Crates) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
local mSet = MENU_GROUP:New(_group,txt,cratesmenu)
MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj)
MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj)
end
end
for _,cargoObj in pairs(self.Cargo_Statics) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)",cargoObj.Name,cargoObj.PerCrateMass or 0)
if cargoObj.Location then txt = txt.."[R]" end
local stock = cargoObj:GetStock()
if stock>=0 and self.showstockinmenuitems then txt = txt.."["..stock.."]" end
local mSet = MENU_GROUP:New(_group,txt,cratesmenu)
MENU_GROUP_COMMAND:New(_group,"Get and Load",mSet,self._GetAndLoad,self,_group,_unit,cargoObj)
MENU_GROUP_COMMAND:New(_group,"Get only",mSet,self._GetCrates,self,_group,_unit,cargoObj)
end
end
end
else
if self.usesubcats then
local subcatmenus = {}
for catName, _ in pairs(self.subcats) do
subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) -- fixed variable case
end
for _, cargoObj in pairs(self.Cargo_Crates) do
if not cargoObj.DontShowInMenu then
local txt = string.format("Crate %s (%dkg)", cargoObj.Name, cargoObj.PerCrateMass or 0)
@ -4384,6 +4544,7 @@ function CTLD:_RefreshF10Menus()
end
end
end
end
local loadCratesMenu=MENU_GROUP:New(_group,"Load Crates",topcrates)
_group.MyLoadCratesMenu=loadCratesMenu
@ -4401,8 +4562,16 @@ function CTLD:_RefreshF10Menus()
local removecratesmenu = MENU_GROUP:New(_group, "Remove crates", topcrates)
MENU_GROUP_COMMAND:New(_group, "Remove crates nearby", removecratesmenu, self._RemoveCratesNearby, self, _group, _unit)
if self.onestepmenu then
local mPack=MENU_GROUP:New(_group,"Pack crates",topcrates)
MENU_GROUP_COMMAND:New(_group,"Pack and Load",mPack,self._PackAndLoad,self,_group,_unit)
MENU_GROUP_COMMAND:New(_group,"Pack and Remove",mPack,self._PackAndRemove,self,_group,_unit)
MENU_GROUP_COMMAND:New(_group,"Pack only",mPack,self._PackCratesNearby,self,_group,_unit)
MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit)
else
MENU_GROUP_COMMAND:New(_group, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit)
MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit)
end
local uName = _unit:GetName()
local loadedData = self.Loaded_Cargo[uName]
@ -4423,8 +4592,6 @@ function CTLD:_RefreshF10Menus()
end
end
-----------------------------------------------------
-- Misc submenus
-----------------------------------------------------
@ -4482,27 +4649,35 @@ function CTLD:_RefreshLoadCratesMenu(Group, Unit)
return
end
MENU_GROUP_COMMAND:New(Group,"Load ALL",Group.MyLoadCratesMenu,self._LoadCratesNearby,self,Group,Unit)
local cargoByName={}
for _,crate in pairs(nearby) do
local cName = crate:GetName()
cargoByName[cName] = cargoByName[cName] or {}
table.insert(cargoByName[cName], crate)
local name=crate:GetName()
cargoByName[name]=cargoByName[name] or{}
table.insert(cargoByName[name],crate)
end
for cName, cList in pairs(cargoByName) do
local needed = cList[1]:GetCratesNeeded() or 1
local found = #cList
local line
if found >= needed then
line = string.format("Load %s", cName)
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
local label
if left>=needed then
label=string.format("%d. Load %s",lineIndex,cName)
i=i+needed
else
MENU_GROUP_COMMAND:New(Group, "Rescan?", Group.MyLoadCratesMenu, function() self:_RefreshLoadCratesMenu(Group, Unit) end)
line = string.format("Load %s (%d/%d)", cName, found, needed)
label=string.format("%d. Load %s (%d/%d)",lineIndex,cName,left,needed)
i=#list+1
end
MENU_GROUP_COMMAND:New(Group, line, Group.MyLoadCratesMenu, self._LoadSingleCrateSet, self, Group, Unit, cName)
MENU_GROUP_COMMAND:New(Group,label,Group.MyLoadCratesMenu,self._LoadSingleCrateSet,self,Group,Unit,cName)
lineIndex=lineIndex+1
end
end
end
---
-- Loads exactly `CratesNeeded` crates for one cargoName in range.
@ -4745,6 +4920,7 @@ end
-- @param Wrapper.Unit#UNIT Unit The calling unit.
-- @return #CTLD self
function CTLD:_RefreshDropCratesMenu(Group, Unit)
if not Group.CTLDTopmenu then return end
local topCrates = Group.MyTopCratesMenu
if not topCrates then return end
@ -4780,7 +4956,15 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
return
end
----------------------------------------------------------------------
-- DEFAULT (“classic”) versus ONE-STEP behaviour
----------------------------------------------------------------------
if not self.onestepmenu then
--------------------------------------------------------------------
-- classic menu
--------------------------------------------------------------------
MENU_GROUP_COMMAND:New(Group,"Drop ALL crates",dropCratesMenu,self._UnloadCrates,self,Group,Unit)
self.CrateGroupList=self.CrateGroupList or{}
self.CrateGroupList[Unit:GetName()]={}
@ -4815,6 +4999,52 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
lineIndex=lineIndex+1
end
end
else
--------------------------------------------------------------------
-- one-step (enhanced) menu
--------------------------------------------------------------------
local mAll=MENU_GROUP:New(Group,"Drop ALL crates",dropCratesMenu)
MENU_GROUP_COMMAND:New(Group,"Drop and build",mAll,self._DropAndBuild,self,Group,Unit)
MENU_GROUP_COMMAND:New(Group,"Drop only",mAll,self._UnloadCrates,self,Group,Unit)
self.CrateGroupList=self.CrateGroupList or{}
self.CrateGroupList[Unit:GetName()]={}
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
local label=string.format("%d. %s",lineIndex,cName)
table.insert(self.CrateGroupList[Unit:GetName()],chunk)
local setIndex=#self.CrateGroupList[Unit:GetName()]
local mSet=MENU_GROUP:New(Group,label,dropCratesMenu)
MENU_GROUP_COMMAND:New(Group,"Drop and build",mSet,self._DropSingleAndBuild,self,Group,Unit,setIndex)
MENU_GROUP_COMMAND:New(Group,"Drop only",mSet,self._UnloadSingleCrateSet,self,Group,Unit,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(Group,label,dropCratesMenu,self._UnloadSingleCrateSet,self,Group,Unit,setIndex)
i=#list+1
end
lineIndex=lineIndex+1
end
end
end
end
--- (Internal) Function to unload a single Troop group by ID.