diff --git a/DCS_Kola/Operation_Polar_Shield/Moose_CTLD_Init_DualCoalitions.lua b/DCS_Kola/Operation_Polar_Shield/Moose_CTLD_Init_DualCoalitions.lua index d9643cb..96bfdb6 100644 --- a/DCS_Kola/Operation_Polar_Shield/Moose_CTLD_Init_DualCoalitions.lua +++ b/DCS_Kola/Operation_Polar_Shield/Moose_CTLD_Init_DualCoalitions.lua @@ -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 }, diff --git a/Moose_CTLD_Pure/Moose_CTLD.lua b/Moose_CTLD_Pure/Moose_CTLD.lua index c2fc651..e03b7d8 100644 --- a/Moose_CTLD_Pure/Moose_CTLD.lua +++ b/Moose_CTLD_Pure/Moose_CTLD.lua @@ -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 diff --git a/Moose_CTLD_Pure/Moose_CTLD_Pure.miz b/Moose_CTLD_Pure/Moose_CTLD_Pure.miz index b8dd508..627b53e 100644 Binary files a/Moose_CTLD_Pure/Moose_CTLD_Pure.miz and b/Moose_CTLD_Pure/Moose_CTLD_Pure.miz differ diff --git a/Moose_CTLD_Pure/catalogs/Moose_CTLD_Catalog.lua b/Moose_CTLD_Pure/catalogs/Moose_CTLD_Catalog.lua index dbc148a..940e181 100644 --- a/Moose_CTLD_Pure/catalogs/Moose_CTLD_Catalog.lua +++ b/Moose_CTLD_Pure/catalogs/Moose_CTLD_Catalog.lua @@ -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 }