From d14a0dc78e35c760ee12e4cf79b9e44de5229582 Mon Sep 17 00:00:00 2001 From: dutchie031 Date: Tue, 8 Sep 2026 08:13:17 +0200 Subject: [PATCH 1/5] Added mission type deepstrike --- src/classes/fleetClasses/FleetGroup.lua | 2 +- .../fleetClasses/GlobalFleetManager.lua | 2 +- src/classes/persistence/Persistence.lua | 2 +- src/classes/spearhead_db.lua | 37 ++++++++++++------- .../stageClasses/Stages/BaseStage/Stage.lua | 6 +++ .../helpers/MissionCommandsHelper.lua | 10 ++--- .../helpers/SupplyConfigHelper.lua | 2 +- .../missions/BuildableMission.lua | 2 +- .../stageClasses/missions/ZoneMission.lua | 30 +++++++++------ .../missions/baseMissions/Mission.lua | 14 +++++-- src/classes/util/Util.lua | 16 ++++---- 11 files changed, 75 insertions(+), 48 deletions(-) diff --git a/src/classes/fleetClasses/FleetGroup.lua b/src/classes/fleetClasses/FleetGroup.lua index 48d7671..4107b53 100644 --- a/src/classes/fleetClasses/FleetGroup.lua +++ b/src/classes/fleetClasses/FleetGroup.lua @@ -72,7 +72,7 @@ function FleetGroup:new(fleetGroupName, database, logger) return nil, nil end - if Util.startswith(namePart, "%[") == true then + if Util.startsWith(namePart, "%[") == true then namePart = Util.split_string(namePart, "[")[1] end diff --git a/src/classes/fleetClasses/GlobalFleetManager.lua b/src/classes/fleetClasses/GlobalFleetManager.lua index 11aa78c..02b65f9 100644 --- a/src/classes/fleetClasses/GlobalFleetManager.lua +++ b/src/classes/fleetClasses/GlobalFleetManager.lua @@ -15,7 +15,7 @@ GlobalFleetManager.start = function(database) local all_groups = MizGroupsManager.getAllGroupNames() for _, groupName in pairs(all_groups) do - if Util.startswith(string.lower(groupName), "carriergroup" ) == true then + if Util.startsWith(string.lower(groupName), "carriergroup" ) == true then logger:info("Registering " .. groupName .. " as a managed fleet") local carrierGroup = FleetGroup:new(groupName, database, logger) table.insert(fleetGroups, carrierGroup) diff --git a/src/classes/persistence/Persistence.lua b/src/classes/persistence/Persistence.lua index d96f3cf..3cb08e3 100644 --- a/src/classes/persistence/Persistence.lua +++ b/src/classes/persistence/Persistence.lua @@ -148,7 +148,7 @@ do for file in lfs.dir(dir) do local split = Util.split_string(file, ".") - local doesStartWith = Util.startswith(file, startsWith, true) + local doesStartWith = Util.startsWith(file, startsWith, true) if split and #split > 0 and split[#split] == EXTENSION and doesStartWith == true then local numberString = split[#split-1] local number = tonumber(numberString) diff --git a/src/classes/spearhead_db.lua b/src/classes/spearhead_db.lua index c60bc0b..ef29de8 100644 --- a/src/classes/spearhead_db.lua +++ b/src/classes/spearhead_db.lua @@ -69,6 +69,7 @@ local StageDrawing = require("classes.stageClasses.drawings.StageDrawing") ---@field descriptionLocation Vec2? ---@field dependsOn Array ---@field completeAt number? +---@field primaryOverwrite boolean? ---@class FarpZoneData ---@field groups Array @@ -211,7 +212,7 @@ function Database.New(Logger) for i, layer in pairs(env.mission.drawings.layers) do if string.lower(layer.name) == "author" then for key, layer_object in pairs(layer.objects) do - if Util.startswith(string.lower(layer_object.name), "buildable", true) == true then + if Util.startsWith(string.lower(layer_object.name), "buildable", true) == true then local airbaseData = self:getAirbaseDataForDrawLayer(layer_object) if airbaseData then self._logger:debug("found airbase data for " .. layer_object.name) @@ -231,7 +232,7 @@ function Database.New(Logger) for i, layer in pairs(env.mission.drawings.layers) do if string.lower(layer.name) == "author" then for key, layer_object in pairs(layer.objects) do - if Util.startswith(layer_object.name, "drawing_", true) then + if Util.startsWith(layer_object.name, "drawing_", true) then local object = layer_object --[[@as DrawingObject]] local stageDrawing = StageDrawing.New(object) if stageDrawing then @@ -259,7 +260,7 @@ function Database.New(Logger) for i, layer in pairs(env.mission.drawings.layers) do if string.lower(layer.name) == "author" then for key, layer_object in pairs(layer.objects) do - if Util.startswith(string.lower(layer_object.name), "stagebriefing_", true) == true then + if Util.startsWith(string.lower(layer_object.name), "stagebriefing_", true) == true then local zone = DcsUtil.getZoneByName(stageZoneName) local vec2 = { x = layer_object.mapX, y = layer_object.mapY } if zone and Util.is2dPointInZone(vec2, zone) == true then @@ -484,7 +485,7 @@ end local getAvailableCAPGroups = function() local result = {} for name, value in pairs(is_group_taken) do - if value == false and Util.startswith(name, "CAP") then + if value == false and Util.startsWith(name, "CAP") then table.insert(result, name) end end @@ -587,11 +588,11 @@ function Database:loadCapUnits() for _, groupName in pairs(groups) do is_group_taken[groupName] = true - if Util.startswith(groupName, "CAP_A", true) or Util.startswith(groupName, "CAP_B", true) then + if Util.startsWith(groupName, "CAP_A", true) or Util.startsWith(groupName, "CAP_B", true) then table.insert(baseData.CapGroups, groupName) - elseif Util.startswith(groupName, "CAP_I", true) then + elseif Util.startsWith(groupName, "CAP_I", true) then table.insert(baseData.InterceptGroups, groupName) - elseif Util.startswith(groupName, "CAP_S", true) then + elseif Util.startsWith(groupName, "CAP_S", true) then table.insert(baseData.SweepGroups, groupName) end end @@ -614,7 +615,7 @@ function Database:loadBlueSamUnits() local triggerZone = DcsUtil.getZoneByName(blueSamZone) if triggerZone then for _, kvPair in pairs(triggerZone.properties) do - if kvPair.key and Util.startswith(kvPair.key, "buildable") then + if kvPair.key and Util.startsWith(kvPair.key, "buildable") then local number = tonumber(kvPair.value) if number and number > 0 then samData.buildingKilos = number @@ -626,7 +627,7 @@ function Database:loadBlueSamUnits() local vec2 = { x = layer_object.mapX, y = layer_object.mapY } if triggerZone and Util.is2dPointInZone(vec2, triggerZone) then - if layer_object.name and Util.startswith(layer_object.name, "supplybriefing_", true) then + if layer_object.name and Util.startsWith(layer_object.name, "supplybriefing_", true) then local description = layer_object.text if description and description ~= "" then samData.briefing = description @@ -702,9 +703,9 @@ function Database:LoadZoneData(missionZoneName) if triggerZone and triggerZone.properties then for _, kvPair in pairs(triggerZone.properties) do local key = kvPair.key - if Util.startswith(key, "dependson", true) == true then + if Util.startsWith(key, "dependson", true) == true then table.insert(self._tables.MissionZoneData[missionZoneName].dependsOn, kvPair.value) - elseif Util.startswith(key, "completeat") == true then + elseif Util.startsWith(key, "completeat") == true then local value = tonumber(kvPair.value) if value then if value > 1 and value <= 100 then @@ -714,6 +715,14 @@ function Database:LoadZoneData(missionZoneName) end self._tables.MissionZoneData[missionZoneName].completeAt = value end + elseif Util.startsWith(key, "primary", true) == true then + if type(kvPair.value) == "string" then + if kvPair.value == "true" then + self._tables.MissionZoneData[missionZoneName].primaryOverwrite = true + elseif kvPair.value == "false" then + self._tables.MissionZoneData[missionZoneName].primaryOverwrite = false + end + end end end end @@ -726,7 +735,7 @@ function Database:LoadZoneData(missionZoneName) local vec2 = { x = layer_object.mapX, y = layer_object.mapY } if triggerZone and Util.is2dPointInZone(vec2, triggerZone) then - if layer_object.name and Util.startswith(layer_object.name, "briefing_", true) then + if layer_object.name and Util.startsWith(layer_object.name, "briefing_", true) then local description = layer_object.text if description and description ~= "" then self._tables.MissionZoneData[missionZoneName].description = description @@ -769,7 +778,7 @@ function Database:loadFarpData() local triggerZone = DcsUtil.getZoneByName(farpZone) if triggerZone then for _, kvPair in pairs(triggerZone.properties) do - if kvPair.key and Util.startswith(kvPair.key, "buildable", true) == true then + if kvPair.key and Util.startsWith(kvPair.key, "buildable", true) == true then local number = tonumber(kvPair.value) if number and number > 0 then farpzoneData.buildingKilos = number @@ -782,7 +791,7 @@ function Database:loadFarpData() local vec2 = { x = layer_object.mapX, y = layer_object.mapY } if triggerZone and Util.is2dPointInZone(vec2, triggerZone) then - if layer_object.name and Util.startswith(layer_object.name, "supplybriefing_", true) then + if layer_object.name and Util.startsWith(layer_object.name, "supplybriefing_", true) then local description = layer_object.text if description and description ~= "" then farpzoneData.briefing = description diff --git a/src/classes/stageClasses/Stages/BaseStage/Stage.lua b/src/classes/stageClasses/Stages/BaseStage/Stage.lua index 69d2f4f..87e802d 100644 --- a/src/classes/stageClasses/Stages/BaseStage/Stage.lua +++ b/src/classes/stageClasses/Stages/BaseStage/Stage.lua @@ -432,6 +432,12 @@ function Stage:PreActivate() end end + for key, mission in pairs(self._db.missions) do + if mission and mission.missionType == "DEEPSTRIKE" then + mission:SpawnActive() + end + end + for _, airbase in pairs(self._db.airbases) do airbase:ActivateRedStage() end diff --git a/src/classes/stageClasses/helpers/MissionCommandsHelper.lua b/src/classes/stageClasses/helpers/MissionCommandsHelper.lua index b9f33fb..17ee91f 100644 --- a/src/classes/stageClasses/helpers/MissionCommandsHelper.lua +++ b/src/classes/stageClasses/helpers/MissionCommandsHelper.lua @@ -212,7 +212,7 @@ function MissionCommandsHelper:OverviewToGroup(groupID) for code, enabled in pairs(self.enabledByCode) do if enabled == true then local mission = self.missionsByCode[code] - if mission and mission:getState() == "ACTIVE" and mission.priority == "primary" then + if mission and mission:getState() == "ACTIVE" and mission:GetPriority() == "primary" then table.insert(primaryMissions, mission) end end @@ -232,7 +232,7 @@ function MissionCommandsHelper:OverviewToGroup(groupID) for code, enabled in pairs(self.enabledByCode) do if enabled == true then local mission = self.missionsByCode[code] - if mission and mission:getState() == "ACTIVE" and mission.priority == "secondary" then + if mission and mission:getState() == "ACTIVE" and mission:GetPriority() == "secondary" then table.insert(secondaryMissions, mission) end end @@ -347,7 +347,7 @@ function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID) for code, enabled in pairs(self.enabledByCode) do if enabled == true then local mission = self.missionsByCode[code] - if mission and mission.priority == "primary" then + if mission and mission:GetPriority() == "primary" then table.insert(primaryMissions, mission) end end @@ -376,7 +376,7 @@ function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID) for code, enabled in pairs(self.enabledByCode) do if enabled == true then local mission = self.missionsByCode[code] - if mission and mission.priority == "secondary" then + if mission and mission:GetPriority() == "secondary" then table.insert(secondaryMissions, mission) end end @@ -418,7 +418,7 @@ function MissionCommandsHelper:addMissionCommands(groupId, path, mission) end local missionFolderName = "[" .. - mission.code .. "]" .. distance .. mission.name .. "( " .. mission.missionTypeDisplay .. " )" + mission.code .. "]" .. distance .. mission.name .. "(" .. mission.missionTypeDisplay .. ")" missionCommands.addSubMenuForGroup(groupId, missionFolderName, path) table.insert(path, missionFolderName) diff --git a/src/classes/stageClasses/helpers/SupplyConfigHelper.lua b/src/classes/stageClasses/helpers/SupplyConfigHelper.lua index 885bd87..da3b256 100644 --- a/src/classes/stageClasses/helpers/SupplyConfigHelper.lua +++ b/src/classes/stageClasses/helpers/SupplyConfigHelper.lua @@ -76,7 +76,7 @@ local SupplyConfigHelper = {} ---@return SupplyConfig? function SupplyConfigHelper.fromObjectName(name) for configName, config in pairs(SupplyConfig) do - if Util.startswith(name, configName, true) == true then + if Util.startsWith(name, configName, true) == true then return config end end diff --git a/src/classes/stageClasses/missions/BuildableMission.lua b/src/classes/stageClasses/missions/BuildableMission.lua index cc0b5b7..3ff0272 100644 --- a/src/classes/stageClasses/missions/BuildableMission.lua +++ b/src/classes/stageClasses/missions/BuildableMission.lua @@ -258,7 +258,7 @@ function BuildableMission:CheckCratesInZone() local crates = self._supplyUnitsTracker:GetCargoCratesDropped() for _, staticObject in pairs(crates) do - if staticObject and staticObject:isExist() and Util.startswith(staticObject:getName(), self._crateType, true) then + if staticObject and staticObject:isExist() and Util.startsWith(staticObject:getName(), self._crateType, true) then local pos = staticObject:getPoint() if Util.is3dPointInZone(pos, self._dropOffZone) then diff --git a/src/classes/stageClasses/missions/ZoneMission.lua b/src/classes/stageClasses/missions/ZoneMission.lua index 8be5f72..447ea64 100644 --- a/src/classes/stageClasses/missions/ZoneMission.lua +++ b/src/classes/stageClasses/missions/ZoneMission.lua @@ -14,7 +14,7 @@ local DcsUtil = require("classes.util.DcsUtil") ---@field private _completeAtIndex number ---@field private _parentStage Stage ---@field private _battleManager? BattleManager ----@field private _lastContactMarkerID number; +---@field private _lastContactMarkerID number local ZoneMission = {} --- @class MissionGroups @@ -24,7 +24,7 @@ local ZoneMission = {} --- @field unitsAlive table> --- @field targetsAlive table> --- @field sceneryTargets Array ---- @field groupNamesPerunit table +--- @field groupNamesPerUnit table ---@class ParsedMissionName ---@field missionName string @@ -36,7 +36,7 @@ local ZoneMission = {} local function ParseZoneName(input) local split_name = Util.split_string(input, "_") local split_length = Util.tableLength(split_name) - if Util.startswith(input, "RANDOMMISSION") == true and split_length < 4 then + if Util.startsWith(input, "RANDOMMISSION") == true and split_length < 4 then MissionEditorWarnings.Add("Random Mission with zonename " .. input .. " not in right format") return nil elseif split_length < 3 then @@ -53,9 +53,10 @@ local function ParseZoneName(input) if inputType == "cas" then parsedType = "CAS" end if inputType == "bai" then parsedType = "BAI" end if inputType == "sam" then parsedType = "SAM" end + if inputType == "deepstrike" then parsedType = "DEEPSTRIKE" end if parsedType == "nil" then - MissionEditorWarnings.Add("Mission with zonename '" .. + MissionEditorWarnings.Add("Mission with zoneName '" .. input .. "' has an unsupported type '" .. (type or "nil")) return nil end @@ -66,8 +67,6 @@ local function ParseZoneName(input) } end -MINIMAL_UNITS_ALIVE_RATIO = 0.21 - ---comment ---@param zoneName string ---@param priority MissionPriority @@ -91,6 +90,14 @@ function ZoneMission.new(zoneName, priority, database, logger, parentStage, spaw local missionData = database:getMissionDataForZone(zoneName) if not missionData then return end + if missionData.primaryOverwrite ~= nil then + if missionData.primaryOverwrite == true then + priority = "primary" + else + priority= "secondary" + end + end + local missionBriefing = missionData.description or "No briefing available" local success, error = Mission.newSuper(self, zoneName, parsed.missionName, parsed.type, missionBriefing, priority, @@ -112,7 +119,7 @@ function ZoneMission.new(zoneName, priority, database, logger, parentStage, spaw unitsAlive = {}, targetsAlive = {}, hasTargets = false, - groupNamesPerunit = {}, + groupNamesPerUnit = {}, sceneryTargets = {} } @@ -150,17 +157,17 @@ function ZoneMission.new(zoneName, priority, database, logger, parentStage, spaw local spearheadGroup = SpearheadGroup.New(groupName, spawnManager, true) table.insert(self._missionGroups.redGroups, spearheadGroup) - local isGroupTarget = Util.startswith(string.lower(groupName), "tgt_") + local isGroupTarget = Util.startsWith(string.lower(groupName), "tgt_") for _, unit in pairs(spearheadGroup:GetObjects()) do local unitName = unit:getName() - local isUnitTarget = Util.startswith(string.lower(unitName), "tgt_") + local isUnitTarget = Util.startsWith(string.lower(unitName), "tgt_") if self._missionGroups.unitsAlive[groupName] == nil then self._missionGroups.unitsAlive[groupName] = {} end self._missionGroups.unitsAlive[groupName][unitName] = true - self._missionGroups.groupNamesPerunit[unitName] = groupName + self._missionGroups.groupNamesPerUnit[unitName] = groupName if isGroupTarget == true or isUnitTarget == true then self._missionGroups.hasTargets = true @@ -180,7 +187,6 @@ function ZoneMission.new(zoneName, priority, database, logger, parentStage, spaw if self.missionType == "CAS" then self._battleManager = BattleManager.New(self._missionGroups.redGroups, self._missionGroups.blueGroups, self.zoneName, self._logger.LogLevel) - end self._logger:debug("Mission " .. self.name .. " group count: " .. Util.tableLength(missionData.RedGroups)) @@ -480,7 +486,7 @@ function ZoneMission:OnUnitLost(object) local unitName = object:getName() self._logger:debug("UnitName:" .. unitName) - local groupName = self._missionGroups.groupNamesPerunit[unitName] + local groupName = self._missionGroups.groupNamesPerUnit[unitName] self._missionGroups.unitsAlive[groupName][unitName] = false if self._missionGroups.targetsAlive[groupName] and self._missionGroups.targetsAlive[groupName][unitName] then diff --git a/src/classes/stageClasses/missions/baseMissions/Mission.lua b/src/classes/stageClasses/missions/baseMissions/Mission.lua index f5272b7..4a48a6b 100644 --- a/src/classes/stageClasses/missions/baseMissions/Mission.lua +++ b/src/classes/stageClasses/missions/baseMissions/Mission.lua @@ -9,7 +9,7 @@ local GlobalConfig = require("classes.configuration.GlobalConfig") ---@field zoneName string ---@field missionType MissionType ---@field missionTypeDisplay string ----@field priority MissionPriority +---@field private _priority MissionPriority ---@field location Vec2? ---@field code string ---@field protected _state MissionState @@ -40,7 +40,7 @@ function Mission.newSuper(self, zoneName, missionName, missionType, missionBrief self.zoneName = zoneName self.name = missionName self.missionType = missionType - self.priority = priority + self._priority = priority self._state = "NEW" self._logger = logger self._database = database @@ -64,6 +64,11 @@ end --region PUBLIC +---@return MissionPriority +function Mission:GetPriority() + return self._priority +end + function Mission:SpawnPersistedState() end function Mission:SpawnActive() end @@ -112,7 +117,7 @@ end function Mission:NotifyMissionComplete() self._missionCommandsHelper:RemoveMissionToCommands(self) self._logger:info("Mission Completed: " .. self.zoneName) - trigger.action.outText("Mission " .. self.name .. " [" .. self.code .. "] was completed succesfully", 20) + trigger.action.outText("Mission " .. self.name .. " [" .. self.code .. "] was completed successfully", 20) for _, listener in pairs(self._completeListeners) do pcall(function() @@ -120,7 +125,7 @@ function Mission:NotifyMissionComplete() end) end - local succ, err = pcall(function() + local success, err = pcall(function() SpearheadAPI.Internal.notifyMissionComplete(self.zoneName) end) @@ -153,6 +158,7 @@ do --aliases --- @alias MissionType --- | "nil" --- | "STRIKE" + --- | "DEEPSTRIKE" --- | "CAS" --- | "BAI" --- | "DEAD" diff --git a/src/classes/util/Util.lua b/src/classes/util/Util.lua index f8366c4..345ae7a 100644 --- a/src/classes/util/Util.lua +++ b/src/classes/util/Util.lua @@ -1,13 +1,13 @@ ---@class Util local UTIL = {} do -- INIT UTIL - ---splits a string in sub parts by seperator + ---splits a string in sub parts by separator ---@param input string - ---@param seperator string + ---@param separator string ---@return table result list of strings - function UTIL.split_string(input, seperator) - if seperator == nil then - seperator = " " + function UTIL.split_string(input, separator) + if separator == nil then + separator = " " end local result = {} @@ -15,7 +15,7 @@ do -- INIT UTIL return result end - for str in string.gmatch(input, "[^" .. seperator .. "]+") do + for str in string.gmatch(input, "[^" .. separator .. "]+") do table.insert(result, str) end return result @@ -120,7 +120,7 @@ do -- INIT UTIL ---@param findable string ---@param ignoreCase boolean? ---@return boolean - UTIL.startswith = function(str, findable, ignoreCase) + UTIL.startsWith = function(str, findable, ignoreCase) if ignoreCase == true then return string.lower(str):find('^' .. string.lower(findable)) ~= nil end @@ -150,7 +150,7 @@ do -- INIT UTIL ---@return boolean UTIL.startswithAny = function(str, findableTable) for key, value in pairs(findableTable) do - if type(value) == "string" and UTIL.startswith(str, value) then return true end + if type(value) == "string" and UTIL.startsWith(str, value) then return true end end return false end -- 2.54.0 From 52f840c2703e990fcd6ddd651a5b2d962a694c0e Mon Sep 17 00:00:00 2001 From: dutchie031 Date: Tue, 8 Sep 2026 15:47:11 +0200 Subject: [PATCH 2/5] Initial Deep Strike implementation --- .docs/web/js/components/sidebar.js | 2 +- .docs/web/pages/advanced/missions.html | 136 ++++++++++++++---- .docs/web/style/style.css | 2 +- .../stageClasses/missions/ZoneMission.lua | 32 +++-- .../missions/baseMissions/Mission.lua | 2 +- 5 files changed, 133 insertions(+), 41 deletions(-) diff --git a/.docs/web/js/components/sidebar.js b/.docs/web/js/components/sidebar.js index c4b685a..a786af7 100644 --- a/.docs/web/js/components/sidebar.js +++ b/.docs/web/js/components/sidebar.js @@ -169,7 +169,7 @@ class Sidebar extends HTMLElement { render() { var betaHtml = ''; - if (true || window.location.hostname.toLowerCase() == 'beta.spearhead.rocks') { + if (window.location.hostname.toLowerCase() == 'beta.spearhead.rocks') { betaHtml = 'You are looking at docs that are released with the beta version.'; } diff --git a/.docs/web/pages/advanced/missions.html b/.docs/web/pages/advanced/missions.html index 49c07bb..85f0e1e 100644 --- a/.docs/web/pages/advanced/missions.html +++ b/.docs/web/pages/advanced/missions.html @@ -26,42 +26,118 @@

