mirror of
https://github.com/iTracerFacer/DCS_MissionDev.git
synced 2025-12-03 04:14:46 +00:00
More menu updates.
This commit is contained in:
parent
093fe59fd8
commit
9c406cb83e
Binary file not shown.
Binary file not shown.
41
Moose_.lua
41
Moose_.lua
@ -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
|
||||
|
||||
@ -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.
Loading…
x
Reference in New Issue
Block a user