From 2e5a31faefaa5defe3c031e6e66421aa5de8b535 Mon Sep 17 00:00:00 2001 From: dutchie031 Date: Sat, 29 Aug 2026 15:57:29 +0200 Subject: [PATCH 1/5] Custom briefings for BlueSam and FARPS --- src/classes/spearhead_db.lua | 47 +++++++++++++++++++ .../stageClasses/SpecialZones/BlueSam.lua | 2 +- .../stageClasses/SpecialZones/FarpZone.lua | 2 +- .../SpecialZones/abstract/BuildableZone.lua | 5 +- .../missions/BuildableMission.lua | 25 ++++++++-- 5 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/classes/spearhead_db.lua b/src/classes/spearhead_db.lua index d36fcfc..cef591e 100644 --- a/src/classes/spearhead_db.lua +++ b/src/classes/spearhead_db.lua @@ -58,6 +58,7 @@ local CustomDrawing = require("classes.stageClasses.drawings.CustomDrawing") ---@class BlueSamData ---@field groups Array ---@field buildingKilos number? +---@field briefing string? ---@class MissionZoneData ---@field ZoneName string @@ -74,6 +75,7 @@ local CustomDrawing = require("classes.stageClasses.drawings.CustomDrawing") ---@field padNames Array ---@field buildingKilos number? ---@field supplyHubNames Array +---@field briefing string? ---@class Database ---@field private _tables DatabaseTables @@ -614,6 +616,27 @@ function Database:loadBlueSamUnits() local number = tonumber(kvPair.value) if number and number > 0 then samData.buildingKilos = number + + if env.mission.drawings and env.mission.drawings.layers then + 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 + + 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 + local description = layer_object.text + if description and description ~= "" then + samData.briefing = description + end + end + end + end + end + end + end + else + MissionEditorWarnings.Add("Buildable number for " .. blueSamZone .. " is invalid") end end end @@ -748,7 +771,31 @@ function Database:loadFarpData() local number = tonumber(kvPair.value) if number and number > 0 then farpzoneData.buildingKilos = number + + -- check briefings + if env.mission.drawings and env.mission.drawings.layers then + 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 + + 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 + local description = layer_object.text + if description and description ~= "" then + farpzoneData.briefing = description + end + end + end + end + end + end + end + else + MissionEditorWarnings.Add("Buildable number for " .. farpZone .. " is invalid.") end + + end end end diff --git a/src/classes/stageClasses/SpecialZones/BlueSam.lua b/src/classes/stageClasses/SpecialZones/BlueSam.lua index bc8baf8..1723fec 100644 --- a/src/classes/stageClasses/SpecialZones/BlueSam.lua +++ b/src/classes/stageClasses/SpecialZones/BlueSam.lua @@ -89,7 +89,7 @@ function BlueSam.New(database, logger, zoneName, spawnManager) local zone = DcsUtil.getZoneByName(zoneName) if zone then - BuildableZone.New(self, zone, self._buildableCrateKilos or 0, "SAM_CRATE", self._blueGroups, logger, database) + BuildableZone.New(self, zone, self._buildableCrateKilos or 0, "SAM_CRATE", self._blueGroups, logger, database, blueSamData.briefing) end return self diff --git a/src/classes/stageClasses/SpecialZones/FarpZone.lua b/src/classes/stageClasses/SpecialZones/FarpZone.lua index ec82cdb..74b329d 100644 --- a/src/classes/stageClasses/SpecialZones/FarpZone.lua +++ b/src/classes/stageClasses/SpecialZones/FarpZone.lua @@ -64,7 +64,7 @@ function FarpZone.New(database, logger, zoneName, spawnManager) local zone = DcsUtil.getZoneByName(zoneName) if zone then self._logger:debug("Creating Buildable zone: " .. zoneName .. " with " .. (farpData.buildingKilos or "nil") .. " kilos") - BuildableZone.New(self, zone, farpData.buildingKilos or 0, "FARP_CRATE", self._groups, logger, database) + BuildableZone.New(self, zone, farpData.buildingKilos or 0, "FARP_CRATE", self._groups, logger, database, farpData.briefing) end end self:Deactivate() diff --git a/src/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua b/src/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua index 5851d10..38fcada 100644 --- a/src/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua +++ b/src/classes/stageClasses/SpecialZones/abstract/BuildableZone.lua @@ -20,7 +20,8 @@ BuildableZone.__index = BuildableZone ---@param database Database ---@param crateType SupplyType ---@param logger Logger -function BuildableZone:New(targetZone, kilosRequired, crateType, buildableGroups, logger, database) +---@param briefing string? +function BuildableZone:New(targetZone, kilosRequired, crateType, buildableGroups, logger, database, briefing) self._targetZone = targetZone self._requiredKilos = kilosRequired or 0 self._buildableGroups = buildableGroups or {} @@ -69,7 +70,7 @@ function BuildableZone:New(targetZone, kilosRequired, crateType, buildableGroup local noLandingZone = self:GetNoLandingZone() if kilosRequired and kilosRequired > 0 then - self._buildableMission = BuildableMission.new(database, logger, targetZone, noLandingZone, kilosRequired, crateType) + self._buildableMission = BuildableMission.new(database, logger, targetZone, noLandingZone, kilosRequired, crateType, briefing) self._buildableMission:AddOnCrateDroppedOfListener(self) else self._buildableMission = nil diff --git a/src/classes/stageClasses/missions/BuildableMission.lua b/src/classes/stageClasses/missions/BuildableMission.lua index 7707c0c..e9e9e05 100644 --- a/src/classes/stageClasses/missions/BuildableMission.lua +++ b/src/classes/stageClasses/missions/BuildableMission.lua @@ -21,9 +21,18 @@ local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelpe ---@field private _dropOffZone SpearheadTriggerZone? ---@field private _noLandingZoneDrawing CustomDrawing? ---@field private _dropOffZoneDrawing CustomDrawing? +---@field private _briefing string? local BuildableMission = {} BuildableMission.__index = BuildableMission + +local function getDefaultBriefing(siteType, coords) + return "We've dispatched forward units to find a proper spot for a new " .. siteType .. "." .. + "\nYou will need to drop off supplies so they can start building." .. + "\nThe coords are: " .. coords .. + "\n\n" +end + ---@class OnCrateDroppedListener ---@field OnCrateDroppedOff fun(self:OnCrateDroppedListener, mission:BuildableMission, kilos:number) @@ -33,7 +42,8 @@ BuildableMission.__index = BuildableMission ---@param requiredCrateType SupplyType ---@param noLandingZone SpearheadTriggerZone? ---@param logger Logger -function BuildableMission.new(database, logger, targetZone, noLandingZone, requiredKilos, requiredCrateType) +---@param briefing string? +function BuildableMission.new(database, logger, targetZone, noLandingZone, requiredKilos, requiredCrateType, briefing) setmetatable(BuildableMission, Mission) @@ -43,6 +53,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi self._database = database self._requiredKilos = requiredKilos self._droppedKilos = 0 + self._briefing = briefing self._noLandingZone = noLandingZone @@ -81,7 +92,6 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi self._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate() self._state = "NEW" - self.location = targetZone.location self.missionType = "LOGISTICS" @@ -116,11 +126,16 @@ function BuildableMission:ShowBriefing(groupID) siteType = "airbase" end + local briefingPart = self._briefing + if briefingPart then + briefingPart = Util.replaceString(briefingPart, "{{coords}}", coords) + else + briefingPart = getDefaultBriefing(siteType, coords) + end + local briefing = "Mission [" .. self.code .. "] " .. self.name .. "\n \n" .. - "We've dispatched forward units to find a proper spot for a new " .. siteType .. "." .. - "\nYou will need to drop off supplies so they can start building." .. - "\nThe coords are: " .. coords .. + briefingPart .. "\n\n" .. "\nKilos still required: " .. self._requiredKilos - self._droppedKilos .. "\n\n" .. -- 2.54.0 From 428fe75a12be58c951d8c4de86ef6e97f537c97d Mon Sep 17 00:00:00 2001 From: dutchie031 Date: Sat, 29 Aug 2026 16:12:43 +0200 Subject: [PATCH 2/5] wip --- .docs/web/pages/reference.html | 7 +++++++ src/classes/stageClasses/missions/BuildableMission.lua | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.docs/web/pages/reference.html b/.docs/web/pages/reference.html index 34a1228..62cb294 100644 --- a/.docs/web/pages/reference.html +++ b/.docs/web/pages/reference.html @@ -253,6 +253,13 @@ To make an airbase buildable add a text box inside of the trigger zone and name it: buildable_[freeform]
Then in the text box type amount of kilo's you want to be transfered before the logistisc mission is complete.
+
+ To add a custom briefing for a buildable zone, include a text box inside the trigger zone and name it: supplybriefing_[freeform]. + {{coords}} is highly recommended for the players.
+ Additionally, the amount of kilos required and delivered are always shown on the bottom, as well as a note to not land in the construction zone. +
+ +
The base or zone will slowly build up with each crate giving both a nice view of it happening AND it's good for performance as there's not a big addition of objects at once.
Right now a crate takes 15 seconds to unpack per 500kg. Meaning 2 crates of 1000kg will be faster than 1 crate of 2000kg.
diff --git a/src/classes/stageClasses/missions/BuildableMission.lua b/src/classes/stageClasses/missions/BuildableMission.lua index e9e9e05..a4fa74e 100644 --- a/src/classes/stageClasses/missions/BuildableMission.lua +++ b/src/classes/stageClasses/missions/BuildableMission.lua @@ -75,7 +75,13 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi end self.code = tostring(database:GetNewMissionCode()) - self.name = "Resupply" + + local splitTargetZoneName = Util.split_string(targetZone.name, "_") + if splitTargetZoneName and #splitTargetZoneName[3] then + self.name = splitTargetZoneName[3] + else + self.name = "Resupply" + end local type = "site" if requiredCrateType == "SAM_CRATE" then -- 2.54.0 From 674160abbf6820cc1facc495c4c13ed7f9c2e880 Mon Sep 17 00:00:00 2001 From: dutchie031 Date: Sun, 30 Aug 2026 19:17:35 +0200 Subject: [PATCH 3/5] Update doc slightly --- .docs/web/pages/reference.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.docs/web/pages/reference.html b/.docs/web/pages/reference.html index 62cb294..0f782ee 100644 --- a/.docs/web/pages/reference.html +++ b/.docs/web/pages/reference.html @@ -255,7 +255,7 @@
To add a custom briefing for a buildable zone, include a text box inside the trigger zone and name it: supplybriefing_[freeform]. - {{coords}} is highly recommended for the players.
+ {{coords}} is highly recommended so the players can easily find their landing zone.
Additionally, the amount of kilos required and delivered are always shown on the bottom, as well as a note to not land in the construction zone.
-- 2.54.0 From 61ba4de33867e9999e77e29d677fbe69520937b4 Mon Sep 17 00:00:00 2001 From: dutchie031 Date: Sun, 30 Aug 2026 20:24:20 +0200 Subject: [PATCH 4/5] buildable mission updates --- .../stageClasses/drawings/helper/DrawingHelper.lua | 7 ++----- src/classes/stageClasses/missions/BuildableMission.lua | 2 +- src/classes/util/DcsUtil.lua | 10 ++++++++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/classes/stageClasses/drawings/helper/DrawingHelper.lua b/src/classes/stageClasses/drawings/helper/DrawingHelper.lua index 8432890..76018c5 100644 --- a/src/classes/stageClasses/drawings/helper/DrawingHelper.lua +++ b/src/classes/stageClasses/drawings/helper/DrawingHelper.lua @@ -1,4 +1,5 @@ local Util = require("classes.util.Util") +local DcsUtil = require("classes.util.DcsUtil") local Logger = require("classes.util.Logger") local GlobalConfig = require("classes.configuration.GlobalConfig") @@ -14,9 +15,6 @@ local drawingLogger = Logger.new("DrawingHelper", level) local DrawingHelper = {} DrawingHelper.__index = DrawingHelper - -local customDrawingIdIncrementer = 4210 - ---@param object DrawingObject ---@param logger Logger? ---@return integer? id @@ -50,8 +48,7 @@ function DrawingHelper.Draw(object, logger) end function DrawingHelper.GetAndAddId() - customDrawingIdIncrementer = customDrawingIdIncrementer + 1 - return customDrawingIdIncrementer + return DcsUtil.GetNextDrawID() end ---@private diff --git a/src/classes/stageClasses/missions/BuildableMission.lua b/src/classes/stageClasses/missions/BuildableMission.lua index a4fa74e..cc0b5b7 100644 --- a/src/classes/stageClasses/missions/BuildableMission.lua +++ b/src/classes/stageClasses/missions/BuildableMission.lua @@ -77,7 +77,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi self.code = tostring(database:GetNewMissionCode()) local splitTargetZoneName = Util.split_string(targetZone.name, "_") - if splitTargetZoneName and #splitTargetZoneName[3] then + if splitTargetZoneName and splitTargetZoneName[3] and splitTargetZoneName[3] ~= "" then self.name = splitTargetZoneName[3] else self.name = "Resupply" diff --git a/src/classes/util/DcsUtil.lua b/src/classes/util/DcsUtil.lua index 1fbdacd..0bdc209 100644 --- a/src/classes/util/DcsUtil.lua +++ b/src/classes/util/DcsUtil.lua @@ -632,13 +632,19 @@ do -- INIT DCS_UTIL ---@field b number ---@field a number + + local customDrawingIdIncrementer = 4210 + function DCS_UTIL.GetNextDrawID() + customDrawingIdIncrementer = customDrawingIdIncrementer + 1 + return customDrawingIdIncrementer + end ---@param groupID number ---@param text string ---@param location Vec3 ---@return number markID function DCS_UTIL.AddMarkToGroup(groupID, text, location) - drawID = drawID + 1 + local drawID = DCS_UTIL.GetNextDrawID() trigger.action.markToGroup(drawID, text, location, groupID, true, nil) return drawID end @@ -648,7 +654,7 @@ do -- INIT DCS_UTIL ---@param location Vec3 ---@return integer function DCS_UTIL.AddMarkToAll(text, location) - drawID = drawID + 1 + local drawID = DCS_UTIL.GetNextDrawID() trigger.action.markToAll(drawID, text, location, true, nil) return drawID end -- 2.54.0 From 95fe7e105853b3b0599d16709f3e5a2ae6780d7e Mon Sep 17 00:00:00 2001 From: dutchie031 Date: Mon, 7 Sep 2026 19:22:52 +0200 Subject: [PATCH 5/5] updated releasenotes --- RELEASENOTES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index f50f92b..d616329 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -15,6 +15,10 @@ These lanes can be used to create different stage progression flows and create different "side-stories". #40 +- Issue: #37 + Now enabled the mission editor to add a custom briefing to the "Buildable" missions. + #44 + ### Bug Fixes ## [0.13.0] 2026-08 -- 2.54.0