mirror of
https://github.com/iTracerFacer/DCS_MissionDev.git
synced 2025-12-03 04:14:46 +00:00
Updated menu system, rearranged build menu, expanded drop 1 crate options to list dynamicaly what the helo is carrying. Made single type multi crate packages spawn like multi type multi crate packages.
This commit is contained in:
parent
440e5c5e5b
commit
093fe59fd8
@ -39,6 +39,13 @@ local blueCfg = {
|
||||
{ name = 'Dallas FARP Supply', flag = 9007, activeWhen = 0 },
|
||||
{ name = 'Paris FARP Supply', flag = 9008, activeWhen = 0 },
|
||||
{ name = 'London FARP Supply', flag = 9009, activeWhen = 0 },
|
||||
{ name = 'Severomorsk-1 Supply', flag = 9104, activeWhen = 0 },
|
||||
{ name = 'Severomorsk-3 Supply', flag = 9105, activeWhen = 0 },
|
||||
{ name = 'Alakurtti Supply', flag = 9106, activeWhen = 0 },
|
||||
{ name = 'Murmansk Supply', flag = 9107, activeWhen = 0 },
|
||||
{ name = 'Olenya Supply', flag = 9108, activeWhen = 0 },
|
||||
{ name = 'Monchegorsk Supply', flag = 9109, activeWhen = 0 },
|
||||
{ name = 'Afrikanda Supply', flag = 9110, activeWhen = 0 },
|
||||
},
|
||||
--DropZones = { { name = 'BRAVO', flag = 9002, activeWhen = 0 } },
|
||||
--FOBZones = { { name = 'CHARLIE', flag = 9003, activeWhen = 0 } },
|
||||
@ -68,8 +75,7 @@ local redCfg = {
|
||||
},
|
||||
|
||||
Zones = {
|
||||
PickupZones = { { name = 'Luostari Supply', flag = 9101, activeWhen = 0 },
|
||||
{ name = 'Severomorsk-1 Supply', flag = 9104, activeWhen = 0 },
|
||||
PickupZones = { { name = 'Severomorsk-1 Supply', flag = 9104, activeWhen = 0 },
|
||||
{ name = 'Severomorsk-3 Supply', flag = 9105, activeWhen = 0 },
|
||||
{ name = 'Alakurtti Supply', flag = 9106, activeWhen = 0 },
|
||||
{ name = 'Murmansk Supply', flag = 9107, activeWhen = 0 },
|
||||
|
||||
@ -4154,8 +4154,6 @@ function CTLD:BuildGroupMenus(group)
|
||||
local navRoot = MENU_GROUP:New(group, 'Navigation', root)
|
||||
local adminRoot = MENU_GROUP:New(group, 'Admin/Help', root)
|
||||
|
||||
CMD('Show Onboard Manifest', opsRoot, function() self:ShowOnboardManifest(group) end)
|
||||
|
||||
-- Admin/Help -> Player Guides (moved to top of Admin/Help)
|
||||
local help = MENU_GROUP:New(group, 'Player Guides', adminRoot)
|
||||
MENU_GROUP_COMMAND:New(group, 'CTLD Basics (2-minute tour)', help, function()
|
||||
@ -4381,18 +4379,6 @@ function CTLD:BuildGroupMenus(group)
|
||||
CMD(string.format('Deploy [Attack (%dm)]', tr), troopsRoot, function() self:UnloadTroops(group, { behavior = 'attack' }) end)
|
||||
end
|
||||
|
||||
-- Operations -> Build
|
||||
local buildRoot = MENU_GROUP:New(group, 'Build', opsRoot)
|
||||
CMD('Build Here', buildRoot, function() self:BuildAtGroup(group) end)
|
||||
local buildAdvRoot = MENU_GROUP:New(group, 'Build (Advanced)', buildRoot)
|
||||
-- Buildable Near You (dynamic) lives directly under Build
|
||||
self:_BuildOrRefreshBuildAdvancedMenu(group, buildRoot)
|
||||
-- Refresh Buildable List (refreshes the list under Build)
|
||||
MENU_GROUP_COMMAND:New(group, 'Refresh Buildable List', buildRoot, function()
|
||||
self:_BuildOrRefreshBuildAdvancedMenu(group, buildRoot)
|
||||
MESSAGE:New('Buildable list refreshed.', 6):ToGroup(group)
|
||||
end)
|
||||
|
||||
-- Operations -> JTAC
|
||||
do
|
||||
local jtacRoot = MENU_GROUP:New(group, 'JTAC', opsRoot)
|
||||
@ -4526,11 +4512,58 @@ function CTLD:BuildGroupMenus(group)
|
||||
CMD('List JTAC Status', opsRoot, function() self:ListJTACStatus(group) end)
|
||||
CMD('JTAC Diagnostics', opsRoot, function() self:JTACDiagnostics(group) end)
|
||||
|
||||
-- Logistics -> Request Crate and Recipe Info
|
||||
CMD('Show Onboard Manifest', logRoot, function() self:ShowOnboardManifest(group) end)
|
||||
local reqRoot = MENU_GROUP:New(group, 'Request Crate', logRoot)
|
||||
local infoRoot = MENU_GROUP:New(group, 'Recipe Info', logRoot)
|
||||
if self.Config.UseCategorySubmenus then
|
||||
-- Logistics -> Crates, Build, and Recipe Details
|
||||
CMD('Show Onboard Manifest', logRoot, function() self:ShowOnboardManifest(group) end)
|
||||
local reqRoot = MENU_GROUP:New(group, 'Request Crate', logRoot)
|
||||
|
||||
local crateMgmt = MENU_GROUP:New(group, 'Crate Management', logRoot)
|
||||
CMD('Drop One Loaded Crate', crateMgmt, function() self:DropLoadedCrates(group, 1) end)
|
||||
CMD('Drop All Loaded Crates', crateMgmt, function() self:DropLoadedCrates(group, -1) end)
|
||||
self:_BuildOrRefreshLoadedCrateMenu(group, crateMgmt)
|
||||
CMD('Re-mark Nearest Crate (Smoke)', crateMgmt, function()
|
||||
local unit = group:GetUnit(1)
|
||||
if not unit or not unit:IsAlive() then return end
|
||||
local p = unit:GetPointVec3()
|
||||
local here = { x = p.x, z = p.z }
|
||||
local bestName, bestMeta, bestd
|
||||
for name,meta in pairs(CTLD._crates) do
|
||||
if meta.side == self.Side then
|
||||
local dx = (meta.point.x - here.x)
|
||||
local dz = (meta.point.z - here.z)
|
||||
local d = math.sqrt(dx*dx + dz*dz)
|
||||
if (not bestd) or d < bestd then
|
||||
bestName, bestMeta, bestd = name, meta, d
|
||||
end
|
||||
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
|
||||
_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
|
||||
end)
|
||||
|
||||
local buildRoot = MENU_GROUP:New(group, 'Build Menu', logRoot)
|
||||
CMD('Build Here', buildRoot, function() self:BuildAtGroup(group) end)
|
||||
self:_BuildOrRefreshBuildAdvancedMenu(group, buildRoot)
|
||||
MENU_GROUP_COMMAND:New(group, 'Refresh Buildable List', buildRoot, function()
|
||||
self:_BuildOrRefreshBuildAdvancedMenu(group, buildRoot)
|
||||
MESSAGE:New('Buildable list refreshed.', 6):ToGroup(group)
|
||||
end)
|
||||
|
||||
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
|
||||
@ -4545,70 +4578,89 @@ function CTLD:BuildGroupMenus(group)
|
||||
end
|
||||
return infoSubs[catLabel]
|
||||
end
|
||||
local replacementQueue = {}
|
||||
for key,def in pairs(self.Config.CrateCatalog) do
|
||||
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)
|
||||
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)
|
||||
else
|
||||
CMD(label, parent, function() self:RequestCrateForGroup(group, key) end)
|
||||
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)
|
||||
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)
|
||||
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
|
||||
if compDef and compDef.hidden and compSideOk then
|
||||
local queue = replacementQueue[catLabel]
|
||||
if not queue then
|
||||
queue = { list = {}, seen = {} }
|
||||
replacementQueue[catLabel] = queue
|
||||
end
|
||||
if not queue.seen[reqKey] then
|
||||
queue.seen[reqKey] = true
|
||||
table.insert(queue.list, { key = reqKey, def = compDef })
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
CMD(label, parent, 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)
|
||||
_msgGroup(group, text)
|
||||
end)
|
||||
end
|
||||
local infoParent = getInfoSub(catLabel)
|
||||
CMD((def and (def.menu or def.description)) or key, infoParent, function()
|
||||
local text = self:_formatRecipeInfo(key, def)
|
||||
_msgGroup(group, text)
|
||||
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)
|
||||
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 parent = getSubmenu(catLabel)
|
||||
local replMenu = MENU_GROUP:New(group, 'Replacement Crates', parent)
|
||||
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)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local replacementList = {}
|
||||
local replacementSeen = {}
|
||||
for key,def in pairs(self.Config.CrateCatalog) do
|
||||
local label = self:_formatMenuLabelWithCrates(key, def)
|
||||
local sideOk = (not def.side) or def.side == self.Side
|
||||
if sideOk then
|
||||
if def and type(def.requires) == 'table' then
|
||||
CMD(label, reqRoot, function() self:RequestRecipeBundleForGroup(group, key) end)
|
||||
else
|
||||
CMD(label, reqRoot, function() self:RequestCrateForGroup(group, key) end)
|
||||
end
|
||||
CMD(((def and (def.menu or def.description)) or key)..' (info)', infoRoot, function()
|
||||
local text = self:_formatRecipeInfo(key, def)
|
||||
_msgGroup(group, text)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Logistics -> Crate Management
|
||||
local crateMgmt = MENU_GROUP:New(group, 'Crate Management', logRoot)
|
||||
CMD('Drop One Loaded Crate', crateMgmt, function() self:DropLoadedCrates(group, 1) end)
|
||||
CMD('Drop All Loaded Crates', crateMgmt, function() self:DropLoadedCrates(group, -1) end)
|
||||
CMD('Re-mark Nearest Crate (Smoke)', crateMgmt, function()
|
||||
local unit = group:GetUnit(1)
|
||||
if not unit or not unit:IsAlive() then return end
|
||||
local p = unit:GetPointVec3()
|
||||
local here = { x = p.x, z = p.z }
|
||||
local bestName, bestMeta, bestd
|
||||
for name,meta in pairs(CTLD._crates) do
|
||||
if meta.side == self.Side then
|
||||
local dx = (meta.point.x - here.x)
|
||||
local dz = (meta.point.z - here.z)
|
||||
local d = math.sqrt(dx*dx + dz*dz)
|
||||
if (not bestd) or d < bestd then
|
||||
bestName, bestMeta, bestd = name, meta, d
|
||||
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
|
||||
if def and type(def.requires) == 'table' then
|
||||
CMD(label, reqRoot, 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
|
||||
if compDef and compDef.hidden and compSideOk and not replacementSeen[reqKey] then
|
||||
replacementSeen[reqKey] = true
|
||||
table.insert(replacementList, { key = reqKey, def = compDef })
|
||||
end
|
||||
end
|
||||
else
|
||||
CMD(label, reqRoot, function() self:RequestCrateForGroup(group, key) end)
|
||||
end
|
||||
CMD((def and (def.menu or def.description)) or key, infoParent, function()
|
||||
local text = self:_formatRecipeInfo(key, def)
|
||||
_msgGroup(group, text)
|
||||
end)
|
||||
end
|
||||
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
|
||||
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
|
||||
@ -5436,6 +5488,7 @@ end
|
||||
function CTLD:BuildSpecificAtGroup(group, recipeKey, opts)
|
||||
local unit = group:GetUnit(1)
|
||||
if not unit or not unit:IsAlive() then return end
|
||||
local ctld = self
|
||||
-- Reuse Build cooldown/confirm logic
|
||||
local now = timer.getTime()
|
||||
local gname = group:GetName()
|
||||
@ -5498,6 +5551,7 @@ function CTLD:BuildSpecificAtGroup(group, recipeKey, opts)
|
||||
if carried.byKey[key] <= 0 then carried.byKey[key] = nil end
|
||||
carried.total = math.max(0, (carried.total or 0) - take)
|
||||
removed = removed + take
|
||||
if take > 0 then ctld:_scheduleLoadedCrateMenuRefresh(group) end
|
||||
end
|
||||
end
|
||||
for _,c in ipairs(nearby) do
|
||||
@ -7074,6 +7128,7 @@ function CTLD:BuildAtGroup(group, opts)
|
||||
if carried.byKey[key] <= 0 then carried.byKey[key] = nil end
|
||||
carried.total = math.max(0, (carried.total or 0) - take)
|
||||
removed = removed + take
|
||||
if take > 0 then ctld:_scheduleLoadedCrateMenuRefresh(group) end
|
||||
end
|
||||
end
|
||||
for _,c in ipairs(nearby) do
|
||||
@ -7288,9 +7343,84 @@ function CTLD:_addLoadedCrate(group, crateKey)
|
||||
|
||||
-- Update DCS internal cargo weight
|
||||
self:_updateCargoWeight(group)
|
||||
|
||||
-- Refresh drop-by-type menu after loading
|
||||
self:_scheduleLoadedCrateMenuRefresh(group)
|
||||
end
|
||||
|
||||
function CTLD:DropLoadedCrates(group, howMany)
|
||||
function CTLD:_clearLoadedCrateMenuCommands(gname)
|
||||
self._loadedCrateMenus = self._loadedCrateMenus or {}
|
||||
local state = self._loadedCrateMenus[gname]
|
||||
if not state or not state.commands then return end
|
||||
for _,cmd in ipairs(state.commands) do
|
||||
if cmd and cmd.Remove then
|
||||
pcall(function() cmd:Remove() end)
|
||||
end
|
||||
end
|
||||
state.commands = {}
|
||||
end
|
||||
|
||||
function CTLD:_BuildOrRefreshLoadedCrateMenu(group, parentMenu)
|
||||
if not group then return end
|
||||
self._loadedCrateMenus = self._loadedCrateMenus or {}
|
||||
local gname = group:GetName()
|
||||
local state = self._loadedCrateMenus[gname] or { commands = {} }
|
||||
state.parent = parentMenu
|
||||
state.groupName = gname
|
||||
self._loadedCrateMenus[gname] = state
|
||||
|
||||
self:_clearLoadedCrateMenuCommands(gname)
|
||||
|
||||
local carried = CTLD._loadedCrates[gname]
|
||||
local byKey = (carried and carried.byKey) or {}
|
||||
local keys = {}
|
||||
for key,count in pairs(byKey) do
|
||||
if count and count > 0 then table.insert(keys, key) end
|
||||
end
|
||||
|
||||
local ctld = self
|
||||
if #keys == 0 then
|
||||
local cmd = MENU_GROUP_COMMAND:New(group, 'No crates onboard', parentMenu, function()
|
||||
_msgGroup(group, 'No crates loaded to drop individually.')
|
||||
end)
|
||||
table.insert(state.commands, cmd)
|
||||
return
|
||||
end
|
||||
|
||||
table.sort(keys, function(a, b)
|
||||
local fa = ctld:_friendlyNameForKey(a) or a
|
||||
local fb = ctld:_friendlyNameForKey(b) or b
|
||||
if fa == fb then return a < b end
|
||||
return fa < fb
|
||||
end)
|
||||
|
||||
for _,key in ipairs(keys) do
|
||||
local count = byKey[key] or 0
|
||||
local friendly = ctld:_friendlyNameForKey(key) or key
|
||||
local title = string.format('Drop %s (%d)', friendly, count)
|
||||
local cmd = MENU_GROUP_COMMAND:New(group, title, parentMenu, function()
|
||||
ctld:DropLoadedCrates(group, 1, key)
|
||||
end)
|
||||
table.insert(state.commands, cmd)
|
||||
end
|
||||
end
|
||||
|
||||
function CTLD:_scheduleLoadedCrateMenuRefresh(group)
|
||||
if not group then return end
|
||||
self._loadedCrateMenus = self._loadedCrateMenus or {}
|
||||
local gname = group:GetName()
|
||||
local state = self._loadedCrateMenus[gname]
|
||||
if not state or not state.parent then return end
|
||||
local ctld = self
|
||||
timer.scheduleFunction(function()
|
||||
local g = GROUP:FindByName(gname)
|
||||
if not g then return end
|
||||
ctld:_BuildOrRefreshLoadedCrateMenu(g, state.parent)
|
||||
return
|
||||
end, {}, timer.getTime() + 0.1)
|
||||
end
|
||||
|
||||
function CTLD:DropLoadedCrates(group, howMany, crateKey)
|
||||
local gname = group:GetName()
|
||||
local lc = CTLD._loadedCrates[gname]
|
||||
if not lc or (lc.total or 0) == 0 then _eventSend(self, group, nil, 'no_loaded_crates', {}) return end
|
||||
@ -7316,40 +7446,81 @@ function CTLD:DropLoadedCrates(group, howMany)
|
||||
local dropPt = (fwd > 0) and { x = here.x + math.sin(hdgRad) * fwd, z = here.z + math.cos(hdgRad) * fwd } or { x = here.x, z = here.z }
|
||||
local initialTotal = lc.total or 0
|
||||
local requested = (howMany and howMany > 0) and howMany or initialTotal
|
||||
local toDrop = math.min(requested, initialTotal)
|
||||
_eventSend(self, group, nil, 'drop_initiated', { count = toDrop })
|
||||
|
||||
local dropPlan = {}
|
||||
if crateKey then
|
||||
local available = lc.byKey[crateKey] or 0
|
||||
if available <= 0 then
|
||||
local friendly = self:_friendlyNameForKey(crateKey) or crateKey
|
||||
_msgGroup(group, string.format('No %s crates loaded.', friendly))
|
||||
return
|
||||
end
|
||||
local qty = math.min(requested, available)
|
||||
table.insert(dropPlan, { key = crateKey, count = qty })
|
||||
else
|
||||
local keys = {}
|
||||
for key,_ in pairs(lc.byKey) do table.insert(keys, key) end
|
||||
table.sort(keys, function(a, b)
|
||||
local fa = self:_friendlyNameForKey(a) or a
|
||||
local fb = self:_friendlyNameForKey(b) or b
|
||||
if fa == fb then return a < b end
|
||||
return fa < fb
|
||||
end)
|
||||
local remaining = math.min(requested, initialTotal)
|
||||
for _,key in ipairs(keys) do
|
||||
if remaining <= 0 then break end
|
||||
local available = lc.byKey[key] or 0
|
||||
if available > 0 then
|
||||
local qty = math.min(available, remaining)
|
||||
table.insert(dropPlan, { key = key, count = qty })
|
||||
remaining = remaining - qty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local totalToDrop = 0
|
||||
for _,entry in ipairs(dropPlan) do totalToDrop = totalToDrop + (entry.count or 0) end
|
||||
if totalToDrop <= 0 then
|
||||
_msgGroup(group, 'No valid crates selected to drop.')
|
||||
return
|
||||
end
|
||||
|
||||
_eventSend(self, group, nil, 'drop_initiated', { count = totalToDrop, key = crateKey })
|
||||
-- Warn about crate timeout when dropping
|
||||
local lifeSec = tonumber(self.Config.CrateLifetime or 0) or 0
|
||||
if lifeSec > 0 then
|
||||
local mins = math.floor((lifeSec + 30) / 60)
|
||||
_msgGroup(group, string.format('Note: Crates will despawn after %d mins to prevent clutter.', mins))
|
||||
end
|
||||
-- Drop in key order
|
||||
for k,count in pairs(DeepCopy(lc.byKey)) do
|
||||
if toDrop <= 0 then break end
|
||||
local dropNow = math.min(count, toDrop)
|
||||
local cat = self.Config.CrateCatalog[k]
|
||||
local crateWeight = (cat and cat.weightKg) or 0
|
||||
for i=1,dropNow do
|
||||
local cname = string.format('CTLD_CRATE_%s_%d', k, math.random(100000,999999))
|
||||
_spawnStaticCargo(self.Side, dropPt, (cat and cat.dcsCargoType) or 'uh1h_cargo', cname)
|
||||
CTLD._crates[cname] = { key = k, side = self.Side, spawnTime = timer.getTime(), point = { x = dropPt.x, z = dropPt.z } }
|
||||
-- Add to spatial index
|
||||
_addToSpatialGrid(cname, CTLD._crates[cname], 'crate')
|
||||
lc.byKey[k] = lc.byKey[k] - 1
|
||||
if lc.byKey[k] <= 0 then lc.byKey[k] = nil end
|
||||
lc.total = lc.total - 1
|
||||
lc.totalWeightKg = (lc.totalWeightKg or 0) - crateWeight
|
||||
toDrop = toDrop - 1
|
||||
if toDrop <= 0 then break end
|
||||
-- Drop following the prepared plan
|
||||
for _,entry in ipairs(dropPlan) do
|
||||
local k = entry.key
|
||||
local dropNow = entry.count or 0
|
||||
if dropNow > 0 then
|
||||
local cat = self.Config.CrateCatalog[k]
|
||||
local crateWeight = (cat and cat.weightKg) or 0
|
||||
for i=1,dropNow do
|
||||
local cname = string.format('CTLD_CRATE_%s_%d', k, math.random(100000,999999))
|
||||
_spawnStaticCargo(self.Side, dropPt, (cat and cat.dcsCargoType) or 'uh1h_cargo', cname)
|
||||
CTLD._crates[cname] = { key = k, side = self.Side, spawnTime = timer.getTime(), point = { x = dropPt.x, z = dropPt.z } }
|
||||
-- Add to spatial index
|
||||
_addToSpatialGrid(cname, CTLD._crates[cname], 'crate')
|
||||
lc.byKey[k] = lc.byKey[k] - 1
|
||||
if lc.byKey[k] <= 0 then lc.byKey[k] = nil end
|
||||
lc.total = lc.total - 1
|
||||
lc.totalWeightKg = (lc.totalWeightKg or 0) - crateWeight
|
||||
end
|
||||
end
|
||||
end
|
||||
local actualDropped = initialTotal - (lc.total or 0)
|
||||
_eventSend(self, group, nil, 'dropped_crates', { count = actualDropped })
|
||||
_eventSend(self, group, nil, 'dropped_crates', { count = actualDropped, key = crateKey })
|
||||
|
||||
-- Update DCS internal cargo weight after dropping
|
||||
self:_updateCargoWeight(group)
|
||||
|
||||
-- Refresh drop-by-type menu after dropping
|
||||
self:_scheduleLoadedCrateMenuRefresh(group)
|
||||
|
||||
-- Reiterate timeout after drop completes (players may miss the initial warning)
|
||||
if lifeSec > 0 then
|
||||
local mins = math.floor((lifeSec + 30) / 60)
|
||||
@ -7538,11 +7709,6 @@ 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
|
||||
|
||||
-- Resolve per-group coach enable override
|
||||
local coachEnabled = coachCfg.enabled
|
||||
if CTLD._coachOverride and CTLD._coachOverride[gname] ~= nil then
|
||||
coachEnabled = CTLD._coachOverride[gname]
|
||||
@ -7554,13 +7720,11 @@ function CTLD:ScanHoverPickup()
|
||||
if bestd <= (coachCfg.thresholds.arrivalDist or 1000) then
|
||||
_coachSend(self, group, uname, 'coach_arrival', {}, false)
|
||||
end
|
||||
-- Close-in
|
||||
if bestd <= (coachCfg.thresholds.closeDist or 100) then
|
||||
_coachSend(self, group, uname, 'coach_close', {}, false)
|
||||
end
|
||||
|
||||
-- Precision phase
|
||||
if bestd <= (coachCfg.thresholds.precisionDist or 30) then
|
||||
-- Precision phase
|
||||
if bestd <= (coachCfg.thresholds.precisionDist or 30) then
|
||||
local hdg, _ = _headingRadDeg(unit)
|
||||
local dx = (bestMeta.point.x - p3.x)
|
||||
local dz = (bestMeta.point.z - p3.z)
|
||||
@ -11377,6 +11541,16 @@ function CTLD:Cleanup()
|
||||
CTLD._buildConfirm = {}
|
||||
CTLD._buildCooldown = {}
|
||||
CTLD._jtacReservedCodes = { [coalition.side.BLUE] = {}, [coalition.side.RED] = {}, [coalition.side.NEUTRAL] = {} }
|
||||
if self._loadedCrateMenus then
|
||||
for _,state in pairs(self._loadedCrateMenus) do
|
||||
if state and state.commands then
|
||||
for _,cmd in ipairs(state.commands) do
|
||||
if cmd and cmd.Remove then pcall(function() cmd:Remove() end) end
|
||||
end
|
||||
end
|
||||
end
|
||||
self._loadedCrateMenus = {}
|
||||
end
|
||||
|
||||
-- Clear salvage state
|
||||
if CTLD._salvageCrates then
|
||||
|
||||
Binary file not shown.
@ -99,24 +99,38 @@ local RED = coalition.side.RED
|
||||
|
||||
local cat = {}
|
||||
|
||||
-- Combat Vehicles (BLUE)
|
||||
cat['BLUE_M1128_STRYKER_MGS'] = { menuCategory='Combat Vehicles', menu='M1128 Stryker MGS', description='M1128 Stryker MGS', dcsCargoType='container_cargo', required=3, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1128 Stryker MGS'), unitType='M1128 Stryker MGS', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['BLUE_M60A3_PATTON'] = { menuCategory='Combat Vehicles', menu='M-60A3 Patton', description='M-60A3 Patton', dcsCargoType='container_cargo', required=3, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-60'), unitType='M-60', MEDEVAC=true, salvageValue=3, crewSize=4 }
|
||||
cat['BLUE_HMMWV_TOW'] = { menuCategory='Combat Vehicles', menu='Humvee - TOW', description='Humvee - TOW', dcsCargoType='container_cargo', required=3, initialStock=12, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1045 HMMWV TOW'), unitType='M1045 HMMWV TOW', MEDEVAC=true, salvageValue=3, crewSize=2 }
|
||||
cat['BLUE_M1134_STRYKER_ATGM']= { menuCategory='Combat Vehicles', menu='M1134 Stryker ATGM',description='M1134 Stryker ATGM',dcsCargoType='container_cargo', required=3, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1134 Stryker ATGM'), unitType='M1134 Stryker ATGM', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['BLUE_LAV25'] = { menuCategory='Combat Vehicles', menu='LAV-25', description='LAV-25', dcsCargoType='container_cargo', required=3, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('LAV-25'), unitType='LAV-25', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['BLUE_M2A2_BRADLEY'] = { menuCategory='Combat Vehicles', menu='M2A2 Bradley', description='M2A2 Bradley', dcsCargoType='container_cargo', required=3, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-2 Bradley'), unitType='M-2 Bradley', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['BLUE_VAB_MEPHISTO'] = { menuCategory='Combat Vehicles', menu='ATGM VAB Mephisto', description='ATGM VAB Mephisto', dcsCargoType='container_cargo', required=3, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('VAB_Mephisto'), unitType='VAB_Mephisto', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['BLUE_M1A2C_ABRAMS'] = { menuCategory='Combat Vehicles', menu='M1A2C Abrams', description='M1A2C Abrams', dcsCargoType='container_cargo', required=3, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1A2C_SEP_V3'), unitType='M1A2C_SEP_V3', MEDEVAC=true, salvageValue=3, crewSize=4 }
|
||||
cat['BLUE_M1128_STRYKER_MGS_CRATE'] = { hidden=true, description='M1128 Stryker MGS crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_M1128_STRYKER_MGS'] = { menuCategory='Combat Vehicles', menu='M1128 Stryker MGS', description='M1128 Stryker MGS', dcsCargoType='container_cargo', requires={ BLUE_M1128_STRYKER_MGS_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1128 Stryker MGS'), unitType='M1128 Stryker MGS', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['BLUE_M60A3_PATTON_CRATE'] = { hidden=true, description='M-60A3 Patton crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_M60A3_PATTON'] = { menuCategory='Combat Vehicles', menu='M-60A3 Patton', description='M-60A3 Patton', dcsCargoType='container_cargo', requires={ BLUE_M60A3_PATTON_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-60'), unitType='M-60', MEDEVAC=true, salvageValue=3, crewSize=4 }
|
||||
cat['BLUE_HMMWV_TOW_CRATE'] = { hidden=true, description='Humvee - TOW crate', dcsCargoType='container_cargo', required=1, initialStock=36, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_HMMWV_TOW'] = { menuCategory='Combat Vehicles', menu='Humvee - TOW', description='Humvee - TOW', dcsCargoType='container_cargo', requires={ BLUE_HMMWV_TOW_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1045 HMMWV TOW'), unitType='M1045 HMMWV TOW', MEDEVAC=true, salvageValue=3, crewSize=2 }
|
||||
cat['BLUE_M1134_STRYKER_ATGM_CRATE']= { hidden=true, description='M1134 Stryker ATGM crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_M1134_STRYKER_ATGM'] = { menuCategory='Combat Vehicles', menu='M1134 Stryker ATGM', description='M1134 Stryker ATGM', dcsCargoType='container_cargo', requires={ BLUE_M1134_STRYKER_ATGM_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1134 Stryker ATGM'), unitType='M1134 Stryker ATGM', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['BLUE_LAV25_CRATE'] = { hidden=true, description='LAV-25 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_LAV25'] = { menuCategory='Combat Vehicles', menu='LAV-25', description='LAV-25', dcsCargoType='container_cargo', requires={ BLUE_LAV25_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('LAV-25'), unitType='LAV-25', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['BLUE_M2A2_BRADLEY_CRATE'] = { hidden=true, description='M2A2 Bradley crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_M2A2_BRADLEY'] = { menuCategory='Combat Vehicles', menu='M2A2 Bradley', description='M2A2 Bradley', dcsCargoType='container_cargo', requires={ BLUE_M2A2_BRADLEY_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-2 Bradley'), unitType='M-2 Bradley', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['BLUE_VAB_MEPHISTO_CRATE'] = { hidden=true, description='ATGM VAB Mephisto crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_VAB_MEPHISTO'] = { menuCategory='Combat Vehicles', menu='ATGM VAB Mephisto', description='ATGM VAB Mephisto', dcsCargoType='container_cargo', requires={ BLUE_VAB_MEPHISTO_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('VAB_Mephisto'), unitType='VAB_Mephisto', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['BLUE_M1A2C_ABRAMS_CRATE'] = { hidden=true, description='M1A2C Abrams crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_M1A2C_ABRAMS'] = { menuCategory='Combat Vehicles', menu='M1A2C Abrams', description='M1A2C Abrams', dcsCargoType='container_cargo', requires={ BLUE_M1A2C_ABRAMS_CRATE=3 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1A2C_SEP_V3'), unitType='M1A2C_SEP_V3', MEDEVAC=true, salvageValue=3, crewSize=4 }
|
||||
|
||||
-- Combat Vehicles (RED)
|
||||
cat['RED_BTR82A'] = { menuCategory='Combat Vehicles', menu='BTR-82A', description='BTR-82A', dcsCargoType='container_cargo', required=3, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('BTR-82A'), unitType='BTR-82A', MEDEVAC=true, salvageValue=2, crewSize=3 }
|
||||
cat['RED_BRDM2'] = { menuCategory='Combat Vehicles', menu='BRDM-2', description='BRDM-2', dcsCargoType='container_cargo', required=3, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('BRDM-2'), unitType='BRDM-2', MEDEVAC=true, salvageValue=2, crewSize=2 }
|
||||
cat['RED_BMP3'] = { menuCategory='Combat Vehicles', menu='BMP-3', description='BMP-3', dcsCargoType='container_cargo', required=3, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('BMP-3'), unitType='BMP-3', MEDEVAC=true, salvageValue=2, crewSize=3 }
|
||||
cat['RED_BMP2'] = { menuCategory='Combat Vehicles', menu='BMP-2', description='BMP-2', dcsCargoType='container_cargo', required=3, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('BMP-2'), unitType='BMP-2', MEDEVAC=true, salvageValue=2, crewSize=3 }
|
||||
cat['RED_BTR80'] = { menuCategory='Combat Vehicles', menu='BTR-80', description='BTR-80', dcsCargoType='container_cargo', required=3, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('BTR-80'), unitType='BTR-80', MEDEVAC=true, salvageValue=2, crewSize=3 }
|
||||
cat['RED_T72B3'] = { menuCategory='Combat Vehicles', menu='T-72B3', description='T-72B3', dcsCargoType='container_cargo', required=3, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('T-72B3'), unitType='T-72B3', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['RED_T90M'] = { menuCategory='Combat Vehicles', menu='T-90M', description='T-90M', dcsCargoType='container_cargo', required=3, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('CHAP_T90M'), unitType='CHAP_T90M', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['RED_BTR82A_CRATE'] = { hidden=true, description='BTR-82A crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_BTR82A'] = { menuCategory='Combat Vehicles', menu='BTR-82A', description='BTR-82A', dcsCargoType='container_cargo', requires={ RED_BTR82A_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BTR-82A'), unitType='BTR-82A', MEDEVAC=true, salvageValue=2, crewSize=3 }
|
||||
cat['RED_BRDM2_CRATE'] = { hidden=true, description='BRDM-2 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_BRDM2'] = { menuCategory='Combat Vehicles', menu='BRDM-2', description='BRDM-2', dcsCargoType='container_cargo', requires={ RED_BRDM2_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BRDM-2'), unitType='BRDM-2', MEDEVAC=true, salvageValue=2, crewSize=2 }
|
||||
cat['RED_BMP3_CRATE'] = { hidden=true, description='BMP-3 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_BMP3'] = { menuCategory='Combat Vehicles', menu='BMP-3', description='BMP-3', dcsCargoType='container_cargo', requires={ RED_BMP3_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BMP-3'), unitType='BMP-3', MEDEVAC=true, salvageValue=2, crewSize=3 }
|
||||
cat['RED_BMP2_CRATE'] = { hidden=true, description='BMP-2 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_BMP2'] = { menuCategory='Combat Vehicles', menu='BMP-2', description='BMP-2', dcsCargoType='container_cargo', requires={ RED_BMP2_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BMP-2'), unitType='BMP-2', MEDEVAC=true, salvageValue=2, crewSize=3 }
|
||||
cat['RED_BTR80_CRATE'] = { hidden=true, description='BTR-80 crate', dcsCargoType='container_cargo', required=1, initialStock=30, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_BTR80'] = { menuCategory='Combat Vehicles', menu='BTR-80', description='BTR-80', dcsCargoType='container_cargo', requires={ RED_BTR80_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('BTR-80'), unitType='BTR-80', MEDEVAC=true, salvageValue=2, crewSize=3 }
|
||||
cat['RED_T72B3_CRATE'] = { hidden=true, description='T-72B3 crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_T72B3'] = { menuCategory='Combat Vehicles', menu='T-72B3', description='T-72B3', dcsCargoType='container_cargo', requires={ RED_T72B3_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('T-72B3'), unitType='T-72B3', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
cat['RED_T90M_CRATE'] = { hidden=true, description='T-90M crate', dcsCargoType='container_cargo', required=1, initialStock=24, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_T90M'] = { menuCategory='Combat Vehicles', menu='T-90M', description='T-90M', dcsCargoType='container_cargo', requires={ RED_T90M_CRATE=3 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('CHAP_T90M'), unitType='CHAP_T90M', MEDEVAC=true, salvageValue=3, crewSize=3 }
|
||||
|
||||
-- Support (BLUE)
|
||||
cat['BLUE_MRAP_JTAC'] = { menuCategory='Support', menu='MRAP - JTAC', description='JTAC MRAP', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND, build=singleUnit('MaxxPro_MRAP'), MEDEVAC=true, salvageValue=1, crewSize=4, roles={'JTAC'}, jtac={ platform='ground' } }
|
||||
@ -131,18 +145,27 @@ cat['RED_ATZ10_TANKER'] = { menuCategory='Support', menu='ATZ-10 Refueler'
|
||||
cat['RED_EWR_1L13'] = { menuCategory='Support', menu='EWR Radar 1L13', description='EWR Radar 1L13', dcsCargoType='container_cargo', required=1, initialStock=6, side=RED, category=Group.Category.GROUND, build=singleUnit('1L13 EWR'), salvageValue=1, crewSize=3 }
|
||||
|
||||
-- Artillery (BLUE)
|
||||
cat['BLUE_MLRS'] = { menuCategory='Artillery', menu='MLRS', description='MLRS', dcsCargoType='container_cargo', required=2, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('MLRS'), salvageValue=2, crewSize=3 }
|
||||
cat['BLUE_SMERCH_CM'] = { menuCategory='Artillery', menu='Smerch_CM', description='Smerch (CM)', dcsCargoType='container_cargo', required=2, initialStock=6, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Smerch'), salvageValue=2, crewSize=3 }
|
||||
cat['BLUE_MLRS_CRATE'] = { hidden=true, description='MLRS crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_MLRS'] = { menuCategory='Artillery', menu='MLRS', description='MLRS', dcsCargoType='container_cargo', requires={ BLUE_MLRS_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('MLRS'), salvageValue=2, crewSize=3 }
|
||||
cat['BLUE_SMERCH_CM_CRATE'] = { hidden=true, description='Smerch (CM) crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_SMERCH_CM'] = { menuCategory='Artillery', menu='Smerch_CM', description='Smerch (CM)', dcsCargoType='container_cargo', requires={ BLUE_SMERCH_CM_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Smerch'), salvageValue=2, crewSize=3 }
|
||||
cat['BLUE_L118_105MM'] = { menuCategory='Artillery', menu='L118 Light Artillery 105mm', description='L118 105mm', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('L118_Unit'), salvageValue=1, crewSize=5 }
|
||||
cat['BLUE_SMERCH_HE'] = { menuCategory='Artillery', menu='Smerch_HE', description='Smerch (HE)', dcsCargoType='container_cargo', required=2, initialStock=6, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Smerch_HE'), salvageValue=2, crewSize=3 }
|
||||
cat['BLUE_M109'] = { menuCategory='Artillery', menu='M-109', description='M-109', dcsCargoType='container_cargo', required=2, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-109'), salvageValue=2, crewSize=4 }
|
||||
cat['BLUE_SMERCH_HE_CRATE'] = { hidden=true, description='Smerch (HE) crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_SMERCH_HE'] = { menuCategory='Artillery', menu='Smerch_HE', description='Smerch (HE)', dcsCargoType='container_cargo', requires={ BLUE_SMERCH_HE_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Smerch_HE'), salvageValue=2, crewSize=3 }
|
||||
cat['BLUE_M109_CRATE'] = { hidden=true, description='M-109 crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_M109'] = { menuCategory='Artillery', menu='M-109', description='M-109', dcsCargoType='container_cargo', requires={ BLUE_M109_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M-109'), salvageValue=2, crewSize=4 }
|
||||
|
||||
-- Artillery (RED)
|
||||
cat['RED_GVOZDika'] = { menuCategory='Artillery', menu='SAU Gvozdika', description='SAU Gvozdika', dcsCargoType='container_cargo', required=2, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('SAU Gvozdika'), salvageValue=2, crewSize=3 }
|
||||
cat['RED_2S19_MSTA'] = { menuCategory='Artillery', menu='SPH 2S19 Msta', description='SPH 2S19 Msta', dcsCargoType='container_cargo', required=2, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('SAU Msta'), salvageValue=2, crewSize=4 }
|
||||
cat['RED_URAGAN_BM27'] = { menuCategory='Artillery', menu='Uragan_BM-27', description='Uragan BM-27', dcsCargoType='container_cargo', required=2, initialStock=6, side=RED, category=Group.Category.GROUND, build=singleUnit('Uragan_BM-27'), salvageValue=2, crewSize=3 }
|
||||
cat['RED_BM21_GRAD'] = { menuCategory='Artillery', menu='BM-21 Grad Ural', description='BM-21 Grad Ural', dcsCargoType='container_cargo', required=2, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('Grad-URAL'), salvageValue=2, crewSize=3 }
|
||||
cat['RED_PLZ05'] = { menuCategory='Artillery', menu='PLZ-05 Mobile Artillery', description='PLZ-05', dcsCargoType='container_cargo', required=2, initialStock=6, side=RED, category=Group.Category.GROUND, build=singleUnit('PLZ05'), salvageValue=2, crewSize=4 }
|
||||
cat['RED_GVOZDIKA_CRATE'] = { hidden=true, description='SAU Gvozdika crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_GVOZDika'] = { menuCategory='Artillery', menu='SAU Gvozdika', description='SAU Gvozdika', dcsCargoType='container_cargo', requires={ RED_GVOZDIKA_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('SAU Gvozdika'), salvageValue=2, crewSize=3 }
|
||||
cat['RED_2S19_MSTA_CRATE'] = { hidden=true, description='SPH 2S19 Msta crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_2S19_MSTA'] = { menuCategory='Artillery', menu='SPH 2S19 Msta', description='SPH 2S19 Msta', dcsCargoType='container_cargo', requires={ RED_2S19_MSTA_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('SAU Msta'), salvageValue=2, crewSize=4 }
|
||||
cat['RED_URAGAN_BM27_CRATE'] = { hidden=true, description='Uragan BM-27 crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_URAGAN_BM27'] = { menuCategory='Artillery', menu='Uragan_BM-27', description='Uragan BM-27', dcsCargoType='container_cargo', requires={ RED_URAGAN_BM27_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Uragan_BM-27'), salvageValue=2, crewSize=3 }
|
||||
cat['RED_BM21_GRAD_CRATE'] = { hidden=true, description='BM-21 Grad crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_BM21_GRAD'] = { menuCategory='Artillery', menu='BM-21 Grad Ural', description='BM-21 Grad Ural', dcsCargoType='container_cargo', requires={ RED_BM21_GRAD_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Grad-URAL'), salvageValue=2, crewSize=3 }
|
||||
cat['RED_PLZ05_CRATE'] = { hidden=true, description='PLZ-05 crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_PLZ05'] = { menuCategory='Artillery', menu='PLZ-05 Mobile Artillery', description='PLZ-05', dcsCargoType='container_cargo', requires={ RED_PLZ05_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('PLZ05'), salvageValue=2, crewSize=4 }
|
||||
|
||||
-- AAA (BLUE)
|
||||
cat['BLUE_GEPARD'] = { menuCategory='AAA', menu='Gepard AAA', description='Gepard AAA', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Gepard'), salvageValue=1, crewSize=3 }
|
||||
@ -155,9 +178,12 @@ cat['RED_URAL_ZU23'] = { menuCategory='AAA', menu='Ural-375 ZU-23',
|
||||
cat['RED_SHILKA'] = { menuCategory='AAA', menu='ZSU-23-4 Shilka', description='ZSU-23-4 Shilka', dcsCargoType='container_cargo', required=1, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('ZSU-23-4 Shilka'), salvageValue=1, crewSize=3 }
|
||||
cat['RED_ZSU57_2'] = { menuCategory='AAA', menu='ZSU_57_2', description='ZSU_57_2', dcsCargoType='container_cargo', required=1, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('ZSU_57_2'), salvageValue=1, crewSize=3 }
|
||||
|
||||
cat['BLUE_M1097_AVENGER'] = { menuCategory='SAM short range', menu='M1097 Avenger', description='M1097 Avenger', dcsCargoType='container_cargo', required=2, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1097 Avenger') }
|
||||
cat['BLUE_M48_CHAPARRAL'] = { menuCategory='SAM short range', menu='M48 Chaparral', description='M48 Chaparral', dcsCargoType='container_cargo', required=2, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M48 Chaparral') }
|
||||
cat['BLUE_ROLAND_ADS'] = { menuCategory='SAM short range', menu='Roland ADS', description='Roland ADS', dcsCargoType='container_cargo', required=2, initialStock=8, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Roland ADS') }
|
||||
cat['BLUE_M1097_AVENGER_CRATE'] = { hidden=true, description='M1097 Avenger crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_M1097_AVENGER'] = { menuCategory='SAM short range', menu='M1097 Avenger', description='M1097 Avenger', dcsCargoType='container_cargo', requires={ BLUE_M1097_AVENGER_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M1097 Avenger') }
|
||||
cat['BLUE_M48_CHAPARRAL_CRATE'] = { hidden=true, description='M48 Chaparral crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_M48_CHAPARRAL'] = { menuCategory='SAM short range', menu='M48 Chaparral', description='M48 Chaparral', dcsCargoType='container_cargo', requires={ BLUE_M48_CHAPARRAL_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M48 Chaparral') }
|
||||
cat['BLUE_ROLAND_ADS_CRATE'] = { hidden=true, description='Roland ADS crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=BLUE, category=Group.Category.GROUND }
|
||||
cat['BLUE_ROLAND_ADS'] = { menuCategory='SAM short range', menu='Roland ADS', description='Roland ADS', dcsCargoType='container_cargo', requires={ BLUE_ROLAND_ADS_CRATE=2 }, initialStock=0, side=BLUE, category=Group.Category.GROUND, build=singleUnit('Roland ADS') }
|
||||
cat['BLUE_M6_LINEBACKER'] = { menuCategory='SAM short range', menu='M6 Linebacker', description='M6 Linebacker', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('M6 Linebacker') }
|
||||
cat['BLUE_RAPIER_LN'] = { menuCategory='SAM short range', menu='Rapier Launcher', description='Rapier Launcher', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('rapier_fsa_launcher') }
|
||||
cat['BLUE_RAPIER_SR'] = { menuCategory='SAM short range', menu='Rapier SR', description='Rapier SR', dcsCargoType='container_cargo', required=1, initialStock=10, side=BLUE, category=Group.Category.GROUND, build=singleUnit('rapier_fsa_blindfire_radar') }
|
||||
@ -166,12 +192,17 @@ cat['BLUE_RAPIER_SITE'] = { menuCategory='SAM short range', menu='Rapier -
|
||||
build=multiUnits({ {type='rapier_fsa_launcher'}, {type='rapier_fsa_blindfire_radar', dx=12, dz=6}, {type='rapier_fsa_optical_tracker_unit', dx=-12, dz=6} }) }
|
||||
|
||||
-- SAM short range (RED)
|
||||
cat['RED_OSA_9K33'] = { menuCategory='SAM short range', menu='9K33 Osa', description='9K33 Osa', dcsCargoType='container_cargo', required=2, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('Osa 9A33 ln') }
|
||||
cat['RED_STRELA1_9P31'] = { menuCategory='SAM short range', menu='9P31 Strela-1', description='9P31 Strela-1', dcsCargoType='container_cargo', required=2, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('Strela-1 9P31') }
|
||||
cat['RED_TUNGUSKA_2S6'] = { menuCategory='SAM short range', menu='2K22 Tunguska', description='2K22 Tunguska', dcsCargoType='container_cargo', required=2, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('2S6 Tunguska') }
|
||||
cat['RED_STRELA10M3'] = { menuCategory='SAM short range', menu='SA-13 Strela-10M3', description='SA-13 Strela-10M3', dcsCargoType='container_cargo', required=2, initialStock=8, side=RED, category=Group.Category.GROUND, build=singleUnit('Strela-10M3') }
|
||||
cat['RED_OSA_9K33_CRATE'] = { hidden=true, description='9K33 Osa crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_OSA_9K33'] = { menuCategory='SAM short range', menu='9K33 Osa', description='9K33 Osa', dcsCargoType='container_cargo', requires={ RED_OSA_9K33_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Osa 9A33 ln') }
|
||||
cat['RED_STRELA1_9P31_CRATE'] = { hidden=true, description='9P31 Strela-1 crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_STRELA1_9P31'] = { menuCategory='SAM short range', menu='9P31 Strela-1', description='9P31 Strela-1', dcsCargoType='container_cargo', requires={ RED_STRELA1_9P31_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Strela-1 9P31') }
|
||||
cat['RED_TUNGUSKA_2S6_CRATE'] = { hidden=true, description='2K22 Tunguska crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_TUNGUSKA_2S6'] = { menuCategory='SAM short range', menu='2K22 Tunguska', description='2K22 Tunguska', dcsCargoType='container_cargo', requires={ RED_TUNGUSKA_2S6_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('2S6 Tunguska') }
|
||||
cat['RED_STRELA10M3_CRATE'] = { hidden=true, description='SA-13 Strela-10M3 crate', dcsCargoType='container_cargo', required=1, initialStock=16, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_STRELA10M3'] = { menuCategory='SAM short range', menu='SA-13 Strela-10M3', description='SA-13 Strela-10M3', dcsCargoType='container_cargo', requires={ RED_STRELA10M3_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('Strela-10M3') }
|
||||
-- HQ-7 components and site
|
||||
cat['RED_HQ7_LN'] = { menuCategory='SAM short range', menu='HQ-7_Launcher', description='HQ-7 Launcher', dcsCargoType='container_cargo', required=2, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('HQ-7_LN_SP') }
|
||||
cat['RED_HQ7_LN_CRATE'] = { hidden=true, description='HQ-7 Launcher crate', dcsCargoType='container_cargo', required=1, initialStock=20, side=RED, category=Group.Category.GROUND }
|
||||
cat['RED_HQ7_LN'] = { menuCategory='SAM short range', menu='HQ-7_Launcher', description='HQ-7 Launcher', dcsCargoType='container_cargo', requires={ RED_HQ7_LN_CRATE=2 }, initialStock=0, side=RED, category=Group.Category.GROUND, build=singleUnit('HQ-7_LN_SP') }
|
||||
cat['RED_HQ7_STR'] = { menuCategory='SAM short range', menu='HQ-7_STR_SP', description='HQ-7 STR', dcsCargoType='container_cargo', required=1, initialStock=10, side=RED, category=Group.Category.GROUND, build=singleUnit('HQ-7_STR_SP') }
|
||||
cat['RED_HQ7_SITE'] = { menuCategory='SAM short range', menu='HQ-7 - All crates', description='HQ-7 Site', dcsCargoType='container_cargo', requires={ RED_HQ7_LN=1, RED_HQ7_STR=1 }, initialStock=0, side=RED, category=Group.Category.GROUND,
|
||||
build=multiUnits({ {type='HQ-7_LN_SP'}, {type='HQ-7_STR_SP', dx=10, dz=8} }) }
|
||||
@ -237,7 +268,7 @@ cat['BLUE_MQ9'] = { menuCategory='Drones', menu='MQ-9 Reaper - JTA
|
||||
cat['RED_WINGLOONG'] = { menuCategory='Drones', menu='WingLoong-I - JTAC', description='WingLoong-I JTAC', dcsCargoType='container_cargo', required=1, initialStock=3, side=RED, category=Group.Category.AIRPLANE, build=singleAirUnit('WingLoong-I'), roles={'JTAC'}, jtac={ platform='air' } }
|
||||
|
||||
-- FOB crates (Support) — three small crates build a FOB site
|
||||
cat['FOB_SMALL'] = { menuCategory='Support', menu='FOB Crate - Small', description='FOB small crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=nil, category=Group.Category.GROUND, build=function(point, headingDeg)
|
||||
cat['FOB_SMALL'] = { hidden=true, description='FOB small crate', dcsCargoType='container_cargo', required=1, initialStock=12, side=nil, category=Group.Category.GROUND, build=function(point, headingDeg)
|
||||
-- spawns a harmless placeholder truck for visibility; consumed by FOB_SITE build
|
||||
return singleUnit('Ural-375')(point, headingDeg)
|
||||
end }
|
||||
@ -245,7 +276,7 @@ cat['FOB_SITE'] = { menuCategory='Support', menu='FOB Crates - All
|
||||
build=multiUnits({ {type='HEMTT TFFT'}, {type='Ural-375 PBU', dx=10, dz=8}, {type='Ural-375', dx=-10, dz=8} }) }
|
||||
|
||||
-- Mobile MASH (Support) — three crates build a Mobile MASH unit
|
||||
cat['MOBILE_MASH_SMALL'] = { menuCategory='Support', menu='Mobile MASH Crate', description='Mobile MASH crate', dcsCargoType='container_cargo', required=1, initialStock=6, side=nil, category=Group.Category.GROUND, build=function(point, headingDeg)
|
||||
cat['MOBILE_MASH_SMALL'] = { hidden=true, description='Mobile MASH crate', dcsCargoType='container_cargo', required=1, initialStock=6, side=nil, category=Group.Category.GROUND, build=function(point, headingDeg)
|
||||
-- spawns placeholder truck for visibility; consumed by MOBILE_MASH build
|
||||
return singleUnit('Ural-375')(point, headingDeg)
|
||||
end }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user