Merge remote-tracking branch 'origin/master' into develop

This commit is contained in:
Applevangelist 2025-05-03 17:02:29 +02:00
commit 6791a0e704
2 changed files with 672 additions and 442 deletions

View File

@ -20,11 +20,12 @@
-- --
-- ### Author: **Applevangelist** (Moose Version), ***Ciribob*** (original), Thanks to: Shadowze, Cammel (testing), bbirchnz (additional code!!) -- ### Author: **Applevangelist** (Moose Version), ***Ciribob*** (original), Thanks to: Shadowze, Cammel (testing), bbirchnz (additional code!!)
-- ### Repack addition for crates: **Raiden** -- ### Repack addition for crates: **Raiden**
-- ### Additional cool features: **Lekaa**
-- --
-- @module Ops.CTLD -- @module Ops.CTLD
-- @image OPS_CTLD.jpg -- @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.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.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.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 -- ## 2.1 CH-47 Chinook support
-- --
@ -1412,7 +1414,7 @@ CTLD.FixedWingTypes = {
--- CTLD class version. --- CTLD class version.
-- @field #string version -- @field #string version
CTLD.version="1.2.33" CTLD.version="1.3.34"
--- Instantiate a new CTLD. --- Instantiate a new CTLD.
-- @param #CTLD self -- @param #CTLD self
@ -1591,6 +1593,7 @@ function CTLD:New(Coalition, Prefixes, Alias)
self.subcats = {} self.subcats = {}
self.subcatsTroop = {} self.subcatsTroop = {}
self.showstockinmenuitems = false self.showstockinmenuitems = false
self.onestepmenu = false
-- disallow building in loadzones -- disallow building in loadzones
self.nobuildinloadzones = true self.nobuildinloadzones = true
@ -2913,10 +2916,10 @@ function CTLD:_GetCrates(Group, Unit, Cargo, number, drop, pack)
if drop then if drop then
text = string.format("Crates for %s have been dropped!",cratename) text = string.format("Crates for %s have been dropped!",cratename)
self:__CratesDropped(1, Group, Unit, droppedcargo) self:__CratesDropped(1, Group, Unit, droppedcargo)
end else
self:_SendMessage(text, 10, false, Group) self:_SendMessage(text, 10, false, Group)
end
self:_RefreshLoadCratesMenu(Group, Unit) self:_RefreshLoadCratesMenu(Group, Unit)
return self return self
end end
@ -3576,7 +3579,10 @@ end
-- @param Wrapper.Unit#UNIT Unit -- @param Wrapper.Unit#UNIT Unit
-- @return #boolean Outcome -- @return #boolean Outcome
function CTLD:IsHook(Unit) 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 return true
else else
return false return false
@ -3766,7 +3772,6 @@ function CTLD:_UnloadCrates(Group, Unit)
self:T(self.lid .. " _UnloadCrates") self:T(self.lid .. " _UnloadCrates")
if not self.dropcratesanywhere then -- #1570 if not self.dropcratesanywhere then -- #1570
-- check if we are in DROP zone
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
self:_SendMessage("You are not close enough to a drop zone!", 10, false, Group) 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 end
end end
-- Door check
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 for hover unload local hoverunload = self:IsCorrectHover(Unit)
local hoverunload = self:IsCorrectHover(Unit) --if true we\'re hovering in parameters
local IsHerc = self:IsFixedWing(Unit) local IsHerc = self:IsFixedWing(Unit)
local IsHook = self:IsHook(Unit) local IsHook = self:IsHook(Unit)
if IsHerc and (not IsHook) then if IsHerc and (not IsHook) then
-- no hover but airdrop here
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
local loadedcargo = self.Loaded_Cargo[unitname] or {} -- #CTLD.LoadedCargo local loadedcargo = self.Loaded_Cargo[unitname] or {}
-- looking for crate
local cargotable = loadedcargo.Cargo local cargotable = loadedcargo.Cargo
local droppedCount = {}
local neededMap = {}
for _,_cargo in pairs (cargotable) do for _,_cargo in pairs (cargotable) do
local cargo = _cargo -- #CTLD_CARGO local cargo = _cargo
local type = cargo:GetType() -- #CTLD_CARGO.Enum 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 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) self:_GetCrates(Group, Unit, cargo, 1, true)
cargo:SetWasDropped(true) cargo:SetWasDropped(true)
cargo:SetHasMoved(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
end end
-- cleanup load list end
local loaded = {} -- #CTLD.LoadedCargo 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.Troopsloaded = 0
loaded.Cratesloaded = 0 loaded.Cratesloaded = 0
loaded.Cargo = {} loaded.Cargo = {}
for _,_cargo in pairs (cargotable) do for _,_cargo in pairs (cargotable) do
local cargo = _cargo -- #CTLD_CARGO local cargo = _cargo
local type = cargo:GetType() -- #CTLD_CARGO.Enum local type = cargo:GetType()
local size = cargo:GetCratesNeeded() local size = cargo:GetCratesNeeded()
if type == CTLD_CARGO.Enum.TROOPS or type == CTLD_CARGO.Enum.ENGINEERS then if type == CTLD_CARGO.Enum.TROOPS or type == CTLD_CARGO.Enum.ENGINEERS then
table.insert(loaded.Cargo,_cargo) table.insert(loaded.Cargo,_cargo)
@ -3838,14 +3857,15 @@ function CTLD:_UnloadCrates(Group, Unit)
end end
end end
return self return self
end end
--- (Internal) Function to build nearby crates. --- (Internal) Function to build nearby crates.
-- @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
-- @param #boolean Engineering If true build is by an engineering team. -- @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") self:T(self.lid .. " _BuildCrates")
-- avoid users trying to build from flying Hercs -- avoid users trying to build from flying Hercs
if self:IsFixedWing(Unit) and self.enableFixedWing and not Engineering then 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 if build.CanBuild then
self:_CleanUpCrates(crates,build,number) self:_CleanUpCrates(crates,build,number)
if self.buildtime and self.buildtime > 0 then 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) buildtimer:Start(self.buildtime)
self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group) self:_SendMessage(string.format("Build started, ready in %d seconds!",self.buildtime),15,false,Group)
self:__CratesBuildStarted(1,Group,Unit) self:__CratesBuildStarted(1,Group,Unit)
self:_RefreshDropTroopsMenu(Group,Unit)
else else
self:_BuildObjectFromCrates(Group,Unit,build) self:_BuildObjectFromCrates(Group,Unit,build,false,nil,MultiDrop)
end end
end 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 _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:_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 self:_RefreshLoadCratesMenu(Group,Unit) -- call the refresher to show the crates in the menu
return self return true
end end
end end
end end
end end
end end
return self self:_SendMessage("Nothing to pack at this distance pilot!",10,false,Group)
return false
end end
--- (Internal) Function to repair nearby vehicles / FOBs --- (Internal) Function to repair nearby vehicles / FOBs
@ -4082,7 +4104,8 @@ end
-- @param #CTLD.Buildable Build -- @param #CTLD.Buildable Build
-- @param #boolean Repair If true this is a repair and not a new 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) -- @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") self:T(self.lid .. " _BuildObjectFromCrates")
-- Spawn-a-crate-content -- Spawn-a-crate-content
if Group and Group:IsAlive() or (RepairLocation and not Repair) then 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 if type(temptable) == "string" then
temptable = {temptable} temptable = {temptable}
end end
local zone = nil local zone = nil -- Core.Zone#ZONE_RADIUS
if RepairLocation and not Repair then if RepairLocation and not Repair then
-- timed build -- timed build
zone = ZONE_RADIUS:New(string.format("Build zone-%d",math.random(1,10000)),RepairLocation:GetVec2(),100) 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 end
--local randomcoord = zone:GetRandomCoordinate(35):GetVec2() --local randomcoord = zone:GetRandomCoordinate(35):GetVec2()
local randomcoord = Build.Coord or 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 if Repair then
randomcoord = RepairLocation:GetVec2() randomcoord = RepairLocation:GetVec2()
end end
@ -4199,11 +4226,91 @@ function CTLD:_CleanUpCrates(Crates,Build,Number)
return self return self
end 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. --- (Internal) Housekeeping - Function to refresh F10 menus.
-- @param #CTLD self -- @param #CTLD self
-- @return #CTLD self -- @return #CTLD self
function CTLD:_RefreshF10Menus() function CTLD:_RefreshF10Menus()
self:T(self.lid .. " _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 -- 1) Gather all the pilot groups from our Set
local PlayerSet = self.PilotGroups local PlayerSet = self.PilotGroups
@ -4314,7 +4421,6 @@ function CTLD:_RefreshF10Menus()
local menutext = cargoObj.Name local menutext = cargoObj.Name
if (stock >= 0) and (self.showstockinmenuitems == true) then menutext = menutext.." ["..stock.."]" end 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) MENU_GROUP_COMMAND:New(_group, menutext, troopsmenu, self._LoadTroops, self, _group, _unit, cargoObj)
end end
end end
end end
@ -4340,11 +4446,65 @@ function CTLD:_RefreshF10Menus()
_group.MyTopCratesMenu = topcrates _group.MyTopCratesMenu = topcrates
-- Build the “Get Crates” sub-menu items -- Build the “Get Crates” sub-menu items
local cratesmenu = MENU_GROUP:New(_group, "Get Crates", topcrates) 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 if self.usesubcats then
local subcatmenus = {} local subcatmenus = {}
for catName, _ in pairs(self.subcats) do for catName, _ in pairs(self.subcats) do
subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) subcatmenus[catName] = MENU_GROUP:New(_group, catName, cratesmenu) -- fixed variable case
end end
for _, cargoObj in pairs(self.Cargo_Crates) do for _, cargoObj in pairs(self.Cargo_Crates) do
if not cargoObj.DontShowInMenu then if not cargoObj.DontShowInMenu then
@ -4384,14 +4544,15 @@ function CTLD:_RefreshF10Menus()
end end
end end
end end
end
local loadCratesMenu=MENU_GROUP:New(_group,"Load Crates",topcrates) local loadCratesMenu=MENU_GROUP:New(_group,"Load Crates",topcrates)
_group.MyLoadCratesMenu=loadCratesMenu _group.MyLoadCratesMenu=loadCratesMenu
MENU_GROUP_COMMAND:New(_group,"Load ALL",loadCratesMenu,self._LoadCratesNearby,self,_group,_unit) MENU_GROUP_COMMAND:New(_group,"Load ALL",loadCratesMenu,self._LoadCratesNearby,self,_group,_unit)
MENU_GROUP_COMMAND:New(_group,"Show loadable crates",loadCratesMenu,self._RefreshLoadCratesMenu,self,_group,_unit) MENU_GROUP_COMMAND:New(_group,"Show loadable crates",loadCratesMenu,self._RefreshLoadCratesMenu,self,_group,_unit)
local dropCratesMenu=MENU_GROUP:New(_group,"Drop Crates",topcrates) local dropCratesMenu = MENU_GROUP:New(_group,"Drop Crates",topcrates)
topcrates.DropCratesMenu=dropCratesMenu topcrates.DropCratesMenu = dropCratesMenu
if not self.nobuildmenu then if not self.nobuildmenu then
MENU_GROUP_COMMAND:New(_group, "Build crates", topcrates, self._BuildCrates, self, _group, _unit) MENU_GROUP_COMMAND:New(_group, "Build crates", topcrates, self._BuildCrates, self, _group, _unit)
@ -4401,8 +4562,16 @@ function CTLD:_RefreshF10Menus()
local removecratesmenu = MENU_GROUP:New(_group, "Remove crates", topcrates) local removecratesmenu = MENU_GROUP:New(_group, "Remove crates", topcrates)
MENU_GROUP_COMMAND:New(_group, "Remove crates nearby", removecratesmenu, self._RemoveCratesNearby, self, _group, _unit) 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, "Pack crates", topcrates, self._PackCratesNearby, self, _group, _unit)
MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit) MENU_GROUP_COMMAND:New(_group, "List crates nearby", topcrates, self._ListCratesNearby, self, _group, _unit)
end
local uName = _unit:GetName() local uName = _unit:GetName()
local loadedData = self.Loaded_Cargo[uName] local loadedData = self.Loaded_Cargo[uName]
@ -4423,8 +4592,6 @@ function CTLD:_RefreshF10Menus()
end end
end end
----------------------------------------------------- -----------------------------------------------------
-- Misc submenus -- Misc submenus
----------------------------------------------------- -----------------------------------------------------
@ -4453,7 +4620,7 @@ function CTLD:_RefreshF10Menus()
-- Mark we built the menu -- Mark we built the menu
self.MenusDone[_unitName] = true self.MenusDone[_unitName] = true
self:_RefreshLoadCratesMenu(_group, _unit) self:_RefreshLoadCratesMenu(_group,_unit)
self:_RefreshDropCratesMenu(_group,_unit) self:_RefreshDropCratesMenu(_group,_unit)
end -- if _group end -- if _group
@ -4464,45 +4631,53 @@ function CTLD:_RefreshF10Menus()
end -- for all pilot units end -- for all pilot units
return self return self
end end
--- (Internal) Function to refresh the menu for load crates. Triggered from land/getcrate/pack and more --- (Internal) Function to refresh the menu for load crates. Triggered from land/getcrate/pack and more
-- @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.
-- @return #CTLD self -- @return #CTLD self
function CTLD:_RefreshLoadCratesMenu(Group, Unit) function CTLD:_RefreshLoadCratesMenu(Group,Unit)
if not Group.MyLoadCratesMenu then return end if not Group.MyLoadCratesMenu then return end
Group.MyLoadCratesMenu:RemoveSubMenus() Group.MyLoadCratesMenu:RemoveSubMenus()
local d = self.CrateDistance or 35 local d=self.CrateDistance or 35
local nearby, n = self:_FindCratesNearby(Group, Unit, d, true, true) local nearby,n=self:_FindCratesNearby(Group,Unit,d,true,true)
if n == 0 then if n==0 then
MENU_GROUP_COMMAND:New(Group, "No crates found! Rescan?", Group.MyLoadCratesMenu, function() self:_RefreshLoadCratesMenu(Group, Unit) end) MENU_GROUP_COMMAND:New(Group,"No crates found! Rescan?",Group.MyLoadCratesMenu,function() self:_RefreshLoadCratesMenu(Group,Unit) end)
return return
end end
MENU_GROUP_COMMAND:New(Group, "Load ALL", Group.MyLoadCratesMenu, self._LoadCratesNearby, self, Group, Unit) MENU_GROUP_COMMAND:New(Group,"Load ALL",Group.MyLoadCratesMenu,self._LoadCratesNearby,self,Group,Unit)
local cargoByName = {}
for _, crate in pairs(nearby) do local cargoByName={}
local cName = crate:GetName() for _,crate in pairs(nearby) do
cargoByName[cName] = cargoByName[cName] or {} local name=crate:GetName()
table.insert(cargoByName[cName], crate) cargoByName[name]=cargoByName[name] or{}
table.insert(cargoByName[name],crate)
end end
for cName, cList in pairs(cargoByName) do local lineIndex=1
local needed = cList[1]:GetCratesNeeded() or 1 for cName,list in pairs(cargoByName) do
local found = #cList local needed=list[1]:GetCratesNeeded() or 1
table.sort(list,function(a,b)return a:GetID()<b:GetID() end)
local line local i=1
if found >= needed then while i<=#list do
line = string.format("Load %s", cName) local left=#list-i+1
local label
if left>=needed then
label=string.format("%d. Load %s",lineIndex,cName)
i=i+needed
else else
MENU_GROUP_COMMAND:New(Group, "Rescan?", Group.MyLoadCratesMenu, function() self:_RefreshLoadCratesMenu(Group, Unit) end) label=string.format("%d. Load %s (%d/%d)",lineIndex,cName,left,needed)
line = string.format("Load %s (%d/%d)", cName, found, needed) i=#list+1
end 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 end
end
--- ---
-- Loads exactly `CratesNeeded` crates for one cargoName in range. -- Loads exactly `CratesNeeded` crates for one cargoName in range.
@ -4745,6 +4920,7 @@ end
-- @param Wrapper.Unit#UNIT Unit The calling unit. -- @param Wrapper.Unit#UNIT Unit The calling unit.
-- @return #CTLD self -- @return #CTLD self
function CTLD:_RefreshDropCratesMenu(Group, Unit) function CTLD:_RefreshDropCratesMenu(Group, Unit)
if not Group.CTLDTopmenu then return end if not Group.CTLDTopmenu then return end
local topCrates = Group.MyTopCratesMenu local topCrates = Group.MyTopCratesMenu
if not topCrates then return end if not topCrates then return end
@ -4780,7 +4956,15 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
return return
end 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) MENU_GROUP_COMMAND:New(Group,"Drop ALL crates",dropCratesMenu,self._UnloadCrates,self,Group,Unit)
self.CrateGroupList=self.CrateGroupList or{} self.CrateGroupList=self.CrateGroupList or{}
self.CrateGroupList[Unit:GetName()]={} self.CrateGroupList[Unit:GetName()]={}
@ -4815,7 +4999,53 @@ function CTLD:_RefreshDropCratesMenu(Group, Unit)
lineIndex=lineIndex+1 lineIndex=lineIndex+1
end end
end 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. --- (Internal) Function to unload a single Troop group by ID.
-- @param #CTLD self -- @param #CTLD self

View File

@ -897,7 +897,7 @@ function UNIT:GetAmmunition()
nAPshells = nAPshells + Nammo nAPshells = nAPshells + Nammo
end end
if ammotable[w].desc.typeName and string.find(ammotable[w].desc.typeName, "_HE", 1, true) then if ammotable[w].desc.typeName and (string.find(ammotable[w].desc.typeName, "_HE", 1, true) or string.find(ammotable[w].desc.typeName, "HESH", 1, true)) then
nHEshells = nHEshells + Nammo nHEshells = nHEshells + Nammo
end end