Advanced Tutorial: Missions

-

Strike

-

- Naming: MISSION_STRIKE_[Name]
-

-

Specific Targets

-

TBD

+
+

Strike

+

+ Naming: MISSION_STRIKE_[Name]
+

+

Specific Targets

+

TBD

+

Scenery Targets

+

+ Bridges, buildings or other type of targets that are baked into the map are awesome targets.
+ We wanted to make sure they were easily integrated in Spearhead. +

-

Scenery Targets

-

- Bridges, buildings or other type of targets that are baked into the map are awesome targets.
- We wanted to make sure they were easily integrated in Spearhead. -

- - - Spearhead detects scenery targets by the trigger zone name. A zone named scenerytarget_[freeform] or - scenerytargets (case-insensitive) will be scanned and any scenery objects that has the attribute "Buildings" inside the zone - will be added as mission scenery targets. - - -

- Scenery targets are treated like mission targets: they are included in the mission completion calculation - (their `IsAlive()` state is checked) and their state is persisted/updated when missions spawn or resume. -

- - - Due to Object IDs changing when maps are updated and edited the "Assign as..." functionality does not work for scenery targets. - Hence the need to use trigger zones to define them. + + Spearhead detects scenery targets by the trigger zone name. A zone named + scenerytarget_[freeform] or + scenerytargets (case-insensitive) will be scanned and any scenery objects that + has the attribute "Buildings" inside the zone + will be added as mission scenery targets. - -

