More menu updates.

This commit is contained in:
iTracerFacer 2025-11-15 00:32:43 -06:00
parent 093fe59fd8
commit 9c406cb83e
5 changed files with 158 additions and 107 deletions

View File

@ -1,4 +1,4 @@
env.info('*** MOOSE GITHUB Commit Hash ID: 2025-11-11T12:57:41+01:00-d7b0b3c898fb636dd8b728721e247763383a5bdb ***')
env.info('*** MOOSE GITHUB Commit Hash ID: 2025-11-14T17:27:02+01:00-cdbf1e147e76dcfab3d1bc471edf593a0e92182a ***')
if not MOOSE_DEVELOPMENT_FOLDER then
MOOSE_DEVELOPMENT_FOLDER='Scripts'
end
@ -31462,6 +31462,7 @@ self.Life0=Life0
else
self:E(string.format("Static object %s does not exist!",tostring(self.StaticName)))
end
self._vec3=self:GetVec3()
return self
end
function STATIC:GetLife0()
@ -31474,6 +31475,20 @@ return DCSStatic:getLife()or 1
end
return nil
end
function STATIC:GetVec2Cached()
local vec2=self:GetVec2()
if not vec2 and self._vec3 then
vec2={x=self._vec3.x,y=self._vec3.z}
end
return vec2
end
function STATIC:GetVec3Cached()
local vec3=self:GetVec3()
if not vec3 and self._vec3 then
vec3=self._vec3
end
return vec3
end
function STATIC:Find(DCSStatic)
local StaticName=DCSStatic:getName()
local StaticFound=_DATABASE:FindStatic(StaticName)
@ -31539,6 +31554,7 @@ SCHEDULER:New(nil,self.SpawnAt,{self,Coordinate,Heading},Delay)
else
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName)
SpawnStatic:SpawnFromPointVec2(Coordinate,Heading,self.StaticName)
self._vec3=self:GetVec3()
end
return self
end
@ -31549,6 +31565,7 @@ else
CountryID=CountryID or self:GetCountry()
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName,CountryID)
SpawnStatic:Spawn(nil,self.StaticName)
self._vec3=self:GetVec3()
end
return self
end
@ -31558,6 +31575,7 @@ SCHEDULER:New(nil,self.ReSpawnAt,{self,Coordinate,Heading},Delay)
else
local SpawnStatic=SPAWNSTATIC:NewFromStatic(self.StaticName,self:GetCountry())
SpawnStatic:SpawnFromCoordinate(Coordinate,Heading,self.StaticName)
self._vec3=self:GetVec3()
end
return self
end
@ -134336,6 +134354,16 @@ local Vector=NavFix.vector:Translate(UTILS.NMToMeters(Distance),Bearing,true)
self=NAVFIX:NewFromVector(Name,Type,Vector)
return self
end
function NAVFIX:NewFromBeacon(Beacon)
local frequency,unit=BEACONS:_GetFrequency(Beacon.frequency)
frequency=string.format("%.3f",frequency)
if Beacon.typeName=="TACAN"then
frequency=Beacon.channel
unit="X"
end
self=NAVFIX:NewFromVector(string.format("%s %s %s",Beacon.typeName,frequency,unit),Beacon.typeName,Beacon.vec3)
return self
end
function NAVFIX:SetIntermediateFix(IntermediateFix)
self.isIF=IntermediateFix
return self
@ -134549,9 +134577,18 @@ return closest
end
function BEACONS:GetBeacons(TypeID)
local beacons={}
local keys={}
if TypeID~=nil and type(TypeID)~="table"then
TypeID={TypeID}
end
for _,_typeid in pairs(TypeID or{})do
if _typeid~=nil then
keys[_typeid]=_typeid
end
end
for _,_beacon in pairs(self.beacons)do
local bc=_beacon
if TypeID==nil or TypeID==bc.type then
if TypeID==nil or keys[bc.type]~=nil then
table.insert(beacons,bc)
end
end

View File

