Author SHA1 Message Date
dutchie031 95fe7e1058 updated releasenotes 2026-09-07 19:22:52 +02:00
dutchie031 b8fe242c43 merged develop 2026-09-07 19:13:11 +02:00
dutchie031 772397250f Feature/lanes (#40)
Update Docs / prepare-docs (push) Successful in 37s
Publish Release / build (push) Successful in 39s
Update Docs / build-image (push) Successful in 30s
Update Docs / deploy-container (push) Successful in 20s
this fixes #35

does not close but starts work partly on #41

Reviewed-on: #40
Co-authored-by: dutchie031 <timrorije@gmail.com>
2026-09-07 17:08:26 +00:00
dutchie031 61ba4de338 buildable mission updates 2026-08-30 20:24:20 +02:00
dutchie031 674160abbf Update doc slightly 2026-08-30 19:17:35 +02:00
dutchie031 8ff25ffeb0 Merge remote-tracking branch 'origin/develop' into feature/customBriefingSupplyMissions 2026-08-30 19:13:26 +02:00
dutchie031 0a7e8ea977 also added the beta block on home screen
Update Docs / prepare-docs (push) Successful in 21s
Update Docs / build-image (push) Successful in 12s
Update Docs / deploy-container (push) Successful in 12s
2026-08-30 18:25:03 +02:00
dutchie031 96507f1d34 updated the sidebar when it's a beta version
Update Docs / prepare-docs (push) Successful in 22s
Update Docs / build-image (push) Successful in 20s
Update Docs / deploy-container (push) Successful in 16s
2026-08-30 18:17:55 +02:00
dutchie031 96ada242a4 updated to change the release name so two releases can co-exist (#46)
Reviewed-on: #46
Co-authored-by: dutchie031 <timrorije@gmail.com>
2026-08-30 12:16:19 +00:00
dutchie031 2bce1985e2 beta.spearhead.rocks now for the beta branch (#45)
Reviewed-on: #45
Co-authored-by: dutchie031 <timrorije@gmail.com>
2026-08-30 11:49:52 +00:00
dutchie031 428fe75a12 wip 2026-08-29 16:12:43 +02:00
dutchie031 2e5a31faef Custom briefings for BlueSam and FARPS 2026-08-29 15:57:29 +02:00
26 changed files with 489 additions and 206 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

+10
View File
@@ -21,6 +21,9 @@
<main> <main>
<div class="reference-container"> <div class="reference-container">
<div class="side-nav"> <div class="side-nav">
<div id="beta-box-div"></div>
<h4>Quick Links</h4> <h4>Quick Links</h4>
<ul> <ul>
<li><a href="/pages/tutorials.html" class="side-nav-h2">Tutorials</a></li> <li><a href="/pages/tutorials.html" class="side-nav-h2">Tutorials</a></li>
@@ -59,6 +62,13 @@
<footer> <footer>
<p>&copy; 2025 Spearhead Project</p> <p>&copy; 2025 Spearhead Project</p>
</footer> </footer>
<script>
if (true || window.location.hostname.toLowerCase() == 'beta.spearhead.rocks') {
betaHtml = '<note-box type="warning" title="Beta Version">You are looking at docs that are released with the beta version.</note-box>';
}
document.getElementById('beta-box-div').innerHTML = betaHtml || '';
</script>
</body> </body>
</html> </html>
+6
View File
@@ -168,8 +168,14 @@ class Sidebar extends HTMLElement {
} }
render() { render() {
var betaHtml = '';
if (window.location.hostname.toLowerCase() == 'beta.spearhead.rocks') {
betaHtml = '<note-box type="warning" title="Beta Version">You are looking at docs that are released with the beta version.</note-box>';
}
this.innerHTML = ` this.innerHTML = `
<div class="side-nav"> <div class="side-nav">
${betaHtml}
<h4 class="side-nav-title"></h4> <h4 class="side-nav-title"></h4>
<ul> <ul>
<!-- Navigation items will be populated automatically --> <!-- Navigation items will be populated automatically -->
+58 -2
View File
@@ -99,10 +99,66 @@
</p> </p>
<h3 id="mermaid-log-example">Log Example</h3> <h3 id="mermaid-log-example">Log Example</h3>
<p> TODO: Show log example</p> <code-block>
2026-09-01 17:53:13.213 INFO SCRIPTING (Main): [Spearhead][StageManager] ========== STAGE FLOW DIAGRAM ==========
graph TD
default_8["MAIN-2 (S8)"]
b_5["West Valley (S5)"]
default_1["MAIN-1 (S1)"]
a_5["WEST-2 (S5)"]
default_4["MAIN-2 (S4)"]
default_10["MAIN-1 (S10)"]
default_6["MAIN-2 (S6)"]
a_4["WEST-1 (S4)"]
default_3["MAIN-1 (S3)"]
default_9["MAIN-3 (S9)"]
a_7["WEST-2 (S7)"]
a_3["WEST (S3)"]
default_5["MAIN-3 (S5)"]
b_6["West Valley-1 (S6)"]
default_61["CAP-Maykop (S61)"]
default_7["MAIN-1 (S7)"]
default_0["START (S0)"]
a_6["WEST-3 (S6)"]
default_60["CAP-Nalchik (S60)"]
default_2["MAIN (S2)"]
a_2["WEST-1 (S2)"]
a_2 --> a_3
a_3 --> a_4
a_4 --> a_5
a_5 --> a_6
a_6 --> a_7
default_0 --> default_1
default_1 --> default_2
default_2 --> default_3
default_3 --> default_4
default_4 --> default_5
default_5 --> default_6
default_6 --> default_7
default_7 --> default_8
default_8 --> default_9
default_9 --> default_10
default_10 -->|chapter| default_60
default_60 --> default_61
b_5 --> b_6
default_2 -->|unlock| a_2
default_5 -->|unlock| b_5
a_7 -->|gate| default_60
b_6 -->|gate| default_60
========== END DIAGRAM ==========
</code-block>
<h3 id="mermaid-diagram-example">Diagram Example</h3> <h3 id="mermaid-diagram-example">Diagram Example</h3>
<p> TODO: Show diagram example</p> <p>
If you want to then copy and paste everything between the <br>
<code-inline>========== STAGE FLOW DIAGRAM ==========</code-inline> and <br>
<code-inline>========== END DIAGRAM ==========</code-inline> <br>
you will be able to go to <a href="https://mermaid.live/">https://mermaid.live/</a> and paste the diagram code into the editor. <br>
It would look like this:
</p>
<img src="/img/mermaid-preview.png" alt="Example of mermaid diagram">
<h2 id="lane-limitations">Limitations</h2> <h2 id="lane-limitations">Limitations</h2>
<h3 class="lane-limitations-cap">CAP</h3> <h3 class="lane-limitations-cap">CAP</h3>
+7
View File
@@ -253,6 +253,13 @@
To make an airbase buildable add a text box inside of the trigger zone and name it: <code-inline>buildable_[freeform]</code-inline> <br/> To make an airbase buildable add a text box inside of the trigger zone and name it: <code-inline>buildable_[freeform]</code-inline> <br/>
Then in the text box type amount of kilo's you want to be transfered before the logistisc mission is complete. <br/> Then in the text box type amount of kilo's you want to be transfered before the logistisc mission is complete. <br/>
<br>
To add a custom briefing for a buildable zone, include a text box inside the trigger zone and name it: <code-inline>supplybriefing_[freeform]</code-inline>.
<code-inline>{{coords}}</code-inline> is highly recommended so the players can easily find their landing zone.<br>
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.
<br/>
<br> <br>
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. <br/> 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. <br/>
Right now a crate takes 15 seconds to unpack per 500kg. Meaning 2 crates of 1000kg will be faster than 1 crate of 2000kg. <br/> Right now a crate takes 15 seconds to unpack per 500kg. Meaning 2 crates of 1000kg will be faster than 1 crate of 2000kg. <br/>
+19 -3
View File
@@ -4,13 +4,14 @@ on:
push: push:
branches: branches:
- main - main
- develop
paths: paths:
- '.docs/**' - '.docs/**'
env: env:
DOCKER_REGISTRY: registry.dutchie031.net DOCKER_REGISTRY: registry.dutchie031.net
DOCKER_IMAGE: spearhead-docs DOCKER_IMAGE: spearhead-docs
DOCKER_TAG: latest DOCKER_TAG: ${{ github.ref_name == 'main' && 'latest' || 'beta' }}
jobs: jobs:
## Run replacements and cleanups on the docs ## Run replacements and cleanups on the docs
@@ -36,7 +37,7 @@ jobs:
sed -i '/@@API_CODE@@/d' .docs/web/pages/spearheadapi.html sed -i '/@@API_CODE@@/d' .docs/web/pages/spearheadapi.html
rm .docs/web/pages/temp_api_code.html rm .docs/web/pages/temp_api_code.html
- name: Highlight API code and update HTML - name: Highlight Config code and update HTML
run: | run: |
pygmentize -f html -l lua -O noclasses,style=monokai ./config.lua > .docs/web/pages/temp_config_code.html pygmentize -f html -l lua -O noclasses,style=monokai ./config.lua > .docs/web/pages/temp_config_code.html
# Insert the highlighted code into the placeholder in spearheadapi.html # Insert the highlighted code into the placeholder in spearheadapi.html
@@ -105,15 +106,30 @@ jobs:
chmod 600 $HOME/.kube/config chmod 600 $HOME/.kube/config
cat $HOME/.kube/config cat $HOME/.kube/config
- name: Run Helm upgrade/install - name: Run Helm upgrade/install spearhead-docs (main)
if: github.ref_name == 'main'
run: | run: |
helm upgrade --install spearhead-docs .helm \ helm upgrade --install spearhead-docs .helm \
--namespace spearhead-docs \ --namespace spearhead-docs \
--create-namespace \ --create-namespace \
-f .helm/values.yaml \
--set image.repository=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }} \ --set image.repository=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }} \
--set image.tag=${{ env.DOCKER_TAG }} \ --set image.tag=${{ env.DOCKER_TAG }} \
--wait --wait
- name: Run Helm upgrade/install spearhead-docs (develop)
if: github.ref_name == 'develop'
run: |
helm upgrade --install spearhead-docs-beta .helm \
--namespace spearhead-docs \
--create-namespace \
-f .helm/values.yaml \
-f .helm/values.beta.yaml \
--set image.repository=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }} \
--set image.tag=${{ env.DOCKER_TAG }} \
--wait
# - name: 'Deploy' # - name: 'Deploy'
# uses: deliverybot/helm@v1 # uses: deliverybot/helm@v1
# with: # with:
+1
View File
@@ -14,3 +14,4 @@ sources:
maintainers: maintainers:
- name: Spearhead Team - name: Spearhead Team
+1 -1
View File
@@ -25,7 +25,7 @@ spec:
type: RuntimeDefault type: RuntimeDefault
containers: containers:
- name: {{ .Values.app }} - name: {{ .Values.app }}
image: {{ .Values.image.repository }}:{{ .Values.image.tag }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: Always imagePullPolicy: Always
ports: ports:
- containerPort: {{ .Values.ports.containerPort }} - containerPort: {{ .Values.ports.containerPort }}
+10 -17
View File
@@ -14,7 +14,7 @@ spec:
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress
metadata: metadata:
name: {{ .Values.app }}-ingress name: "{{ .Values.app }}-ingress"
namespace: spearhead-docs namespace: spearhead-docs
annotations: annotations:
kubernetes.io/tls-acme: "true" kubernetes.io/tls-acme: "true"
@@ -22,28 +22,21 @@ metadata:
spec: spec:
ingressClassName: nginx ingressClassName: nginx
rules: rules:
- host: spearhead.dutchie031.com {{- range .Values.ingress.hosts }}
- host: {{ . }}
http: http:
paths: paths:
- path: / - path: /
pathType: Prefix pathType: Prefix
backend: backend:
service: service:
name: {{ .Values.app }} name: {{ $.Values.app }}
port: port:
number: {{ .Values.ports.servicePort }} number: {{ $.Values.ports.servicePort }}
- host: spearhead.rocks {{- end }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ .Values.app }}
port:
number: {{ .Values.ports.servicePort }}
tls: tls:
- hosts: - hosts:
- spearhead.dutchie031.com {{- range .Values.ingress.hosts }}
- spearhead.rocks - {{ . }}
secretName: spearhead-docs-tls {{- end }}
secretName: "{{ .Values.app }}-docs-tls"
+9
View File
@@ -0,0 +1,9 @@
app: spearhead-docs-beta
image:
tag: "beta"
ingress:
hosts:
- beta.spearhead.rocks
+5
View File
@@ -8,3 +8,8 @@ image:
ports: ports:
servicePort: 80 servicePort: 80
containerPort: 80 containerPort: 80
ingress:
hosts:
- spearhead.dutchie031.com
- spearhead.rocks
+4
View File
@@ -15,6 +15,10 @@
These lanes can be used to create different stage progression flows and create different "side-stories". These lanes can be used to create different stage progression flows and create different "side-stories".
#40 #40
- Issue: #37
Now enabled the mission editor to add a custom briefing to the "Buildable" missions.
#44
### Bug Fixes ### Bug Fixes
## [0.13.0] 2026-08 ## [0.13.0] 2026-08
+9 -9
View File
@@ -1,7 +1,7 @@
{ {
"type": "excalidraw", "type": "excalidraw",
"version": 2, "version": 2,
"source": "vscode-webview://1h45nhtr1vhnknf2q5n6qdd43citnkfueml5qdvamifv7pfv0our", "source": "vscode-webview://1hn2vaam3v69jt67pr4i27hnkafotvd70l4ao9nlb18pmrffl5dm",
"elements": [ "elements": [
{ {
"id": "kJXWwZE94uUnPMEB7mBNj", "id": "kJXWwZE94uUnPMEB7mBNj",
@@ -629,11 +629,11 @@
"type": 2 "type": 2
}, },
"seed": 2125327475, "seed": 2125327475,
"version": 44, "version": 46,
"versionNonce": 2047370396, "versionNonce": 342494645,
"isDeleted": true, "isDeleted": true,
"boundElements": [], "boundElements": [],
"updated": 1788258273370, "updated": 1788285477032,
"link": null, "link": null,
"locked": false, "locked": false,
"points": [ "points": [
@@ -2426,7 +2426,7 @@
"version": 112, "version": 112,
"versionNonce": 1755199388, "versionNonce": 1755199388,
"isDeleted": false, "isDeleted": false,
"boundElements": null, "boundElements": [],
"updated": 1788258305636, "updated": 1788258305636,
"link": null, "link": null,
"locked": false "locked": false
@@ -2456,7 +2456,7 @@
"version": 28, "version": 28,
"versionNonce": 557293604, "versionNonce": 557293604,
"isDeleted": false, "isDeleted": false,
"boundElements": null, "boundElements": [],
"updated": 1788258305636, "updated": 1788258305636,
"link": null, "link": null,
"locked": false, "locked": false,
@@ -2598,7 +2598,7 @@
"version": 7, "version": 7,
"versionNonce": 969870492, "versionNonce": 969870492,
"isDeleted": true, "isDeleted": true,
"boundElements": null, "boundElements": [],
"updated": 1788258356227, "updated": 1788258356227,
"link": null, "link": null,
"locked": false, "locked": false,
@@ -2637,7 +2637,7 @@
"version": 3, "version": 3,
"versionNonce": 1886913564, "versionNonce": 1886913564,
"isDeleted": true, "isDeleted": true,
"boundElements": null, "boundElements": [],
"updated": 1788258344772, "updated": 1788258344772,
"link": null, "link": null,
"locked": false, "locked": false,
@@ -2713,7 +2713,7 @@
"version": 3, "version": 3,
"versionNonce": 1539555236, "versionNonce": 1539555236,
"isDeleted": true, "isDeleted": true,
"boundElements": null, "boundElements": [],
"updated": 1788258343223, "updated": 1788258343223,
"link": null, "link": null,
"locked": false, "locked": false,
@@ -34,7 +34,7 @@ function AirGroup:New(groupName, groupType, config, logger, spawnManager)
self._config = config self._config = config
self._logger = logger self._logger = logger
self._spawnManager = spawnManager self._spawnManager = spawnManager
self._routeDrawing = nil self._routeDrawings = {}
local group = Group.getByName(self._groupName) local group = Group.getByName(self._groupName)
if group then if group then
+47
View File
@@ -58,6 +58,7 @@ local StageDrawing = require("classes.stageClasses.drawings.StageDrawing")
---@class BlueSamData ---@class BlueSamData
---@field groups Array<string> ---@field groups Array<string>
---@field buildingKilos number? ---@field buildingKilos number?
---@field briefing string?
---@class MissionZoneData ---@class MissionZoneData
---@field ZoneName string ---@field ZoneName string
@@ -74,6 +75,7 @@ local StageDrawing = require("classes.stageClasses.drawings.StageDrawing")
---@field padNames Array<string> ---@field padNames Array<string>
---@field buildingKilos number? ---@field buildingKilos number?
---@field supplyHubNames Array<string> ---@field supplyHubNames Array<string>
---@field briefing string?
---@class Database ---@class Database
---@field private _tables DatabaseTables ---@field private _tables DatabaseTables
@@ -616,6 +618,27 @@ function Database:loadBlueSamUnits()
local number = tonumber(kvPair.value) local number = tonumber(kvPair.value)
if number and number > 0 then if number and number > 0 then
samData.buildingKilos = number 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 end
end end
@@ -750,12 +773,36 @@ function Database:loadFarpData()
local number = tonumber(kvPair.value) local number = tonumber(kvPair.value)
if number and number > 0 then if number and number > 0 then
farpzoneData.buildingKilos = number 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 end
end end
end end
end
else
MissionEditorWarnings.Add("Buildable number for " .. farpZone .. " is invalid.")
end
end
end
end
end
end
function Database:loadAirbaseGroups() function Database:loadAirbaseGroups()
local all_groups = getAvailableGroups() local all_groups = getAvailableGroups()
@@ -368,12 +368,51 @@ function GlobalStageManager:PrintMermaidStage()
local stageIndicesByLane = {} -- Track all stage indices per lane local stageIndicesByLane = {} -- Track all stage indices per lane
local mainLaneId = "default" local mainLaneId = "default"
-- Color palette for lanes (26 vibrant colors optimized for dark mode)
local laneColors = {
"#FF6B6B", -- 1: Red
"#4ECDC4", -- 2: Teal
"#45B7D1", -- 3: Blue
"#FFA502", -- 4: Orange
"#95E1D3", -- 5: Mint
"#F38181", -- 6: Coral
"#AA96DA", -- 7: Purple
"#FCBAD3", -- 8: Pink
"#A8E6CF", -- 9: Light green
"#FFD3B6", -- 10: Peach
"#FFAAA5", -- 11: Light red
"#FF8B94", -- 12: Rose
"#FFEAA7", -- 13: Butter
"#DFE6E9", -- 14: Gray
"#00B894", -- 15: Emerald
"#0984E3", -- 16: Cobalt
"#6C5CE7", -- 17: Indigo
"#A29BFE", -- 18: Lavender
"#FD79A8", -- 19: Magenta
"#FDCB6E", -- 20: Gold
"#6C757D", -- 21: Slate
"#20C997", -- 22: Seafoam
"#E74C3C", -- 23: Scarlet
"#3498DB", -- 24: Dodger blue
"#9B59B6", -- 25: Amethyst
"#1ABC9C", -- 26: Turquoise
}
local laneColorMap = {} -- Map lane ID to color
local colorIndex = 1
-- Build nodes and collect all stage indices per lane -- Build nodes and collect all stage indices per lane
for _, lane in ipairs(lanes) do for _, lane in ipairs(lanes) do
local laneId = lane:GetStageLaneIdentifier() or "default" local laneId = lane:GetStageLaneIdentifier() or "default"
local stageIndices = lane:GetAllStageIndices() local stageIndices = lane:GetAllStageIndices()
stageIndicesByLane[laneId] = stageIndices stageIndicesByLane[laneId] = stageIndices
-- Assign color to this lane
laneColorMap[laneId] = laneColors[colorIndex]
colorIndex = colorIndex + 1
if colorIndex > #laneColors then
colorIndex = 1
end
-- Create nodes for each stage index in this lane -- Create nodes for each stage index in this lane
for _, stageIndex in ipairs(stageIndices) do for _, stageIndex in ipairs(stageIndices) do
local stages = lane:GetStagesAtIndex(stageIndex) local stages = lane:GetStagesAtIndex(stageIndex)
@@ -382,7 +421,18 @@ function GlobalStageManager:PrintMermaidStage()
for _, stage in ipairs(stages) do for _, stage in ipairs(stages) do
local nodeId = laneId .. "_" .. stageIndex local nodeId = laneId .. "_" .. stageIndex
local stageType = stage:GetStageType() local stageType = stage:GetStageType()
local label = stage.stageName or stage.zoneName local stageName = stage.stageName or stage.zoneName
-- Generate bracket label: [1], [2] for default, [w1], [e2] for other lanes
local bracketLabel
if laneId == "default" then
bracketLabel = "[" .. stageIndex .. "]"
else
bracketLabel = "[" .. laneId .. stageIndex .. "]"
end
-- Combined label: [bracket] Name
local label = bracketLabel .. " " .. stageName
-- Different node shapes for different stage types -- Different node shapes for different stage types
local nodeShape = "[" local nodeShape = "["
@@ -395,8 +445,8 @@ function GlobalStageManager:PrintMermaidStage()
nodeEnd = "]]" nodeEnd = "]]"
end end
nodes[nodeId] = string.format(' %s%s"%s (S%d)"%s', nodes[nodeId] = string.format(' %s%s"%s"%s',
nodeId, nodeShape, label, stageIndex, nodeEnd) nodeId, nodeShape, label, nodeEnd)
end end
end end
end end
@@ -435,7 +485,7 @@ function GlobalStageManager:PrintMermaidStage()
end end
-- Add dependencies from DEFAULT lane to SIDE lanes at chapter starts -- Add dependencies from DEFAULT lane to SIDE lanes at chapter starts
-- Side lanes activate when main reaches a chapter start index for that side lane -- Side lanes activate when main completes the stage BEFORE the chapter start
if mainStageLane then if mainStageLane then
for _, lane in ipairs(lanes) do for _, lane in ipairs(lanes) do
if lane:IsDefaultStageLane() == false then if lane:IsDefaultStageLane() == false then
@@ -446,9 +496,10 @@ function GlobalStageManager:PrintMermaidStage()
for _, stageIdx in ipairs(sideIndices) do for _, stageIdx in ipairs(sideIndices) do
-- Check if this is a chapter start in the side lane -- Check if this is a chapter start in the side lane
if lane:IsChapterStart(stageIdx) then if lane:IsChapterStart(stageIdx) then
local fromNodeId = mainLaneId .. "_" .. stageIdx -- Main lane must complete (stageIdx - 1) to activate side lane at stageIdx
local fromNodeId = mainLaneId .. "_" .. (stageIdx - 1)
local toNodeId = sideId .. "_" .. stageIdx local toNodeId = sideId .. "_" .. stageIdx
-- Side lane activates when main lane reaches this chapter start -- Side lane activates when main lane completes the prior stage
table.insert(edges, string.format(' %s -->|unlock| %s', fromNodeId, toNodeId)) table.insert(edges, string.format(' %s -->|unlock| %s', fromNodeId, toNodeId))
end end
end end
@@ -502,13 +553,30 @@ function GlobalStageManager:PrintMermaidStage()
-- Build complete Mermaid diagram -- Build complete Mermaid diagram
local diagramLines = {"graph TD"} local diagramLines = {"graph TD"}
-- Add class definitions for each lane with colors and contrasting text
for laneId, color in pairs(laneColorMap) do
table.insert(diagramLines, string.format(' classDef lane_%s fill:%s,stroke:#333,stroke-width:2px,color:#000', laneId, color))
end
-- Add nodes
for _, nodeStr in pairs(nodes) do for _, nodeStr in pairs(nodes) do
table.insert(diagramLines, nodeStr) table.insert(diagramLines, nodeStr)
end end
-- Add edges
for _, edgeStr in pairs(edges) do for _, edgeStr in pairs(edges) do
table.insert(diagramLines, edgeStr) table.insert(diagramLines, edgeStr)
end end
-- Apply classes to nodes
for nodeId in pairs(nodes) do
local laneId = nodeId:match("(.+)_[0-9]+$")
if laneId then
table.insert(diagramLines, string.format(' class %s lane_%s', nodeId, laneId))
end
end
-- Print as single multi-line message -- Print as single multi-line message
local diagram = "========== STAGE FLOW DIAGRAM ==========\n" .. table.concat(diagramLines, "\n") .. "\n========== END DIAGRAM ==========" local diagram = "========== STAGE FLOW DIAGRAM ==========\n" .. table.concat(diagramLines, "\n") .. "\n========== END DIAGRAM =========="
self.logger:info(diagram) self.logger:info(diagram)
@@ -89,7 +89,7 @@ function BlueSam.New(database, logger, zoneName, spawnManager)
local zone = DcsUtil.getZoneByName(zoneName) local zone = DcsUtil.getZoneByName(zoneName)
if zone then 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 end
return self return self
@@ -64,7 +64,7 @@ function FarpZone.New(database, logger, zoneName, spawnManager)
local zone = DcsUtil.getZoneByName(zoneName) local zone = DcsUtil.getZoneByName(zoneName)
if zone then if zone then
self._logger:debug("Creating Buildable zone: " .. zoneName .. " with " .. (farpData.buildingKilos or "nil") .. " kilos") 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
end end
self:Deactivate() self:Deactivate()
@@ -20,7 +20,8 @@ BuildableZone.__index = BuildableZone
---@param database Database ---@param database Database
---@param crateType SupplyType ---@param crateType SupplyType
---@param logger Logger ---@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._targetZone = targetZone
self._requiredKilos = kilosRequired or 0 self._requiredKilos = kilosRequired or 0
self._buildableGroups = buildableGroups or {} self._buildableGroups = buildableGroups or {}
@@ -69,7 +70,7 @@ function BuildableZone:New(targetZone, kilosRequired, crateType, buildableGroup
local noLandingZone = self:GetNoLandingZone() local noLandingZone = self:GetNoLandingZone()
if kilosRequired and kilosRequired > 0 then 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) self._buildableMission:AddOnCrateDroppedOfListener(self)
else else
self._buildableMission = nil self._buildableMission = nil
@@ -13,6 +13,8 @@ local Events = require("classes.spearhead_events")
local GlobalCapManager = require("classes.capClasses.GlobalCapManager") local GlobalCapManager = require("classes.capClasses.GlobalCapManager")
local CustomDrawing = require("classes.stageClasses.drawings.CustomDrawing") local CustomDrawing = require("classes.stageClasses.drawings.CustomDrawing")
local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper") local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper")
local StageRepository = require("classes.stageClasses.StageRepository")
local StageState = require("classes.stageClasses.Stages.BaseStage.StageState")
---@alias StageColor ---@alias StageColor
---| "RED" ---| "RED"
@@ -58,9 +60,9 @@ local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelpe
--- @field protected _missionCommandsHelper MissionCommandsHelper --- @field protected _missionCommandsHelper MissionCommandsHelper
--- @field protected _missionPriority MissionPriority --- @field protected _missionPriority MissionPriority
--- @field protected _database Database --- @field protected _database Database
--- @field protected _stageRepository StageRepository
--- @field protected _db StageData --- @field protected _db StageData
--- @field protected _logger Logger --- @field protected _logger Logger
--- @field protected _activeStage integer
--- @field protected _stageConfig StageConfig --- @field protected _stageConfig StageConfig
--- @field protected _customDrawing CustomDrawing --- @field protected _customDrawing CustomDrawing
--- @field protected _spawnedGroups Array<string> --- @field protected _spawnedGroups Array<string>
@@ -72,14 +74,6 @@ local Stage = {}
Stage.__index = Stage Stage.__index = Stage
---@enum CurrentStageState
Stage.CurrentStageState = {
INACTIVE = 0,
PREACTIVATED = 1,
ACTIVE = 2,
BLUE = 3
}
Stage.StageColors = { Stage.StageColors = {
INVISIBLE = { 0, 0, 0, 0 }, INVISIBLE = { 0, 0, 0, 0 },
RED_ACTIVE = { 1, 0, 0, 0.20 }, RED_ACTIVE = { 1, 0, 0, 0.20 },
@@ -100,16 +94,16 @@ Stage.StageColors = {
function Stage:superNew(database, stageConfig, logger, initData, stageType, missionPriority, spawnManager) function Stage:superNew(database, stageConfig, logger, initData, stageType, missionPriority, spawnManager)
logger:debug("[BaseStage] Initiating stage with name: " .. initData.stageZoneName) logger:debug("[BaseStage] Initiating stage with name: " .. initData.stageZoneName)
self._currentStageState = Stage.CurrentStageState.INACTIVE self._currentStageState = StageState.Inactive
self.zoneName = initData.stageZoneName self.zoneName = initData.stageZoneName
self.stageNumber = initData.stageNumber self.stageNumber = initData.stageNumber
self._stageRepository = StageRepository.getInstance()
if initData.stageLaneIdentifier then if initData.stageLaneIdentifier then
self._stageLaneIdentifier = string.lower(initData.stageLaneIdentifier) self._stageLaneIdentifier = string.lower(initData.stageLaneIdentifier)
else else
self._stageLaneIdentifier = nil self._stageLaneIdentifier = nil
end end
self.stageName = initData.stageDisplayName self.stageName = initData.stageDisplayName
self._currentStageState = Stage.CurrentStageState.INACTIVE
self._stageType = stageType self._stageType = stageType
self.OnPostStageComplete = nil self.OnPostStageComplete = nil
@@ -131,7 +125,6 @@ function Stage:superNew(database, stageConfig, logger, initData, stageType, miss
supplyHubs = {} supplyHubs = {}
} }
self._activeStage = -99
self._stageConfig = stageConfig or {} self._stageConfig = stageConfig or {}
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate() self._missionCommandsHelper = MissionCommandsHelper.getOrCreate()
@@ -289,7 +282,7 @@ end
---@return boolean ---@return boolean
function Stage:IsComplete() function Stage:IsComplete()
if self._currentStageState == Stage.CurrentStageState.BLUE then return true end if self._currentStageState >= StageState.Blue then return true end
for i, mission in pairs(self._db.sams) do for i, mission in pairs(self._db.sams) do
local state = mission:getState() local state = mission:getState()
@@ -304,14 +297,12 @@ function Stage:IsComplete()
return false return false
end end
end end
self._currentStageState = Stage.CurrentStageState.BLUE
return true return true
end end
---@return boolean ---@return boolean
function Stage:IsActive() function Stage:IsActive()
return self._currentStageState == Stage.CurrentStageState.ACTIVE return self._currentStageState == StageState.Activated
end end
---@return StageType ---@return StageType
@@ -429,8 +420,12 @@ end
---Activates all SAMS, Airbase units etc all at once. ---Activates all SAMS, Airbase units etc all at once.
function Stage:PreActivate() function Stage:PreActivate()
if self._currentStageState == Stage.CurrentStageState.INACTIVE then
self._currentStageState = Stage.CurrentStageState.PREACTIVATED if self._currentStageState >= StageState.PreActivated then
return
end
self._currentStageState = StageState.PreActivated
for key, mission in pairs(self._db.sams) do for key, mission in pairs(self._db.sams) do
if mission then if mission then
mission:SpawnInactive() mission:SpawnInactive()
@@ -440,7 +435,6 @@ function Stage:PreActivate()
for _, airbase in pairs(self._db.airbases) do for _, airbase in pairs(self._db.airbases) do
airbase:ActivateRedStage() airbase:ActivateRedStage()
end end
end
self:MarkStage() self:MarkStage()
@@ -455,22 +449,22 @@ function Stage:MarkStage()
end end
if self._stageConfig.isDrawStagesEnabled == false then return end if self._stageConfig.isDrawStagesEnabled == false then return end
if self._stageConfig.isDrawPreActivatedEnabled == false and self._currentStageState == Stage.CurrentStageState.PREACTIVATED then if self._stageConfig.isDrawPreActivatedEnabled == false and self._currentStageState == StageState.PreActivated then
return return
end end
if self._customDrawing then if self._customDrawing then
self._customDrawing:UpdateDrawingObject(function(drawingObject) self._customDrawing:UpdateDrawingObject(function(drawingObject)
local drawing = drawingObject --[[@as Polygon]] local drawing = drawingObject --[[@as Polygon]]
if self._currentStageState == Stage.CurrentStageState.ACTIVE then if self._currentStageState == StageState.Activated then
drawing.fillColorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_ACTIVE) drawing.fillColorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_ACTIVE)
drawing.colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_ACTIVE) drawing.colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_ACTIVE)
drawing.style = "dot dash" drawing.style = "dot dash"
elseif self._currentStageState == Stage.CurrentStageState.PREACTIVATED then elseif self._currentStageState == StageState.PreActivated then
drawing.fillColorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_PREACTIVE) drawing.fillColorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_PREACTIVE)
drawing.colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_PREACTIVE) drawing.colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_PREACTIVE)
drawing.style = "no line" drawing.style = "no line"
elseif self._currentStageState == Stage.CurrentStageState.BLUE then elseif self._currentStageState == StageState.Blue then
drawing.fillColorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.BLUE) drawing.fillColorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.BLUE)
drawing.colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.BLUE) drawing.colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.BLUE)
drawing.style = "two dash" drawing.style = "two dash"
@@ -488,10 +482,13 @@ function Stage:MarkStage()
end end
function Stage:ActivateStage() function Stage:ActivateStage()
self._currentStageState = Stage.CurrentStageState.ACTIVE
if self._currentStageState >= StageState.Activated then
return
end
self:PreActivate() self:PreActivate()
self._currentStageState = StageState.Activated
pcall(function() pcall(function()
self:MarkStage() self:MarkStage()
end) end)
@@ -519,6 +516,10 @@ function Stage:ActivateStage()
end end
end end
if self._db and self._db.stageBriefing then
self._missionCommandsHelper:AddStageBriefing(self.zoneName, self._db.stageBriefing)
end
timer.scheduleFunction(self.CheckContinuousAsync, self, timer.getTime() + 3) timer.scheduleFunction(self.CheckContinuousAsync, self, timer.getTime() + 3)
end end
@@ -534,45 +535,57 @@ end
---@param stageLaneIdentifier string? ---@param stageLaneIdentifier string?
function Stage:OnStageNumberChanged(number, stageLaneIdentifier) function Stage:OnStageNumberChanged(number, stageLaneIdentifier)
if stageLaneIdentifier ~= self._stageLaneIdentifier then ---@return boolean
return local needsPreActivation = function()
if self._stageLaneIdentifier == stageLaneIdentifier then
if self.stageNumber <= number + self._stageConfig.AmountPreactivateStage then
return true
end
elseif self._stageLaneIdentifier == nil then
--main lane
--Check if this stage is a chapter stage
if self._stageRepository:getStageLane(self._stageLaneIdentifier):IsChapterStart(self.stageNumber)
and self.stageNumber < number + self._stageConfig.AmountPreactivateStage
then
return true
end end
if self._activeStage == number then --only activate once for a stage if GlobalCapManager.IsCapActiveWhenZoneIsActive(self.zoneName, number) == true then
return return true
end
end end
local previousActive = self._activeStage return false
self._activeStage = number end
if self.stageNumber - self._activeStage == self._stageConfig.AmountPreactivateStage then ---@return boolean
self._logger:debug("Pre-activating stage: " .. self.zoneName .. " with number: " .. number) local needsActivation = function()
self:PreActivate() if self._stageLaneIdentifier == stageLaneIdentifier and self.stageNumber == number then
elseif GlobalCapManager.IsCapActiveWhenZoneIsActive(self.zoneName, number) == true then return true
end
return false
end
---@return boolean
local needsBlueActivation = function()
if self._stageLaneIdentifier == stageLaneIdentifier and self.stageNumber < number then
return true
end
return false
end
if needsPreActivation() == true then
self:PreActivate() self:PreActivate()
end end
if number == self.stageNumber then if needsActivation() == true then
self:ActivateStage() self:ActivateStage()
if self._db and self._db.stageBriefing then
self._missionCommandsHelper:AddStageBriefing(self.zoneName, self._db.stageBriefing)
end
end end
if previousActive <= self.stageNumber then if needsBlueActivation() == true then
if number > self.stageNumber then
self:ActivateBlueStage() self:ActivateBlueStage()
end end
end
if number > self.stageNumber then
self._missionCommandsHelper:RemoveStageBriefing(self.zoneName)
end
end
function Stage:GetBriefing()
return "Briefing For "
end end
---@param self Stage ---@param self Stage
@@ -581,7 +594,6 @@ Stage.OnMissionComplete = function(self, mission)
self:CheckAndUpdateSelf() self:CheckAndUpdateSelf()
end end
---private use only ---private use only
function Stage:ActivateBlueGroups() function Stage:ActivateBlueGroups()
@@ -643,8 +655,12 @@ end
function Stage:ActivateBlueStage() function Stage:ActivateBlueStage()
if self._currentStageState >= StageState.Blue then
return
end
self._logger:debug("Setting stage '" .. Util.toString(self.zoneName) .. "' to blue") self._logger:debug("Setting stage '" .. Util.toString(self.zoneName) .. "' to blue")
self._currentStageState = Stage.CurrentStageState.BLUE self._currentStageState = StageState.Blue
for _, mission in pairs(self._db.missions) do for _, mission in pairs(self._db.missions) do
mission:SpawnPersistedState() mission:SpawnPersistedState()
end end
@@ -668,6 +684,8 @@ function Stage:ActivateBlueStage()
return nil return nil
end end
self._missionCommandsHelper:RemoveStageBriefing(self.zoneName)
timer.scheduleFunction(ActivateBlueAsync, self, timer.getTime() + 3) timer.scheduleFunction(ActivateBlueAsync, self, timer.getTime() + 3)
end end
@@ -0,0 +1,12 @@
--- StageState enumeration for the current stage state.
--- Chronological order, meaning that higher values should represent later stages in the sequence.
---@enum CurrentStageState
local StageState = {
Inactive = 0,
PreActivated = 1,
Activated = 2,
Blue = 3
}
return StageState
@@ -6,7 +6,7 @@ local drawingLogger = Logger.new("CustomDrawing")
---@class CustomDrawing ---@class CustomDrawing
---@field protected _id integer? ---@field protected _IDs Array<integer>?
---@field protected _name string? ---@field protected _name string?
---@field protected _drawingObject DrawingObject ---@field protected _drawingObject DrawingObject
local CustomDrawing = {} local CustomDrawing = {}
@@ -18,7 +18,7 @@ CustomDrawing.__index = CustomDrawing
function CustomDrawing.New(drawingObject) function CustomDrawing.New(drawingObject)
local self = setmetatable({}, CustomDrawing) local self = setmetatable({}, CustomDrawing)
self._drawingObject = drawingObject self._drawingObject = drawingObject
self._id = nil -- initiate ID as nil, when drawn it will be set to the ID returned by DrawingHelper.Draw self._IDs = {} -- initiate IDs as an empty array, when drawn it will be set to the IDs returned by DrawingHelper.Draw
self._name = drawingObject.name self._name = drawingObject.name
return self return self
end end
@@ -110,20 +110,24 @@ function CustomDrawing:GetName()
end end
function CustomDrawing:Draw() function CustomDrawing:Draw()
drawingLogger:debug("Drawing custom drawing with ID " .. tostring(self._id)) drawingLogger:debug("Drawing custom drawing with IDs " .. table.concat(self._IDs, ", "))
if self._id ~= nil then if self._IDs ~= nil then
DrawingHelper.Remove(self._id) for _, id in ipairs(self._IDs) do
DrawingHelper.Remove(id)
end
end end
self._id = DrawingHelper.Draw(self._drawingObject) self._IDs = DrawingHelper.Draw(self._drawingObject)
end end
function CustomDrawing:Remove() function CustomDrawing:Remove()
if self._id ~= nil then if self._IDs ~= nil then
drawingLogger:debug("Removing custom drawing with ID " .. tostring(self._id)) for _, id in ipairs(self._IDs) do
DrawingHelper.Remove(self._id) drawingLogger:debug("Removing custom drawing with ID " .. tostring(id))
self._id = nil DrawingHelper.Remove(id)
end
self._IDs = {}
end end
end end
@@ -1,57 +1,45 @@
local Util = require("classes.util.Util") local Util = require("classes.util.Util")
local DcsUtil = require("classes.util.DcsUtil")
local Logger = require("classes.util.Logger") local Logger = require("classes.util.Logger")
local GlobalConfig = require("classes.configuration.GlobalConfig") local GlobalConfig = require("classes.configuration.GlobalConfig")
---@type LogLevel ---@type LogLevel
local level = "INFO" local level = "INFO"
if GlobalConfig:isDebugEnabled() then if GlobalConfig.New():isDebugEnabled() then
level = "DEBUG" level = "DEBUG"
end end
local drawingLogger = Logger.new("DrawingHelper", level) local logger = Logger.new("DrawingHelper", level)
---@class DrawingHelper ---@class DrawingHelper
local DrawingHelper = {} local DrawingHelper = {}
DrawingHelper.__index = DrawingHelper DrawingHelper.__index = DrawingHelper
local customDrawingIdIncrementer = 4210
---@param object DrawingObject ---@param object DrawingObject
---@param logger Logger? ---@return Array<integer> id
---@return integer? id function DrawingHelper.Draw(object)
function DrawingHelper.Draw(object, logger)
if object == nil then if object == nil then
if logger then if logger then
logger:warn("DrawingHelper.Draw called with nil object") logger:warn("DrawingHelper.Draw called with nil object")
end end
return nil return {}
end
local id = DrawingHelper.GetAndAddId()
if logger then
logger:debug("Drawing object with ID " .. tostring(id) .. " and primitive type: " .. tostring(object.primitiveType))
end end
if(object.primitiveType == "Polygon") then if(object.primitiveType == "Polygon") then
DrawingHelper.DrawPolygon(object--[[@as Polygon]], id, logger) return DrawingHelper.DrawPolygon(object--[[@as Polygon]])
elseif(object.primitiveType == "Line") then elseif(object.primitiveType == "Line") then
DrawingHelper.DrawLine(object--[[@as Line]], id, logger) return DrawingHelper.DrawLine(object--[[@as Line]])
elseif(object.primitiveType == "TextBox") then elseif(object.primitiveType == "TextBox") then
DrawingHelper.DrawTextBox(object--[[@as TextBox]], id) return DrawingHelper.DrawTextBox(object--[[@as TextBox]])
else else
if logger then
logger:warn("Unknown primitive type: " .. tostring(object.primitiveType)) logger:warn("Unknown primitive type: " .. tostring(object.primitiveType))
end end
end
return id return {}
end end
function DrawingHelper.GetAndAddId() function DrawingHelper.GetAndAddId()
customDrawingIdIncrementer = customDrawingIdIncrementer + 1 return DcsUtil.GetNextDrawID()
return customDrawingIdIncrementer
end end
---@private ---@private
@@ -62,8 +50,7 @@ end
---@param lineColor table ---@param lineColor table
---@param lineStyle LineType ---@param lineStyle LineType
---@param lineThickness number ---@param lineThickness number
---@param logger Logger? local function MarkupToAll(shapeID, drawID, points, fillColor, lineColor, lineStyle, lineThickness)
local function MarkupToAll(shapeID, drawID, points, fillColor, lineColor, lineStyle, lineThickness, logger)
if lineThickness == nil or lineThickness <= 0 then if lineThickness == nil or lineThickness <= 0 then
lineStyle = 0 lineStyle = 0
@@ -76,23 +63,19 @@ local function MarkupToAll(shapeID, drawID, points, fillColor, lineColor, lineS
end end
functionString = functionString .. "{0,1,0,1}, {0,1,0,1}, " .. lineStyle .. ")" functionString = functionString .. "{0,1,0,1}, {0,1,0,1}, " .. lineStyle .. ")"
if logger then
logger:debug("Drawing complex drawing with ID " .. tostring(drawID) .. " and function string: " .. functionString) logger:debug("Drawing complex drawing with ID " .. tostring(drawID) .. " and function string: " .. functionString)
end
---@diagnostic disable-next-line: deprecated ---@diagnostic disable-next-line: deprecated
local f, err = loadstring(functionString) local f, err = loadstring(functionString)
if f then if f then
f() f()
else else
env.error("Something failed when drawing complex drawing" .. err) logger:error("Something failed when drawing complex drawing" .. err)
end
if logger then
logger:debug("Drawing with fill color: " .. table.concat(fillColor, ",") .. " and line color: " .. table.concat(lineColor, ",") .. " and line style: " .. tostring(lineStyle) .. " and line thickness: " .. tostring(lineThickness))
end end
if fillColor then
trigger.action.setMarkupColorFill(drawID, fillColor) trigger.action.setMarkupColorFill(drawID, fillColor)
end
trigger.action.setMarkupColor(drawID, lineColor) trigger.action.setMarkupColor(drawID, lineColor)
trigger.action.setMarkupTypeLine(drawID, lineStyle) trigger.action.setMarkupTypeLine(drawID, lineStyle)
@@ -100,13 +83,14 @@ end
---@private ---@private
---@param object Polygon ---@param object Polygon
---@param id integer ---@return Array<integer>
---@param logger Logger? function DrawingHelper.DrawPolygon(object)
function DrawingHelper.DrawPolygon(object, id, logger)
if object == nil then if object == nil then
return return {}
end end
local id = DrawingHelper.GetAndAddId()
---@param circle Circle ---@param circle Circle
local function DrawCircle(circle) local function DrawCircle(circle)
local vec3 = { x = circle.mapX, y = 0, z = circle.mapY } local vec3 = { x = circle.mapX, y = 0, z = circle.mapY }
@@ -117,8 +101,8 @@ function DrawingHelper.DrawPolygon(object, id, logger)
end end
---@param oval Oval ---@param oval Oval
---@param logger Logger? ---@return integer?, Array<CustomDrawing>?
local function DrawOval(oval, logger) local function DrawOval(oval)
---@type Array<Vec3> ---@type Array<Vec3>
local points = {} local points = {}
local pointsNo = 30 local pointsNo = 30
@@ -134,12 +118,11 @@ function DrawingHelper.DrawPolygon(object, id, logger)
local y = oval.mapY + (oval.r2 * math.sin(angle)) local y = oval.mapY + (oval.r2 * math.sin(angle))
table.insert(points, { x = x, y = 0, z = y } ) table.insert(points, { x = x, y = 0, z = y } )
end end
MarkupToAll(7, id, points, fillColor, color, lineStyle, oval.thickness, logger) MarkupToAll(7, id, points, fillColor, color, lineStyle, oval.thickness)
end end
---@param free Free ---@param free Free
---@param logger Logger? local function DrawFree(free)
local function DrawFree(free, logger)
local fillColor = DrawingHelper.ColorToColorTable(free.fillColorString) local fillColor = DrawingHelper.ColorToColorTable(free.fillColorString)
local color = DrawingHelper.ColorToColorTable(free.colorString) local color = DrawingHelper.ColorToColorTable(free.colorString)
local lineStyle = DrawingHelper.ToLineStyleInteger(free.style) local lineStyle = DrawingHelper.ToLineStyleInteger(free.style)
@@ -163,7 +146,7 @@ function DrawingHelper.DrawPolygon(object, id, logger)
end end
end end
MarkupToAll(7, id, points, fillColor, color, lineStyle, free.thickness, logger) MarkupToAll(7, id, points, fillColor, color, lineStyle, free.thickness)
end end
---@param rect Rect ---@param rect Rect
@@ -175,19 +158,16 @@ function DrawingHelper.DrawPolygon(object, id, logger)
local pointA = { x = rect.mapX, y = 0, z = rect.mapY } local pointA = { x = rect.mapX, y = 0, z = rect.mapY }
local pointB = { x = rect.mapX + rect.width, y = 0, z = rect.mapY + rect.height } local pointB = { x = rect.mapX + rect.width, y = 0, z = rect.mapY + rect.height }
trigger.action.rectToAll(-1, id, pointA, pointB, color, fillColor, lineStyle, true) trigger.action.rectToAll(-1, id, pointA, pointB, color, fillColor, lineStyle, true)
end end
---@param arrow Arrow ---@param arrow Arrow
---@param logger Logger? local function DrawArrow(arrow)
local function DrawArrow(arrow, logger)
local fillColor = DrawingHelper.ColorToColorTable(arrow.fillColorString) local fillColor = DrawingHelper.ColorToColorTable(arrow.fillColorString)
local color = DrawingHelper.ColorToColorTable(arrow.colorString) local color = DrawingHelper.ColorToColorTable(arrow.colorString)
local lineStyle = DrawingHelper.ToLineStyleInteger(arrow.style) local lineStyle = DrawingHelper.ToLineStyleInteger(arrow.style)
if logger then
logger:debug("Drawing arrow with start point: " .. tostring(arrow.mapX) .. ", " .. tostring(arrow.mapY) .. " and angle: " .. tostring(arrow.angle) .. " and length: " .. tostring(arrow.length)) logger:debug("Drawing arrow with start point: " .. tostring(arrow.mapX) .. ", " .. tostring(arrow.mapY) .. " and angle: " .. tostring(arrow.angle) .. " and length: " .. tostring(arrow.length))
end
local endPoint = { x = arrow.mapX, y = 0, z = arrow.mapY } local endPoint = { x = arrow.mapX, y = 0, z = arrow.mapY }
local rad = math.rad(arrow.angle or 0) local rad = math.rad(arrow.angle or 0)
@@ -203,44 +183,56 @@ function DrawingHelper.DrawPolygon(object, id, logger)
if object.polygonMode == "circle" then if object.polygonMode == "circle" then
DrawCircle(object--[[@as Circle]]) DrawCircle(object--[[@as Circle]])
elseif object.polygonMode == "oval" then elseif object.polygonMode == "oval" then
DrawOval(object--[[@as Oval]], logger) DrawOval(object--[[@as Oval]])
elseif object.polygonMode == "free" then elseif object.polygonMode == "free" then
DrawFree(object--[[@as Free]], logger) DrawFree(object--[[@as Free]])
elseif object.polygonMode == "rect" then elseif object.polygonMode == "rect" then
DrawRect(object--[[@as Rect]]) DrawRect(object--[[@as Rect]])
elseif object.polygonMode == "arrow" then elseif object.polygonMode == "arrow" then
DrawArrow(object--[[@as Arrow]], logger) DrawArrow(object--[[@as Arrow]])
end end
return {id}
end end
---@private ---@private
---@param object Line ---@param object Line
---@param id integer ---@return Array<integer>
---@param logger Logger? function DrawingHelper.DrawLine(object)
function DrawingHelper.DrawLine(object, id, logger)
---@type Array<Vec3> ---@type Array<Vec3>
local points = {} local points = {}
local ids = {}
for _, point in ipairs(object.points) do for _, point in ipairs(object.points) do
table.insert(points, { x = point.x, y = 0, z = point.y } ) table.insert(points, { x = object.mapX + point.x, y = 0, z = object.mapY + point.y } )
end end
local color = DrawingHelper.ColorToColorTable(object.colorString) local color = DrawingHelper.ColorToColorTable(object.colorString)
local lineStyle = DrawingHelper.ToLineStyleInteger(object.style) local lineStyle = DrawingHelper.ToLineStyleInteger(object.style)
MarkupToAll(1, id, points, color, color, lineStyle, object.thickness, logger)
for i = 1, #points - 1 do
local id = DrawingHelper.GetAndAddId()
trigger.action.lineToAll(-1, id, points[i], points[i + 1], color, lineStyle, true)
table.insert(ids, id)
end
return ids
end end
---@private ---@private
---@param object TextBox ---@param object TextBox
---@param id integer ---@return Array<integer>
function DrawingHelper.DrawTextBox(object, id) function DrawingHelper.DrawTextBox(object)
local id = DrawingHelper.GetAndAddId()
trigger.action.textToAll(-1, id, { x= object.mapX, y = 0, z = object.mapY }, trigger.action.textToAll(-1, id, { x= object.mapX, y = 0, z = object.mapY },
DrawingHelper.ColorToColorTable(object.colorString), DrawingHelper.ColorToColorTable(object.colorString),
DrawingHelper.ColorToColorTable(object.fillColorString), DrawingHelper.ColorToColorTable(object.fillColorString),
object.fontSize or 12, object.fontSize or 12,
true, true,
object.text or "") object.text or "")
return {id}
end end
function DrawingHelper.Remove(id) function DrawingHelper.Remove(id)
@@ -252,7 +244,7 @@ end
function DrawingHelper.ColorToColorTable(hexStr) function DrawingHelper.ColorToColorTable(hexStr)
if hexStr == nil then if hexStr == nil then
drawingLogger:warn("ColorToColorTable called with nil hexStr, returning default color {0, 0, 0, 0}") logger:warn("ColorToColorTable called with nil hexStr, returning default color {0, 0, 0, 0}")
return { 0, 0, 0, 0 } return { 0, 0, 0, 0 }
end end
@@ -270,7 +262,7 @@ end
---@return string ---@return string
function DrawingHelper.ColorTableToColorString(rgba) function DrawingHelper.ColorTableToColorString(rgba)
if rgba == nil or #rgba < 4 or rgba[1] == nil or rgba[2] == nil or rgba[3] == nil or rgba[4] == nil then if rgba == nil or #rgba < 4 or rgba[1] == nil or rgba[2] == nil or rgba[3] == nil or rgba[4] == nil then
drawingLogger:warn("ColorTableToColorString called with invalid rgba table, returning default color string '0x00000000'") logger:warn("ColorTableToColorString called with invalid rgba table, returning default color string '0x00000000'")
return "0x00000000" return "0x00000000"
end end
@@ -21,9 +21,18 @@ local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelpe
---@field private _dropOffZone SpearheadTriggerZone? ---@field private _dropOffZone SpearheadTriggerZone?
---@field private _noLandingZoneDrawing CustomDrawing? ---@field private _noLandingZoneDrawing CustomDrawing?
---@field private _dropOffZoneDrawing CustomDrawing? ---@field private _dropOffZoneDrawing CustomDrawing?
---@field private _briefing string?
local BuildableMission = {} local BuildableMission = {}
BuildableMission.__index = 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 ---@class OnCrateDroppedListener
---@field OnCrateDroppedOff fun(self:OnCrateDroppedListener, mission:BuildableMission, kilos:number) ---@field OnCrateDroppedOff fun(self:OnCrateDroppedListener, mission:BuildableMission, kilos:number)
@@ -33,7 +42,8 @@ BuildableMission.__index = BuildableMission
---@param requiredCrateType SupplyType ---@param requiredCrateType SupplyType
---@param noLandingZone SpearheadTriggerZone? ---@param noLandingZone SpearheadTriggerZone?
---@param logger Logger ---@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) setmetatable(BuildableMission, Mission)
@@ -43,6 +53,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi
self._database = database self._database = database
self._requiredKilos = requiredKilos self._requiredKilos = requiredKilos
self._droppedKilos = 0 self._droppedKilos = 0
self._briefing = briefing
self._noLandingZone = noLandingZone self._noLandingZone = noLandingZone
@@ -64,7 +75,13 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi
end end
self.code = tostring(database:GetNewMissionCode()) self.code = tostring(database:GetNewMissionCode())
local splitTargetZoneName = Util.split_string(targetZone.name, "_")
if splitTargetZoneName and splitTargetZoneName[3] and splitTargetZoneName[3] ~= "" then
self.name = splitTargetZoneName[3]
else
self.name = "Resupply" self.name = "Resupply"
end
local type = "site" local type = "site"
if requiredCrateType == "SAM_CRATE" then if requiredCrateType == "SAM_CRATE" then
@@ -81,7 +98,6 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi
self._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate() self._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate()
self._state = "NEW" self._state = "NEW"
self.location = targetZone.location self.location = targetZone.location
self.missionType = "LOGISTICS" self.missionType = "LOGISTICS"
@@ -116,11 +132,16 @@ function BuildableMission:ShowBriefing(groupID)
siteType = "airbase" siteType = "airbase"
end 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 .. local briefing = "Mission [" .. self.code .. "] " .. self.name ..
"\n \n" .. "\n \n" ..
"We've dispatched forward units to find a proper spot for a new " .. siteType .. "." .. briefingPart ..
"\nYou will need to drop off supplies so they can start building." ..
"\nThe coords are: " .. coords ..
"\n\n" .. "\n\n" ..
"\nKilos still required: " .. self._requiredKilos - self._droppedKilos .. "\nKilos still required: " .. self._requiredKilos - self._droppedKilos ..
"\n\n" .. "\n\n" ..
@@ -18,7 +18,7 @@ local RunwayStrikeMission = {}
---@field corners Array<Vec2> ---@field corners Array<Vec2>
---@field kilosHit number ---@field kilosHit number
---@field repairGroups Array<string> ---@field repairGroups Array<string>
---@field drawID number? ---@field drawID Array<number>
---@param runway Runway ---@param runway Runway
@@ -172,8 +172,10 @@ function RunwayStrikeMission:Draw()
runwaySection.drawID = DrawingHelper.Draw(drawObject) runwaySection.drawID = DrawingHelper.Draw(drawObject)
else else
DcsUtil.SetFillColor(runwaySection.drawID, fillColor) for _, drawID in pairs(runwaySection.drawID) do
DcsUtil.SetLineColor(runwaySection.drawID, lineColor) DcsUtil.SetFillColor(drawID, fillColor)
DcsUtil.SetLineColor(drawID, lineColor)
end
end end
end end
@@ -497,6 +499,7 @@ function RunwayStrikeMission:ToSections(runway, numSections)
corners = corners, corners = corners,
kilosHit = 0, kilosHit = 0,
repairGroups = {}, repairGroups = {},
drawID = {},
} }
table.insert(sections, section) table.insert(sections, section)
+12 -2
View File
@@ -632,13 +632,19 @@ do -- INIT DCS_UTIL
---@field b number ---@field b number
---@field a number ---@field a number
local drawID = 4210
function DCS_UTIL.GetNextDrawID()
drawID = drawID + 1
return drawID
end
---@param groupID number ---@param groupID number
---@param text string ---@param text string
---@param location Vec3 ---@param location Vec3
---@return number markID ---@return number markID
function DCS_UTIL.AddMarkToGroup(groupID, text, location) function DCS_UTIL.AddMarkToGroup(groupID, text, location)
drawID = drawID + 1 local drawID = DCS_UTIL.GetNextDrawID()
trigger.action.markToGroup(drawID, text, location, groupID, true, nil) trigger.action.markToGroup(drawID, text, location, groupID, true, nil)
return drawID return drawID
end end
@@ -648,7 +654,7 @@ do -- INIT DCS_UTIL
---@param location Vec3 ---@param location Vec3
---@return integer ---@return integer
function DCS_UTIL.AddMarkToAll(text, location) function DCS_UTIL.AddMarkToAll(text, location)
drawID = drawID + 1 local drawID = DCS_UTIL.GetNextDrawID()
trigger.action.markToAll(drawID, text, location, true, nil) trigger.action.markToAll(drawID, text, location, true, nil)
return drawID return drawID
end end
@@ -677,6 +683,10 @@ do -- INIT DCS_UTIL
---@param drawID number ---@param drawID number
---@param fillColor DrawColor ---@param fillColor DrawColor
function DCS_UTIL.SetFillColor(drawID, fillColor) function DCS_UTIL.SetFillColor(drawID, fillColor)
if fillColor == nil then
return
end
local lineColorMapped = { local lineColorMapped = {
fillColor.r or 0, fillColor.r or 0,
fillColor.g or 0, fillColor.g or 0,