Here's two images showing how a bridge is added to a mission.

- +

+ Scenery targets are treated like mission targets: they are included in the mission completion + calculation + (their `IsAlive()` state is checked) and their state is persisted/updated when missions spawn or + resume. +

+ + + Due to Object IDs changing when maps are updated and edited the "Assign as..." functionality + does not work for scenery targets. + Hence the need to use trigger zones to define them. + + + +

Here's two images showing how a bridge is added to a mission.

+ +
+
+

CAS

+

+ Naming: MISSION_CAS_[Name]
+

+ +

Battle Manager

+

TBD

+
+
+

DEAD

+

+ Naming: MISSION_DEAD_[Name]
+ Naming: MISSION_SAM_[Name]
+

+ +

SAM vs DEAD

+

TBD

+
+ +
+

BAI

+

+ Naming: MISSION_BAI_[Name]
+

+
+ +
+

DEEPSTRIKE

+

+ Naming: MISSION_DEEPSTRIKE_[Name]
+
+ When you, as a mission editor, want to create a mission that's further away from the current front-line you can use the Deep Strike mission type.
+ This allows you to plan missions that require more strategic positioning and timing.
+

+ +

Activation

+

+ Deep Strike missions are activated when the Stage in which they are located becomes "PreActive" or "Active".
+ "PreActive" is when either the current active StageNumber is a certain number of stages away OR the stage has "CAP" airbases active .
+ SpearheadConfig.StageConfig.preactivateStage changes the configuration.
+
+ For example:
+ If the current active stage is MissionStage_2_[name] and preActivate config is set to 2.
+ Then both MissionStage_3_[name] and MissionStage_4_[name] would become "PreActive". +

+

Make Primary

+

+ By default DEEPSTRIKE missions are "Secondary" missions when spawned as a pre-activated stage.
+ Then when the stage they are in is "Active", the mission becomes a "Primary" mission.
+
+ If you want to make it a "Primary" mission from the start, you can overwrite it.
+ Click the mission's trigger zone. Add a property named primary and set it to true. + This will make the mission "Primary" from the start.
+
+ If you want it to "Secondary" even when its stage is the active stage, you can set "primary" to false.
+
+ If you want to have it be "Secondary" when its stage is "Pre-Active" and "primary" when its stage is "Active" you don't have to do anything. +

+ +

Future

+

+ In the future we're thinking it would be cool to make the Deep Strike missions + be more integrated with the CAP airbases and/or logistics.
+ Eg. Completing a DEEPSTRIKE mission would disable CAP for X amount of minutes after completion.
+ This still needs to be refined, but we've already have ideas. +

+ +
+
- +