@ -4537,16 +4537,13 @@ function CTLD:BuildGroupMenus(group)
end
end
if bestName and bestMeta then
local zdef = { smoke = self.Config.PickupZoneSmokeColor }
local sx, sz = bestMeta.point.x, bestMeta.point.z
local sy = 0
if land and land.getHeight then
-- land.getHeight expects Vec2 where y is z
local ok, h = pcall(land.getHeight, { x = sx, y = sz })
if ok and type(h) == 'number' then sy = h end
end
-- Use new smoke helper with crate ID for refresh scheduling
local smokeColor = (zdef and zdef.smoke) or self.Config.PickupZoneSmokeColor
local smokeColor = self.Config.PickupZoneSmokeColor
_spawnCrateSmoke({ x = sx, y = sy, z = sz }, smokeColor, self.Config.CrateSmoke, bestName)
_eventSend(self, group, nil, 'crate_re_marked', { id = bestName, mark = 'smoke' })
else
@ -4564,13 +4561,14 @@ function CTLD:BuildGroupMenus(group)
local infoRoot = MENU_GROUP:New(group, 'Recipe Info', logRoot)
if self.Config.UseCategorySubmenus then
local submenus = {}
local function getSubmenu(catLabel)
if not submenus[catLabel] then
submenus[catLabel] = MENU_GROUP:New(group, catLabel, reqRoot)
local reqSubmenus = {}
local function getRequestSub(catLabel)
if not reqSubmenus[catLabel] then
reqSubmenus[catLabel] = MENU_GROUP:New(group, catLabel, reqRoot)
end
return submenus[catLabel]
return reqSubmenus[catLabel]
end
local infoSubs = {}
local function getInfoSub(catLabel)
if not infoSubs[catLabel] then
@ -4578,17 +4576,18 @@ function CTLD:BuildGroupMenus(group)
end
return infoSubs[catLabel]
end
local replacementQueue = {}
for key,def in pairs(self.Config.CrateCatalog) do
if not (def and def.hidden) then
local label = self:_formatMenuLabelWithCrates(key, def)
local sideOk = (not def.side) or def.side == self.Side
if sideOk then
local catLabel = (def and def.menuCategory) or 'Other'
local parent = getSubmenu(catLabel)
local reqParent = getRequestSub(catLabel)
local label = self:_formatMenuLabelWithCrates(key, def)
if def and type(def.requires) == 'table' then
-- Composite recipe: request full bundle of component crates
CMD(label, parent, function() self:RequestRecipeBundleForGroup(group, key) end)
CMD(label, reqParent, function() self:RequestRecipeBundleForGroup(group, key) end)
for reqKey,_ in pairs(def.requires) do
local compDef = self.Config.CrateCatalog[reqKey]
local compSideOk = (not compDef) or (not compDef.side) or compDef.side == self.Side
@ -4605,8 +4604,9 @@ function CTLD:BuildGroupMenus(group)
end
end
else
CMD(label, parent, function() self:RequestCrateForGroup(group, key) end)
CMD(label, reqParent, function() self:RequestCrateForGroup(group, key) end)
end
local infoParent = getInfoSub(catLabel)
CMD((def and (def.menu or def.description)) or key, infoParent, function()
local text = self:_formatRecipeInfo(key, def)
@ -4615,6 +4615,7 @@ function CTLD:BuildGroupMenus(group)
end
end
end
for catLabel,queue in pairs(replacementQueue) do
if queue and queue.list and #queue.list > 0 then
table.sort(queue.list, function(a,b)
@ -4622,8 +4623,8 @@ function CTLD:BuildGroupMenus(group)
local lb = (b.def and (b.def.menu or b.def.description)) or b.key
return tostring(la) < tostring(lb)
end)
local parent = getSubmenu(catLabel)
local replMenu = MENU_GROUP:New(group, 'Replacement Crates', parent)
local reqParent = getRequestSub(catLabel)
local replMenu = MENU_GROUP:New(group, 'Replacement Crates', reqParent)
for _,entry in ipairs(queue.list) do
local replLabel = string.format('Replacement: %s', self:_formatMenuLabelWithCrates(entry.key, entry.def))
CMD(replLabel, replMenu, function() self:RequestCrateForGroup(group, entry.key) end)
@ -4635,9 +4636,9 @@ function CTLD:BuildGroupMenus(group)
local replacementSeen = {}
for key,def in pairs(self.Config.CrateCatalog) do
if not (def and def.hidden) then
local label = self:_formatMenuLabelWithCrates(key, def)
local sideOk = (not def.side) or def.side == self.Side
if sideOk then
local label = self:_formatMenuLabelWithCrates(key, def)
if def and type(def.requires) == 'table' then
CMD(label, reqRoot, function() self:RequestRecipeBundleForGroup(group, key) end)
for reqKey,_ in pairs(def.requires) do
@ -4651,25 +4652,28 @@ function CTLD:BuildGroupMenus(group)
else
CMD(label, reqRoot, function() self:RequestCrateForGroup(group, key) end)
end
CMD((def and (def.menu or def.description)) or key, infoParent, function()
CMD((def and (def.menu or def.description)) or key, infoRoot, function()
local text = self:_formatRecipeInfo(key, def)
_msgGroup(group, text)
end)
end
end
end
if #replacementList > 0 then
-- Logistics -> Show Inventory at Nearest Pickup Zone/FOB
CMD('Show Inventory at Nearest Zone', logRoot, function() self:ShowNearestZoneInventory(group) end)
end
-- Use new smoke helper with crate ID for refresh scheduling
local smokeColor = (zdef and zdef.smoke) or self.Config.PickupZoneSmokeColor
_spawnCrateSmoke({ x = sx, y = sy, z = sz }, smokeColor, self.Config.CrateSmoke, bestName)
_eventSend(self, group, nil, 'crate_re_marked', { id = bestName, mark = 'smoke' })
else
_msgGroup(group, 'No friendly crates found to mark.')
end
table.sort(replacementList, function(a,b)
local la = (a.def and (a.def.menu or a.def.description)) or a.key
local lb = (b.def and (b.def.menu or b.def.description)) or b.key
return tostring(la) < tostring(lb)
end)
local replMenu = MENU_GROUP:New(group, 'Replacement Crates', reqRoot)
for _,entry in ipairs(replacementList) do
local replLabel = string.format('Replacement: %s', self:_formatMenuLabelWithCrates(entry.key, entry.def))
CMD(replLabel, replMenu, function() self:RequestCrateForGroup(group, entry.key) end)
end
end
end
-- Logistics -> Show Inventory at Nearest Pickup Zone/FOB
CMD('Show Inventory at Nearest Zone', logRoot, function() self:ShowNearestZoneInventory(group) end)
@ -7709,22 +7713,32 @@ function CTLD:ScanHoverPickup()
-- Group doesn't exist or is dead, remove from tracking
_removeFromSpatialGrid(troopGroupName, troopMeta.point, 'troops')
CTLD._deployedTroops[troopGroupName] = nil
end
end
end
local coachEnabled = coachCfg.enabled
if CTLD._coachOverride and CTLD._coachOverride[gname] ~= nil then
coachEnabled = CTLD._coachOverride[gname]
end
-- If coach is on, provide phased guidance
if coachEnabled and bestName and bestMeta then
local thresholds = coachCfg.thresholds or {}
local isMetric = _getPlayerIsMetric(unit)
-- Arrival phase
if bestd <= (coachCfg.thresholds.arrivalDist or 1000) then
if bestd <= (thresholds.arrivalDist or 1000) then
_coachSend(self, group, uname, 'coach_arrival', {}, false)
end
-- Close-in guidance
if bestd <= (thresholds.closeDist or 100) then
_coachSend(self, group, uname, 'coach_close', {}, false)
end
-- Precision phase
if bestd <= (coachCfg.thresholds.precisionDist or 30) then
if bestd <= (thresholds.precisionDist or 30) then
local hdg, _ = _headingRadDeg(unit)
local dx = (bestMeta.point.x - p3.x)
local dz = (bestMeta.point.z - p3.z)
@ -7745,8 +7759,8 @@ function CTLD:ScanHoverPickup()
-- Vertical hint against AGL window
local vHint
local aglMin = coachCfg.thresholds.aglMin or 5
local aglMax = coachCfg.thresholds.aglMax or 20
local aglMin = thresholds.aglMin or 5
local aglMax = thresholds.aglMax or 20
if agl < aglMin then
local dv, du = _fmtAGL(aglMin - agl, isMetric)
vHint = string.format("Up %d %s", dv, du)
@ -7763,7 +7777,7 @@ function CTLD:ScanHoverPickup()
_coachSend(self, group, uname, 'coach_hint', data, true)
-- Error prompts (dominant one)
local maxGS = coachCfg.thresholds.maxGS or (8/3.6)
local maxGS = thresholds.maxGS or (8/3.6)
local aglMinT = aglMin
local aglMaxT = aglMax
if gs > maxGS then

Binary file not shown.