mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-08-15 10:47:21 +00:00
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:
parent
1d08bcf2e0
commit
cad8f15b61
@ -2355,7 +2355,7 @@ function CTLD:_LoadTroops(Group, Unit, Cargotype, Inject)
|
||||
loaded.Troopsloaded = loaded.Troopsloaded + troopsize
|
||||
table.insert(loaded.Cargo,loadcargotype)
|
||||
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:__TroopsPickedUp(1,Group, Unit, Cargotype)
|
||||
self:_UpdateUnitCargoMass(Unit)
|
||||
@ -2589,8 +2589,8 @@ end
|
||||
loaded.Troopsloaded = loaded.Troopsloaded + troopsize
|
||||
table.insert(loaded.Cargo,loadcargotype)
|
||||
self.Loaded_Cargo[unitname] = loaded
|
||||
self:ScheduleOnce(running,self._SendMessage,self,"Troops boarded!", 10, false, Group)
|
||||
self:_SendMessage("Troops boarding!", 10, false, Group)
|
||||
self:ScheduleOnce(running, self._SendMessage, self, string.format("%s boarded!", Cargotype.Name), 10, false, Group)
|
||||
self:_SendMessage(string.format("%s boarding!", Cargotype.Name), 10, false, Group)
|
||||
self:_RefreshDropTroopsMenu(Group,Unit)
|
||||
self:_UpdateUnitCargoMass(Unit)
|
||||
local groupname = nearestGroup:GetName()
|
||||
@ -3099,23 +3099,21 @@ function CTLD:_LoadCratesNearby(Group, Unit)
|
||||
self:T(self.lid .. " _LoadCratesNearby")
|
||||
-- load crates into heli
|
||||
local group = Group -- Wrapper.Group#GROUP
|
||||
local unit = Unit -- Wrapper.Unit#UNIT
|
||||
local unit = Unit -- Wrapper.Unit#UNIT
|
||||
local unitname = unit:GetName()
|
||||
-- see if this heli can load crates
|
||||
-- see if this heli can load crates
|
||||
local unittype = unit:GetTypeName()
|
||||
local capabilities = self:_GetUnitCapabilities(Unit) -- #CTLD.UnitTypeCapabilities
|
||||
--local capabilities = self.UnitTypeCapabilities[unittype] -- #CTLD.UnitTypeCapabilities
|
||||
local cancrates = capabilities.crates -- #boolean
|
||||
local cratelimit = capabilities.cratelimit -- #number
|
||||
local grounded = not self:IsUnitInAir(Unit)
|
||||
local canhoverload = self:CanHoverLoad(Unit)
|
||||
|
||||
|
||||
-- Door check
|
||||
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)
|
||||
if not self.debug then return self end
|
||||
if not self.debug then return self end
|
||||
end
|
||||
|
||||
--- cases -------------------------------
|
||||
-- Chopper can\'t do crates - bark & return
|
||||
-- Chopper can do crates -
|
||||
@ -3123,77 +3121,97 @@ function CTLD:_LoadCratesNearby(Group, Unit)
|
||||
-- --> hover or land if not forcedhover
|
||||
-----------------------------------------
|
||||
if not cancrates then
|
||||
self:_SendMessage("Sorry this chopper cannot carry crates!", 10, false, Group)
|
||||
self:_SendMessage("Sorry this chopper cannot carry crates!", 10, false, Group)
|
||||
elseif self.forcehoverload and not canhoverload then
|
||||
self:_SendMessage("Hover over the crates to pick them up!", 10, false, Group)
|
||||
self:_SendMessage("Hover over the crates to pick them up!", 10, false, Group)
|
||||
elseif not grounded and not canhoverload then
|
||||
self:_SendMessage("Land or hover over the crates to pick them up!", 10, false, Group)
|
||||
self:_SendMessage("Land or hover over the crates to pick them up!", 10, false, Group)
|
||||
else
|
||||
-- have we loaded stuff already?
|
||||
-- have we loaded stuff already?
|
||||
local numberonboard = 0
|
||||
local massonboard = 0
|
||||
local loaded = {}
|
||||
local loaded = {}
|
||||
if self.Loaded_Cargo[unitname] then
|
||||
loaded = self.Loaded_Cargo[unitname] -- #CTLD.LoadedCargo
|
||||
numberonboard = loaded.Cratesloaded or 0
|
||||
massonboard = self:_GetUnitCargoMass(Unit)
|
||||
loaded = self.Loaded_Cargo[unitname] -- #CTLD.LoadedCargo
|
||||
numberonboard = loaded.Cratesloaded or 0
|
||||
else
|
||||
loaded = {} -- #CTLD.LoadedCargo
|
||||
loaded = {}
|
||||
loaded.Troopsloaded = 0
|
||||
loaded.Cratesloaded = 0
|
||||
loaded.Cargo = {}
|
||||
end
|
||||
|
||||
-- get nearby crates
|
||||
local finddist = self.CrateDistance or 35
|
||||
local nearcrates,number = self:_FindCratesNearby(Group,Unit,finddist,false,false) -- #table
|
||||
local finddist = self.CrateDistance or 35
|
||||
local nearcrates, number = self:_FindCratesNearby(Group,Unit,finddist,false,false)
|
||||
self:T(self.lid .. " Crates found: " .. number)
|
||||
|
||||
if number == 0 and self.hoverautoloading then
|
||||
return self -- exit
|
||||
return self
|
||||
elseif number == 0 then
|
||||
self:_SendMessage("Sorry, no loadable crates nearby or max cargo weight reached!", 10, false, Group)
|
||||
return self -- exit
|
||||
self:_SendMessage("Sorry, no loadable crates nearby or max cargo weight reached!", 10, false, Group)
|
||||
return self
|
||||
elseif numberonboard == cratelimit then
|
||||
self:_SendMessage("Sorry, we are fully loaded!", 10, false, Group)
|
||||
return self -- exit
|
||||
self:_SendMessage("Sorry, we are fully loaded!", 10, false, Group)
|
||||
return self
|
||||
else
|
||||
-- go through crates and load
|
||||
local capacity = cratelimit - numberonboard
|
||||
local crateidsloaded = {}
|
||||
local loops = 0
|
||||
while loaded.Cratesloaded < cratelimit and loops < number do
|
||||
loops = loops + 1
|
||||
local crateind = 0
|
||||
-- get crate with largest index
|
||||
for _ind,_crate in pairs (nearcrates) do
|
||||
if self.allowcratepickupagain then
|
||||
if _crate:GetID() > crateind and _crate.Positionable ~= nil then
|
||||
crateind = _crate:GetID()
|
||||
end
|
||||
local crateMap = {}
|
||||
|
||||
for _, cObj in pairs(nearcrates) do
|
||||
if not cObj:HasMoved() or self.allowcratepickupagain then
|
||||
local cName = cObj:GetName() or "Unknown"
|
||||
crateMap[cName] = crateMap[cName] or {}
|
||||
table.insert(crateMap[cName], cObj)
|
||||
end
|
||||
end
|
||||
for cName, crateList in pairs(crateMap) do
|
||||
if capacity <= 0 then break end
|
||||
|
||||
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
|
||||
crate:SetHasMoved(true)
|
||||
crate:SetWasDropped(false)
|
||||
table.insert(loaded.Cargo, crate)
|
||||
table.insert(crateidsloaded, crate:GetID())
|
||||
-- destroy crate
|
||||
crate:GetPositionable():Destroy(false)
|
||||
crate.Positionable = nil
|
||||
else
|
||||
if not _crate:HasMoved() and not _crate:WasDropped() and _crate:GetID() > crateind then
|
||||
crateind = _crate:GetID()
|
||||
end
|
||||
loadedHere = loadedHere - 1
|
||||
break
|
||||
end
|
||||
end
|
||||
-- load one if we found one
|
||||
if crateind > 0 then
|
||||
local crate = nearcrates[crateind] -- #CTLD_CARGO
|
||||
loaded.Cratesloaded = loaded.Cratesloaded + 1
|
||||
crate:SetHasMoved(true)
|
||||
crate:SetWasDropped(false)
|
||||
table.insert(loaded.Cargo, crate)
|
||||
table.insert(crateidsloaded,crate:GetID())
|
||||
-- destroy crate
|
||||
crate:GetPositionable():Destroy(false)
|
||||
crate.Positionable = nil
|
||||
self:_SendMessage(string.format("Crate ID %d for %s loaded!",crate:GetID(),crate:GetName()), 10, false, Group)
|
||||
table.remove(nearcrates,crate:GetID())
|
||||
self:__CratesPickedUp(1, Group, Unit, crate)
|
||||
|
||||
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
|
||||
self.Loaded_Cargo[unitname] = loaded
|
||||
self:_UpdateUnitCargoMass(Unit)
|
||||
self:_RefreshDropCratesMenu(Group,Unit)
|
||||
self:_UpdateUnitCargoMass(Unit)
|
||||
self:_RefreshDropCratesMenu(Group, Unit)
|
||||
-- clean up real world crates
|
||||
self:_CleanupTrackedCrates(crateidsloaded)
|
||||
end
|
||||
@ -3201,6 +3219,7 @@ function CTLD:_LoadCratesNearby(Group, Unit)
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
--- (Internal) Function to clean up tracked cargo crates
|
||||
-- @param #CTLD self
|
||||
-- @param #list crateIdsToRemove Table of IDs
|
||||
@ -3858,6 +3877,7 @@ end
|
||||
-- @param #CTLD self
|
||||
-- @param Wrapper.Group#GROUP Group
|
||||
-- @param Wrapper.Unit#UNIT Unit
|
||||
|
||||
function CTLD:_PackCratesNearby(Group, Unit)
|
||||
self:T(self.lid .. " _PackCratesNearby")
|
||||
-----------------------------------------
|
||||
@ -4294,7 +4314,7 @@ function CTLD:_RefreshF10Menus()
|
||||
end
|
||||
for name, info in pairs(cargoByName) do
|
||||
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
|
||||
|
||||
@ -4344,22 +4364,52 @@ end
|
||||
-- @param #CTLD self
|
||||
-- @param Wrapper.Group#GROUP Group The calling group.
|
||||
-- @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
|
||||
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
|
||||
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)
|
||||
if not self.debug then
|
||||
return self
|
||||
if not self.debug then
|
||||
return self
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if doors must be open
|
||||
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 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 hoverunload = self:IsCorrectHover(Unit)
|
||||
local isHerc = self:IsHercules(Unit)
|
||||
@ -4373,64 +4423,51 @@ function CTLD:_UnloadSingleCrate(Group, Unit, CrateName)
|
||||
else
|
||||
self:_SendMessage("Nothing loaded or not hovering within parameters!", 10, false, Group)
|
||||
end
|
||||
if not self.debug then return self end
|
||||
return self
|
||||
end
|
||||
local unitName = Unit:GetName()
|
||||
|
||||
-- Get the first crate from this set
|
||||
local crateObj = chunk[1]
|
||||
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
|
||||
end
|
||||
|
||||
-- Perform the actual "drop" spawn
|
||||
local needed = crateObj:GetCratesNeeded() or 1
|
||||
self:_GetCrates(Group, Unit, crateObj, #chunk, true)
|
||||
|
||||
-- Mark all crates in the chunk as dropped
|
||||
for _, cObj in ipairs(chunk) do
|
||||
cObj:SetWasDropped(true)
|
||||
cObj:SetHasMoved(true)
|
||||
end
|
||||
|
||||
-- Rebuild the cargo list to remove the dropped crates
|
||||
local loadedData = self.Loaded_Cargo[unitName]
|
||||
if not loadedData or not loadedData.Cargo then
|
||||
self:_SendMessage("Nothing loaded!", 10, false, Group)
|
||||
return self
|
||||
end
|
||||
local cargoList = loadedData.Cargo
|
||||
local needed = 0
|
||||
for _, cObj in ipairs(cargoList) do
|
||||
if cObj:GetName() == CrateName and not cObj:WasDropped() then
|
||||
needed = cObj:GetCratesNeeded() or 1
|
||||
break
|
||||
end
|
||||
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:SetHasMoved(true)
|
||||
end
|
||||
end
|
||||
local newList = {}
|
||||
local newCratesCount = 0
|
||||
for _, cObj in ipairs(cargoList) do
|
||||
if not cObj:WasDropped() then
|
||||
table.insert(newList, cObj)
|
||||
local ct = cObj:GetType()
|
||||
if ct ~= CTLD_CARGO.Enum.TROOPS and ct ~= CTLD_CARGO.Enum.ENGINEERS then
|
||||
newCratesCount = newCratesCount + 1
|
||||
if loadedData and loadedData.Cargo then
|
||||
local newList = {}
|
||||
local newCratesCount = 0
|
||||
for _, cObj in ipairs(loadedData.Cargo) do
|
||||
if not cObj:WasDropped() then
|
||||
table.insert(newList, cObj)
|
||||
local ct = cObj:GetType()
|
||||
if ct ~= CTLD_CARGO.Enum.TROOPS and ct ~= CTLD_CARGO.Enum.ENGINEERS then
|
||||
newCratesCount = newCratesCount + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
loadedData.Cargo = newList
|
||||
loadedData.Cratesloaded = newCratesCount
|
||||
self.Loaded_Cargo[unitName] = loadedData
|
||||
end
|
||||
loadedData.Cargo = newList
|
||||
loadedData.Cratesloaded = newCratesCount
|
||||
self.Loaded_Cargo[unitName] = loadedData
|
||||
|
||||
-- Update cargo mass, refresh menu
|
||||
self:_UpdateUnitCargoMass(Unit)
|
||||
self:_RefreshDropCratesMenu(Group,Unit)
|
||||
self:_RefreshDropCratesMenu(Group, Unit)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@ -4445,29 +4482,67 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
|
||||
if not theGroup.CTLDTopmenu then return end
|
||||
local topCrates = theGroup.MyTopCratesMenu
|
||||
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)
|
||||
topCrates.DropCratesMenu = dropCratesMenu
|
||||
MENU_GROUP_COMMAND:New(theGroup, "Drop ALL crates", dropCratesMenu, self._UnloadCrates, self, theGroup, theUnit)
|
||||
|
||||
local loadedData = self.Loaded_Cargo[Unit:GetName()]
|
||||
if loadedData and loadedData.Cargo then
|
||||
local cargoByName = {}
|
||||
for _, cargoObj in pairs(loadedData.Cargo) do
|
||||
if cargoObj and not cargoObj:WasDropped() then
|
||||
local ctype = cargoObj:GetType()
|
||||
if ctype ~= CTLD_CARGO.Enum.TROOPS and ctype ~= CTLD_CARGO.Enum.ENGINEERS and ctype ~= CTLD_CARGO.Enum.GCLOADABLE then
|
||||
local cName = cargoObj:GetName()
|
||||
local needed = cargoObj:GetCratesNeeded() or 1
|
||||
if not cargoByName[cName] then
|
||||
cargoByName[cName] = {count = 0, needed = needed}
|
||||
end
|
||||
cargoByName[cName].count = cargoByName[cName].count + 1
|
||||
end
|
||||
if not loadedData or not loadedData.Cargo then return end
|
||||
|
||||
local cargoByName = {}
|
||||
for _, cObj in ipairs(loadedData.Cargo) do
|
||||
if cObj and not cObj:WasDropped() then
|
||||
local cType = cObj:GetType()
|
||||
if cType ~= CTLD_CARGO.Enum.TROOPS and cType ~= CTLD_CARGO.Enum.ENGINEERS and cType ~= CTLD_CARGO.Enum.GCLOADABLE then
|
||||
local name = cObj:GetName() or "Unknown"
|
||||
cargoByName[name] = cargoByName[name] or {}
|
||||
table.insert(cargoByName[name], cObj)
|
||||
end
|
||||
end
|
||||
for name, info in pairs(cargoByName) do
|
||||
local line = string.format("Drop %s (%d/%d)", name, info.count, info.needed)
|
||||
MENU_GROUP_COMMAND:New(theGroup, line, dropCratesMenu, self._UnloadSingleCrate, self, theGroup, theUnit, name)
|
||||
end
|
||||
|
||||
self.CrateGroupList = self.CrateGroupList or {}
|
||||
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
|
||||
@ -4476,21 +4551,12 @@ end
|
||||
-- @param #CTLD self
|
||||
-- @param Wrapper.Group#GROUP Group The calling group.
|
||||
-- @param Wrapper.Unit#UNIT Unit The calling unit.
|
||||
-- @param #number cargoId the Cargo ID
|
||||
-- @param #number chunkID the Cargo ID
|
||||
-- @return #CTLD self
|
||||
function CTLD:_UnloadSingleTroopByID(Group, Unit, cargoID)
|
||||
self:T(self.lid .. " _UnloadSingleTroopByID for cargo ID " .. tostring(cargoID))
|
||||
function CTLD:_UnloadSingleTroopByID(Group, Unit, chunkID)
|
||||
self:T(self.lid .. " _UnloadSingleTroopByID chunkID=" .. tostring(chunkID))
|
||||
|
||||
-- check if we are in LOAD zone
|
||||
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)
|
||||
if not inzone then
|
||||
inzone, zonename, zone, distance = self:IsUnitInZone(Unit, CTLD.CargoZoneType.SHIP)
|
||||
@ -4499,120 +4565,116 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, cargoID)
|
||||
droppingatbase = true
|
||||
end
|
||||
|
||||
-- check for hover unload
|
||||
local hoverunload = self:IsCorrectHover(Unit) -- if true we\'re hovering in parameters
|
||||
local IsHerc = self:IsHercules(Unit)
|
||||
local IsHook = self:IsHook(Unit)
|
||||
if IsHerc and (not IsHook) then
|
||||
-- no hover but airdrop here
|
||||
hoverunload = self:IsCorrectFlightParameters(Unit)
|
||||
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
|
||||
|
||||
-- check if we\'re landed
|
||||
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)
|
||||
end
|
||||
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
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- (NEW CODE FOR SINGLE DROP)
|
||||
-- Instead of dropping ALL troop cargo, we only drop the one matching cargoID.
|
||||
------------------------------------------------------------------------
|
||||
local loadedCargoData = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo
|
||||
local cargoList = loadedCargoData.Cargo or {}
|
||||
|
||||
local foundCargo = nil
|
||||
for _, cargoObj in ipairs(cargoList) do
|
||||
if (cargoObj:GetType() == CTLD_CARGO.Enum.TROOPS or cargoObj:GetType() == CTLD_CARGO.Enum.ENGINEERS)
|
||||
and not cargoObj:WasDropped()
|
||||
and (cargoObj:GetID() == cargoID)
|
||||
then
|
||||
foundCargo = cargoObj
|
||||
break
|
||||
end
|
||||
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)
|
||||
if not self.debug then return self end
|
||||
return self
|
||||
end
|
||||
|
||||
if foundCargo then
|
||||
local cType = foundCargo:GetType()
|
||||
local name = foundCargo:GetName() or "none"
|
||||
local temptable = foundCargo:GetTemplates() or {}
|
||||
local zoneradius = self.troopdropzoneradius or 100 -- drop zone radius
|
||||
local factor = 1
|
||||
if IsHerc then
|
||||
factor = foundCargo:GetCratesNeeded() or 1 -- spread a bit more if airdropping
|
||||
zoneradius = Unit:GetVelocityMPS() or 100
|
||||
local chunk = self.TroopsIDToChunk[chunkID]
|
||||
if not chunk or #chunk == 0 then
|
||||
self:_SendMessage(string.format("Troop chunk is empty for ID %d!", chunkID), 10, false, Group)
|
||||
if not self.debug then return self end
|
||||
return self
|
||||
end
|
||||
|
||||
-- Drop ONLY the FIRST cargo in that chunk
|
||||
local foundCargo = chunk[1]
|
||||
if not foundCargo then
|
||||
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
|
||||
|
||||
local cType = foundCargo:GetType()
|
||||
local name = foundCargo:GetName() or "none"
|
||||
local tmpl = foundCargo:GetTemplates() or {}
|
||||
local zoneradius = self.troopdropzoneradius or 100
|
||||
local factor = 1
|
||||
if isHerc then
|
||||
factor = foundCargo:GetCratesNeeded() or 1
|
||||
zoneradius = Unit:GetVelocityMPS() or 100
|
||||
end
|
||||
local zone = ZONE_GROUP:New(string.format("Unload zone-%s", unitName), Group, zoneradius * factor)
|
||||
local randomcoord = zone:GetRandomCoordinate(10, 30 * factor)
|
||||
local heading = Group:GetHeading() or 0
|
||||
|
||||
if grounded or hoverunload then
|
||||
randomcoord = Group:GetCoordinate()
|
||||
local Angle = (heading + 270) % 360
|
||||
if isHerc or isHook then
|
||||
Angle = (heading + 180) % 360
|
||||
end
|
||||
local zone = ZONE_GROUP:New(string.format("Unload zone-%s",unitname), Group, zoneradius * factor)
|
||||
local randomcoord = zone:GetRandomCoordinate(10, 30 * factor)
|
||||
local heading = Group:GetHeading() or 0
|
||||
-- Spawn troops left from us, closer when hovering, further off when landed
|
||||
if hoverunload or grounded then
|
||||
randomcoord = Group:GetCoordinate()
|
||||
-- slightly left from us
|
||||
local Angle = (heading + 270) % 360
|
||||
if IsHerc or IsHook then Angle = (heading + 180) % 360 end
|
||||
local offset = hoverunload and self.TroopUnloadDistHover or self.TroopUnloadDistGround
|
||||
if IsHerc then offset = self.TroopUnloadDistGroundHerc or 25 end
|
||||
if IsHook then
|
||||
offset = self.TroopUnloadDistGroundHook or 15
|
||||
if hoverunload and self.TroopUnloadDistHoverHook then
|
||||
offset = self.TroopUnloadDistHoverHook or 5
|
||||
end
|
||||
local offset = hoverunload and self.TroopUnloadDistHover or self.TroopUnloadDistGround
|
||||
if isHerc then
|
||||
offset = self.TroopUnloadDistGroundHerc or 25
|
||||
end
|
||||
if isHook then
|
||||
offset = self.TroopUnloadDistGroundHook or 15
|
||||
if hoverunload and self.TroopUnloadDistHoverHook then
|
||||
offset = self.TroopUnloadDistHoverHook or 5
|
||||
end
|
||||
randomcoord:Translate(offset, Angle, nil, true)
|
||||
end
|
||||
randomcoord:Translate(offset, Angle, nil, true)
|
||||
end
|
||||
|
||||
local tempcount = 0
|
||||
if IsHook then tempcount = self.ChinookTroopCircleRadius or 5 end -- 10m circle for the Chinook
|
||||
for _, _template in pairs(temptable) do
|
||||
self.TroopCounter = self.TroopCounter + 1
|
||||
tempcount = tempcount + 1
|
||||
local alias = string.format("%s-%d", _template, math.random(1,100000))
|
||||
local rad = 2.5 + (tempcount * 2)
|
||||
local Positions = self:_GetUnitPositions(randomcoord, rad, heading, _template)
|
||||
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template, alias)
|
||||
:InitDelayOff()
|
||||
:InitSetUnitAbsolutePositions(Positions)
|
||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||
:SpawnFromVec2(randomcoord:GetVec2())
|
||||
|
||||
self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter], cType)
|
||||
end
|
||||
foundCargo:SetWasDropped(true)
|
||||
if cType == CTLD_CARGO.Enum.ENGINEERS then
|
||||
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)
|
||||
else
|
||||
self:_SendMessage(string.format("Dropped Troops %s into action!", name), 10, false, Group)
|
||||
end
|
||||
local tempcount = 0
|
||||
if isHook then
|
||||
tempcount = self.ChinookTroopCircleRadius or 5
|
||||
end
|
||||
for _, _template in pairs(tmpl) do
|
||||
self.TroopCounter = self.TroopCounter + 1
|
||||
tempcount = tempcount + 1
|
||||
local alias = string.format("%s-%d", _template, math.random(1,100000))
|
||||
local rad = 2.5 + (tempcount * 2)
|
||||
local Positions = self:_GetUnitPositions(randomcoord, rad, heading, _template)
|
||||
self.DroppedTroops[self.TroopCounter] = SPAWN:NewWithAlias(_template, alias)
|
||||
:InitDelayOff()
|
||||
:InitSetUnitAbsolutePositions(Positions)
|
||||
:OnSpawnGroup(function(grp) grp.spawntime = timer.getTime() end)
|
||||
:SpawnFromVec2(randomcoord:GetVec2())
|
||||
self:__TroopsDeployed(1, Group, Unit, self.DroppedTroops[self.TroopCounter], cType)
|
||||
end
|
||||
|
||||
foundCargo:SetWasDropped(true)
|
||||
if cType == CTLD_CARGO.Enum.ENGINEERS then
|
||||
self.Engineers = self.Engineers + 1
|
||||
self:_SendMessage(string.format("Dropped Engineers %s into action!", name), 10, false, Group)
|
||||
else
|
||||
-- We did not find any troop cargo with that ID
|
||||
self:_SendMessage(string.format("No troop cargo with ID %d found or already dropped!", cargoID), 10, false, Group)
|
||||
self:_SendMessage(string.format("Dropped Troops %s into action!", name), 10, false, Group)
|
||||
end
|
||||
|
||||
table.remove(chunk, 1)
|
||||
if #chunk == 0 then
|
||||
self.TroopsIDToChunk[chunkID] = nil
|
||||
end
|
||||
|
||||
else
|
||||
-- droppingatbase logic
|
||||
self:_SendMessage("Troops have returned to base!", 10, false, Group)
|
||||
-- Return to base logic, remove ONLY the first cargo
|
||||
self:_SendMessage("Troops have returned to base!", 10, false, Group)
|
||||
self:__TroopsRTB(1, Group, Unit, zonename, zone)
|
||||
|
||||
--------------------------------------------------------------------
|
||||
-- (NEW CODE FOR SINGLE DROP AT BASE)
|
||||
-- If you want to return only the single cargo item with cargoID to stock
|
||||
-- instead of returning all, you can do something similar here:
|
||||
--------------------------------------------------------------------
|
||||
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()
|
||||
if self.TroopsIDToChunk and self.TroopsIDToChunk[chunkID] then
|
||||
local chunk = self.TroopsIDToChunk[chunkID]
|
||||
if #chunk > 0 then
|
||||
local firstObj = chunk[1]
|
||||
local cName = firstObj:GetName()
|
||||
local gentroops = self.Cargo_Troops
|
||||
for _id, _troop in pairs(gentroops) do
|
||||
if _troop.Name == cName then
|
||||
@ -4622,53 +4684,42 @@ function CTLD:_UnloadSingleTroopByID(Group, Unit, cargoID)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Mark it as dropped so we remove it from the loaded cargo
|
||||
cObj:SetWasDropped(true)
|
||||
firstObj:SetWasDropped(true)
|
||||
table.remove(chunk, 1)
|
||||
if #chunk == 0 then
|
||||
self.TroopsIDToChunk[chunkID] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- cleanup load list
|
||||
------------------------------------------------------------------------
|
||||
local cargoList = self.Loaded_Cargo[unitname].Cargo
|
||||
|
||||
-- 1) Remove all dropped cargo (iterate backward for table.remove)
|
||||
local cargoList = self.Loaded_Cargo[unitName].Cargo
|
||||
for i = #cargoList, 1, -1 do
|
||||
if cargoList[i]:WasDropped() then
|
||||
table.remove(cargoList, i)
|
||||
end
|
||||
end
|
||||
|
||||
-- 2) Recount
|
||||
local troopsLoaded = 0
|
||||
local cratesLoaded = 0
|
||||
for _, cargo in ipairs(cargoList) do
|
||||
local cType = cargo:GetType()
|
||||
if cType == CTLD_CARGO.Enum.TROOPS or cType == CTLD_CARGO.Enum.ENGINEERS then
|
||||
-- If each cargo item represents just 1 group (or “1 load of troops”):
|
||||
local cT = cargo:GetType()
|
||||
if cT == CTLD_CARGO.Enum.TROOPS or cT == CTLD_CARGO.Enum.ENGINEERS then
|
||||
troopsLoaded = troopsLoaded + 1
|
||||
-- If you track “troops loaded” by `CratesNeeded()`,
|
||||
-- then do: troopsLoaded = troopsLoaded + cargo:GetCratesNeeded()
|
||||
else
|
||||
cratesLoaded = cratesLoaded + 1
|
||||
end
|
||||
end
|
||||
|
||||
self.Loaded_Cargo[unitname].Troopsloaded = troopsLoaded
|
||||
self.Loaded_Cargo[unitname].Cratesloaded = cratesLoaded
|
||||
|
||||
self.Loaded_Cargo[unitName].Troopsloaded = troopsLoaded
|
||||
self.Loaded_Cargo[unitName].Cratesloaded = cratesLoaded
|
||||
self:_RefreshDropTroopsMenu(Group, Unit)
|
||||
|
||||
|
||||
else
|
||||
if IsHerc then
|
||||
local isHerc = self:IsHercules(Unit)
|
||||
if isHerc then
|
||||
self:_SendMessage("Nothing loaded or not within airdrop parameters!", 10, false, Group)
|
||||
else
|
||||
self:_SendMessage("Nothing loaded or not hovering within parameters!", 10, false, Group)
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@ -4678,31 +4729,46 @@ end
|
||||
-- @param Wrapper.Unit#UNIT Unit The requesting unit.
|
||||
-- @return #CTLD self
|
||||
function CTLD:_RefreshDropTroopsMenu(Group, Unit)
|
||||
local theGroup=Group
|
||||
local theUnit=Unit
|
||||
local theGroup = Group
|
||||
local theUnit = Unit
|
||||
if not theGroup.CTLDTopmenu then return end
|
||||
local topTroops=theGroup.MyTopTroopsMenu
|
||||
local topTroops = theGroup.MyTopTroopsMenu
|
||||
if not topTroops then return end
|
||||
if topTroops.DropTroopsMenu then topTroops.DropTroopsMenu:Remove() end
|
||||
local dropTroopsMenu=MENU_GROUP:New(theGroup,"Drop Troops",topTroops)
|
||||
topTroops.DropTroopsMenu=dropTroopsMenu
|
||||
MENU_GROUP_COMMAND:New(theGroup,"Drop ALL troops",dropTroopsMenu,self._UnloadTroops,self,theGroup,theUnit)
|
||||
local loadedData=self.Loaded_Cargo[theUnit:GetName()]
|
||||
if loadedData and loadedData.Cargo then
|
||||
for i,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()
|
||||
then
|
||||
local name=cargoObj:GetName()or"Unknown"
|
||||
local size=cargoObj:GetCratesNeeded()or 1
|
||||
local cID=cargoObj:GetID()
|
||||
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
|
||||
if topTroops.DropTroopsMenu then
|
||||
topTroops.DropTroopsMenu:Remove()
|
||||
end
|
||||
local dropTroopsMenu = MENU_GROUP:New(theGroup, "Drop Troops", topTroops)
|
||||
topTroops.DropTroopsMenu = dropTroopsMenu
|
||||
MENU_GROUP_COMMAND:New(theGroup, "Drop ALL troops", dropTroopsMenu, self._UnloadTroops, self, theGroup, theUnit)
|
||||
|
||||
local loadedData = self.Loaded_Cargo[theUnit:GetName()]
|
||||
if not loadedData or not loadedData.Cargo then return end
|
||||
|
||||
-- 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()
|
||||
then
|
||||
local name = cargoObj:GetName() or "Unknown"
|
||||
troopsByName[name] = troopsByName[name] or {}
|
||||
table.insert(troopsByName[name], cargoObj)
|
||||
end
|
||||
end
|
||||
return self
|
||||
|
||||
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
|
||||
|
||||
--- [Internal] Function to check if a template exists in the mission.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user