Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52f840c270 | ||
|
|
d14a0dc78e | ||
|
|
a1355ff05d | ||
|
|
2e636b2ded | ||
|
|
488a492e39 |
@@ -64,7 +64,7 @@
|
|||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
if (true || window.location.hostname.toLowerCase() == 'beta.spearhead.rocks') {
|
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>';
|
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 || '';
|
document.getElementById('beta-box-div').innerHTML = betaHtml || '';
|
||||||
|
|||||||
@@ -49,17 +49,6 @@ class DownloadScript extends HTMLElement {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchReleaseAssets(url){
|
|
||||||
try {
|
|
||||||
const response = await fetch(url);
|
|
||||||
const data = await response.json();
|
|
||||||
return data;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching release assets:', error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async connectedCallback() {
|
async connectedCallback() {
|
||||||
|
|
||||||
@@ -72,10 +61,9 @@ class DownloadScript extends HTMLElement {
|
|||||||
if (latestRelease) {
|
if (latestRelease) {
|
||||||
version = latestRelease.tag_name;
|
version = latestRelease.tag_name;
|
||||||
timestamp = new Date(latestRelease.published_at).toLocaleDateString('en-CA');
|
timestamp = new Date(latestRelease.published_at).toLocaleDateString('en-CA');
|
||||||
|
const assets = latestRelease.assets;
|
||||||
const assets = await this.fetchReleaseAssets(latestRelease.assets_url);
|
|
||||||
if (assets && assets.length > 0) {
|
if (assets && assets.length > 0) {
|
||||||
const spearheadAsset = assets.find(asset => asset.name.includes('spearhead'));
|
const spearheadAsset = assets.find(asset => asset.name.includes('spearhead.v'));
|
||||||
if (spearheadAsset) {
|
if (spearheadAsset) {
|
||||||
size = (spearheadAsset.size / 1024).toFixed(2) + 'kb';
|
size = (spearheadAsset.size / 1024).toFixed(2) + 'kb';
|
||||||
href = spearheadAsset.browser_download_url;
|
href = spearheadAsset.browser_download_url;
|
||||||
@@ -105,7 +93,7 @@ class DownloadScript extends HTMLElement {
|
|||||||
<p>
|
<p>
|
||||||
<span class="version-text">${version}</span> (${timestamp}) <br>
|
<span class="version-text">${version}</span> (${timestamp}) <br>
|
||||||
<a style="text-decoration: underline;" target="_blank" href="${href}">Download</a> (${size}) <br>
|
<a style="text-decoration: underline;" target="_blank" href="${href}">Download</a> (${size}) <br>
|
||||||
<a style="text-decoration: underline;" target="_blank" href="https://git.dutchie031.com/api/v1/repos/Spearhead/spearhead/releases">See All Versions here</a>
|
<a style="text-decoration: underline;" target="_blank" href="https://git.dutchie031.com/Spearhead/spearhead/releases">See All Versions here</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -175,7 +175,10 @@ class Sidebar extends HTMLElement {
|
|||||||
|
|
||||||
this.innerHTML = `
|
this.innerHTML = `
|
||||||
<div class="side-nav">
|
<div class="side-nav">
|
||||||
${betaHtml}
|
<div style="width:100%">
|
||||||
|
${betaHtml}
|
||||||
|
</div>
|
||||||
|
|
||||||
<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 -->
|
||||||
|
|||||||
@@ -80,17 +80,12 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
<note-box type="info" title="Combining Tasks">
|
<note-box type="info" title="Combining Tasks">
|
||||||
Currently a group can do 1 thing. Either be Primary, Seconday, Sweep or Intercept. <br>
|
Currently a group can do 1 thing. Either be Primary, Seconday, Sweep or Intercept. <br>
|
||||||
If you want to have different types during different stages, it's best to copy paste groups and
|
If you want to have different types during different stages, it's best to copy paste groups and
|
||||||
rename them accordingly. <br>
|
rename them accordingly. <br>
|
||||||
</note-box>
|
</note-box>
|
||||||
|
|
||||||
<note-box type="info" title="Airfield Defenses">
|
|
||||||
|
|
||||||
</note-box>
|
|
||||||
|
|
||||||
<h3 id="cap-zones-ref">Zones</h3>
|
<h3 id="cap-zones-ref">Zones</h3>
|
||||||
<table class="table-no-style">
|
<table class="table-no-style">
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -99,6 +94,7 @@
|
|||||||
<td>=></td>
|
<td>=></td>
|
||||||
<td>A Cap ROUTE. The two most outer points are used to define the fly-over points.</td>
|
<td>A Cap ROUTE. The two most outer points are used to define the fly-over points.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr><td>______________________</td><td></td><td></td> </tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code-inline>INTERCEPTZONE_[ZoneID]_[NAME]</code-inline></td>
|
<td><code-inline>INTERCEPTZONE_[ZoneID]_[NAME]</code-inline></td>
|
||||||
<td>=></td>
|
<td>=></td>
|
||||||
@@ -112,6 +108,19 @@
|
|||||||
</p>
|
</p>
|
||||||
<h2 id="setup">Setting up groups</h2>
|
<h2 id="setup">Setting up groups</h2>
|
||||||
|
|
||||||
|
<h3 id="airbases-grouping">Airbases</h3>
|
||||||
|
<p>
|
||||||
|
Before talking about the groups, it's good to mention that groups are currently logically grouped and managed by an Airbase. <br>
|
||||||
|
Meaning, Airbase A does not know how many flights Airbase B is sending out. <br>
|
||||||
|
This might change in the future where multiple Airbases can work together.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<note-box type="info" title="Airbase Defenses">
|
||||||
|
When an Airbase is "active" and thus has aircraft being scheduled for taskings, all RED groups at that airfield will also be spawned. <br>
|
||||||
|
Additionally, all missions of type <code-inline>SAM</code-inline> will be spawned (without being available in Primary Missions). <br>
|
||||||
|
This should hopefully give you all the tools to make distance CAP airbases still feel very well defended.
|
||||||
|
</note-box>
|
||||||
|
|
||||||
<h3 id="types-explained">Types explained</h3>
|
<h3 id="types-explained">Types explained</h3>
|
||||||
<p>
|
<p>
|
||||||
Before we go into depth on each type it's best to first look at the types briefly and what we
|
Before we go into depth on each type it's best to first look at the types briefly and what we
|
||||||
@@ -140,7 +149,7 @@
|
|||||||
The ground attack units mentioned are not in yet and thus escort groups are not either. <br>
|
The ground attack units mentioned are not in yet and thus escort groups are not either. <br>
|
||||||
|
|
||||||
<note-box type="warning" title="Overriding Taskings">
|
<note-box type="warning" title="Overriding Taskings">
|
||||||
Each tasking has very specific waypoints, both for departure, arrical and ofcourse all point in between. <br>
|
Each tasking has very specific waypoints, both for departure, arrival and ofcourse all point in between. <br>
|
||||||
Overriding the "tasking" will break part of the cap flow as "RTBInTen" and RTB events are triggered by waypoints. <br>
|
Overriding the "tasking" will break part of the cap flow as "RTBInTen" and RTB events are triggered by waypoints. <br>
|
||||||
Overriding these waypoints and taskings will break the management by Spearhead.
|
Overriding these waypoints and taskings will break the management by Spearhead.
|
||||||
</note-box>
|
</note-box>
|
||||||
@@ -154,7 +163,7 @@
|
|||||||
The way the trigger zone is mapped to a route is as follows: <br>
|
The way the trigger zone is mapped to a route is as follows: <br>
|
||||||
<br>
|
<br>
|
||||||
The 2 points that are furthest apart from each other are chosen as the "leg" of the route. <br>
|
The 2 points that are furthest apart from each other are chosen as the "leg" of the route. <br>
|
||||||
The other 2 points are discarded. <br>
|
The other 2 points are discarded at this time. <br>
|
||||||
<br>
|
<br>
|
||||||
The Orbit route is then created with an "Anchored" task. With the closest point being the starting
|
The Orbit route is then created with an "Anchored" task. With the closest point being the starting
|
||||||
point with an outbound leg to the furthest point. <br>
|
point with an outbound leg to the furthest point. <br>
|
||||||
|
|||||||
@@ -26,42 +26,118 @@
|
|||||||
|
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
<h1>Advanced Tutorial: Missions</h1>
|
<h1>Advanced Tutorial: Missions</h1>
|
||||||
<h2 id="strike">Strike</h2>
|
<div id="strike-region">
|
||||||
<p>
|
<h2 id="strike">Strike</h2>
|
||||||
Naming: <span class="inline-lua"><span class="lua-variable">MISSION_STRIKE_[Name]</span></span> <br>
|
<p>
|
||||||
</p>
|
Naming: <code-inline>MISSION_STRIKE_[Name]</code-inline> <br>
|
||||||
<h3 id="specific_targets">Specific Targets</h3>
|
</p>
|
||||||
<p>TBD</p>
|
<h3 id="specific_targets">Specific Targets</h3>
|
||||||
|
<p>TBD</p>
|
||||||
|
|
||||||
|
<h3 id="scenery_targets">Scenery Targets</h3>
|
||||||
|
<p>
|
||||||
|
Bridges, buildings or other type of targets that are baked into the map are awesome targets.<br>
|
||||||
|
We wanted to make sure they were easily integrated in Spearhead.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3 id="scenery_targets">Scenery Targets</h3>
|
<note-box type="info" title="Implementation details">
|
||||||
<p>
|
Spearhead detects scenery targets by the trigger zone name. A zone named
|
||||||
Bridges, buildings or other type of targets that are baked into the map are awesome targets.<br>
|
<strong>scenerytarget_[freeform]</strong> or
|
||||||
We wanted to make sure they were easily integrated in Spearhead.
|
<strong>scenerytargets</strong> (case-insensitive) will be scanned and any scenery objects that
|
||||||
</p>
|
has the attribute "Buildings" inside the zone
|
||||||
|
will be added as mission scenery targets.
|
||||||
<note-box type="info" title="Implementation details">
|
|
||||||
Spearhead detects scenery targets by the trigger zone name. A zone named <strong>scenerytarget_[freeform]</strong> or
|
|
||||||
<strong>scenerytargets</strong> (case-insensitive) will be scanned and any scenery objects that has the attribute "Buildings" inside the zone
|
|
||||||
will be added as mission scenery targets.
|
|
||||||
</note-box>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
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.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<note-box type="warning" title="Changing IDs">
|
|
||||||
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.
|
|
||||||
</note-box>
|
</note-box>
|
||||||
|
|
||||||
|
<p>
|
||||||
<p>Here's two images showing how a bridge is added to a mission.</p>
|
Scenery targets are treated like mission targets: they are included in the mission completion
|
||||||
<img src="/img/bridge.png" style="max-height: 35remrem;"/>
|
calculation
|
||||||
|
(their `IsAlive()` state is checked) and their state is persisted/updated when missions spawn or
|
||||||
|
resume.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<note-box type="warning" title="Changing IDs">
|
||||||
|
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.
|
||||||
|
</note-box>
|
||||||
|
|
||||||
|
|
||||||
|
<p>Here's two images showing how a bridge is added to a mission.</p>
|
||||||
|
<img src="/img/bridge.png" style="max-height: 35remrem;" />
|
||||||
|
</div>
|
||||||
|
<div id="cas-region">
|
||||||
|
<h2 id="cas">CAS</h2>
|
||||||
|
<p>
|
||||||
|
Naming: <code-inline>MISSION_CAS_[Name]</code-inline> <br>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="BattleManager">Battle Manager</h3>
|
||||||
|
<p>TBD</p>
|
||||||
|
</div>
|
||||||
|
<div id="dead-region">
|
||||||
|
<h2 id="dead">DEAD</h2>
|
||||||
|
<p>
|
||||||
|
Naming: <code-inline>MISSION_DEAD_[Name]</code-inline> <br>
|
||||||
|
Naming: <code-inline>MISSION_SAM_[Name]</code-inline> <br>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="sam-vs-dead">SAM vs DEAD</h3>
|
||||||
|
<p>TBD</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="bai-region">
|
||||||
|
<h2 id="bai">BAI</h2>
|
||||||
|
<p>
|
||||||
|
Naming: <code-inline>MISSION_BAI_[Name]</code-inline> <br>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="deepstrike-region">
|
||||||
|
<h2 id="deepstrike">DEEPSTRIKE</h2>
|
||||||
|
<p>
|
||||||
|
Naming: <code-inline>MISSION_DEEPSTRIKE_[Name]</code-inline> <br>
|
||||||
|
<br>
|
||||||
|
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. <br>
|
||||||
|
This allows you to plan missions that require more strategic positioning and timing. <br>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="activation">Activation</h3>
|
||||||
|
<p>
|
||||||
|
Deep Strike missions are activated when the Stage in which they are located becomes "PreActive" or "Active". <br>
|
||||||
|
"PreActive" is when either the current active StageNumber is a certain number of stages away OR the stage has "CAP" airbases active . <br>
|
||||||
|
<code-inline>SpearheadConfig.StageConfig.preactivateStage</code-inline> changes the configuration. <br>
|
||||||
|
<br>
|
||||||
|
For example: <br>
|
||||||
|
If the current active stage is <code-inline>MissionStage_2_[name]</code-inline> and preActivate config is set to 2. <br>
|
||||||
|
Then both <code-inline>MissionStage_3_[name]</code-inline> and <code-inline>MissionStage_4_[name]</code-inline> would become "PreActive".
|
||||||
|
</p>
|
||||||
|
<h3 id="primary-vs-secondary">Make Primary</h3>
|
||||||
|
<p>
|
||||||
|
By default DEEPSTRIKE missions are "Secondary" missions when spawned as a pre-activated stage.<br>
|
||||||
|
Then when the stage they are in is "Active", the mission becomes a "Primary" mission. <br>
|
||||||
|
<br>
|
||||||
|
If you want to make it a "Primary" mission from the start, you can overwrite it.<br>
|
||||||
|
Click the mission's trigger zone. Add a property named <code-inline>primary</code-inline> and set it to <code-inline>true</code-inline>.
|
||||||
|
This will make the mission "Primary" from the start. <br>
|
||||||
|
<br>
|
||||||
|
If you want it to "Secondary" even when its stage is the active stage, you can set "primary" to false. <br>
|
||||||
|
<br>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 id="future-additions">Future</h3>
|
||||||
|
<p>
|
||||||
|
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. <br>
|
||||||
|
Eg. Completing a DEEPSTRIKE mission would disable CAP for X amount of minutes after completion. <br>
|
||||||
|
This still needs to be refined, but we've already have ideas.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<p>© 2025 Spearhead Project</p>
|
<p>© 2025 Spearhead Project</p>
|
||||||
|
|||||||
@@ -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/>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
--color-bg-hover: rgba(120, 140, 255, 0.12); /* More visible hover */
|
--color-bg-hover: rgba(120, 140, 255, 0.12); /* More visible hover */
|
||||||
--color-bg-note-dark: rgba(40, 35, 30, 0.85); /* Slightly darker note box */
|
--color-bg-note-dark: rgba(40, 35, 30, 0.85); /* Slightly darker note box */
|
||||||
|
|
||||||
--color-text-primary: #a5a5a5; /* Brighter text */
|
--color-text-primary: #b4b3b3; /* Brighter text */
|
||||||
--color-text-secondary: #bfc8d8; /* Lighter secondary text */
|
--color-text-secondary: #bfc8d8; /* Lighter secondary text */
|
||||||
--color-text-accent: #7ecbff; /* Brighter accent */
|
--color-text-accent: #7ecbff; /* Brighter accent */
|
||||||
--color-text-light: #ffffff;
|
--color-text-light: #ffffff;
|
||||||
@@ -337,6 +337,7 @@ main {
|
|||||||
|
|
||||||
.side-nav {
|
.side-nav {
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
|
max-width: 200px;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ function FleetGroup:new(fleetGroupName, database, logger)
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if Util.startswith(namePart, "%[") == true then
|
if Util.startsWith(namePart, "%[") == true then
|
||||||
namePart = Util.split_string(namePart, "[")[1]
|
namePart = Util.split_string(namePart, "[")[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ GlobalFleetManager.start = function(database)
|
|||||||
|
|
||||||
local all_groups = MizGroupsManager.getAllGroupNames()
|
local all_groups = MizGroupsManager.getAllGroupNames()
|
||||||
for _, groupName in pairs(all_groups) do
|
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")
|
logger:info("Registering " .. groupName .. " as a managed fleet")
|
||||||
local carrierGroup = FleetGroup:new(groupName, database, logger)
|
local carrierGroup = FleetGroup:new(groupName, database, logger)
|
||||||
table.insert(fleetGroups, carrierGroup)
|
table.insert(fleetGroups, carrierGroup)
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ do
|
|||||||
for file in lfs.dir(dir) do
|
for file in lfs.dir(dir) do
|
||||||
|
|
||||||
local split = Util.split_string(file, ".")
|
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
|
if split and #split > 0 and split[#split] == EXTENSION and doesStartWith == true then
|
||||||
local numberString = split[#split-1]
|
local numberString = split[#split-1]
|
||||||
local number = tonumber(numberString)
|
local number = tonumber(numberString)
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -68,12 +69,14 @@ local StageDrawing = require("classes.stageClasses.drawings.StageDrawing")
|
|||||||
---@field descriptionLocation Vec2?
|
---@field descriptionLocation Vec2?
|
||||||
---@field dependsOn Array<string>
|
---@field dependsOn Array<string>
|
||||||
---@field completeAt number?
|
---@field completeAt number?
|
||||||
|
---@field primaryOverwrite boolean?
|
||||||
|
|
||||||
---@class FarpZoneData
|
---@class FarpZoneData
|
||||||
---@field groups Array<string>
|
---@field groups Array<string>
|
||||||
---@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
|
||||||
@@ -209,7 +212,7 @@ function Database.New(Logger)
|
|||||||
for i, layer in pairs(env.mission.drawings.layers) do
|
for i, layer in pairs(env.mission.drawings.layers) do
|
||||||
if string.lower(layer.name) == "author" then
|
if string.lower(layer.name) == "author" then
|
||||||
for key, layer_object in pairs(layer.objects) do
|
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)
|
local airbaseData = self:getAirbaseDataForDrawLayer(layer_object)
|
||||||
if airbaseData then
|
if airbaseData then
|
||||||
self._logger:debug("found airbase data for " .. layer_object.name)
|
self._logger:debug("found airbase data for " .. layer_object.name)
|
||||||
@@ -229,7 +232,7 @@ function Database.New(Logger)
|
|||||||
for i, layer in pairs(env.mission.drawings.layers) do
|
for i, layer in pairs(env.mission.drawings.layers) do
|
||||||
if string.lower(layer.name) == "author" then
|
if string.lower(layer.name) == "author" then
|
||||||
for key, layer_object in pairs(layer.objects) do
|
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 object = layer_object --[[@as DrawingObject]]
|
||||||
local stageDrawing = StageDrawing.New(object)
|
local stageDrawing = StageDrawing.New(object)
|
||||||
if stageDrawing then
|
if stageDrawing then
|
||||||
@@ -257,7 +260,7 @@ function Database.New(Logger)
|
|||||||
for i, layer in pairs(env.mission.drawings.layers) do
|
for i, layer in pairs(env.mission.drawings.layers) do
|
||||||
if string.lower(layer.name) == "author" then
|
if string.lower(layer.name) == "author" then
|
||||||
for key, layer_object in pairs(layer.objects) do
|
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 zone = DcsUtil.getZoneByName(stageZoneName)
|
||||||
local vec2 = { x = layer_object.mapX, y = layer_object.mapY }
|
local vec2 = { x = layer_object.mapX, y = layer_object.mapY }
|
||||||
if zone and Util.is2dPointInZone(vec2, zone) == true then
|
if zone and Util.is2dPointInZone(vec2, zone) == true then
|
||||||
@@ -482,7 +485,7 @@ end
|
|||||||
local getAvailableCAPGroups = function()
|
local getAvailableCAPGroups = function()
|
||||||
local result = {}
|
local result = {}
|
||||||
for name, value in pairs(is_group_taken) do
|
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)
|
table.insert(result, name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -585,11 +588,11 @@ function Database:loadCapUnits()
|
|||||||
for _, groupName in pairs(groups) do
|
for _, groupName in pairs(groups) do
|
||||||
is_group_taken[groupName] = true
|
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)
|
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)
|
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)
|
table.insert(baseData.SweepGroups, groupName)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -612,10 +615,31 @@ function Database:loadBlueSamUnits()
|
|||||||
local triggerZone = DcsUtil.getZoneByName(blueSamZone)
|
local triggerZone = DcsUtil.getZoneByName(blueSamZone)
|
||||||
if triggerZone then
|
if triggerZone then
|
||||||
for _, kvPair in pairs(triggerZone.properties) do
|
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)
|
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
|
||||||
@@ -679,9 +703,9 @@ function Database:LoadZoneData(missionZoneName)
|
|||||||
if triggerZone and triggerZone.properties then
|
if triggerZone and triggerZone.properties then
|
||||||
for _, kvPair in pairs(triggerZone.properties) do
|
for _, kvPair in pairs(triggerZone.properties) do
|
||||||
local key = kvPair.key
|
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)
|
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)
|
local value = tonumber(kvPair.value)
|
||||||
if value then
|
if value then
|
||||||
if value > 1 and value <= 100 then
|
if value > 1 and value <= 100 then
|
||||||
@@ -691,6 +715,14 @@ function Database:LoadZoneData(missionZoneName)
|
|||||||
end
|
end
|
||||||
self._tables.MissionZoneData[missionZoneName].completeAt = value
|
self._tables.MissionZoneData[missionZoneName].completeAt = value
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
@@ -703,7 +735,7 @@ function Database:LoadZoneData(missionZoneName)
|
|||||||
|
|
||||||
local vec2 = { x = layer_object.mapX, y = layer_object.mapY }
|
local vec2 = { x = layer_object.mapX, y = layer_object.mapY }
|
||||||
if triggerZone and Util.is2dPointInZone(vec2, triggerZone) then
|
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
|
local description = layer_object.text
|
||||||
if description and description ~= "" then
|
if description and description ~= "" then
|
||||||
self._tables.MissionZoneData[missionZoneName].description = description
|
self._tables.MissionZoneData[missionZoneName].description = description
|
||||||
@@ -746,11 +778,35 @@ function Database:loadFarpData()
|
|||||||
local triggerZone = DcsUtil.getZoneByName(farpZone)
|
local triggerZone = DcsUtil.getZoneByName(farpZone)
|
||||||
if triggerZone then
|
if triggerZone then
|
||||||
for _, kvPair in pairs(triggerZone.properties) do
|
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)
|
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
|
||||||
|
else
|
||||||
|
MissionEditorWarnings.Add("Buildable number for " .. farpZone .. " is invalid.")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -432,6 +432,12 @@ function Stage:PreActivate()
|
|||||||
end
|
end
|
||||||
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
|
for _, airbase in pairs(self._db.airbases) do
|
||||||
airbase:ActivateRedStage()
|
airbase:ActivateRedStage()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
local Stage = require("classes.stageClasses.Stages.BaseStage.Stage")
|
local Stage = require("classes.stageClasses.Stages.BaseStage.Stage")
|
||||||
local GlobalCapManager = require("classes.capClasses.GlobalCapManager")
|
local GlobalCapManager = require("classes.capClasses.GlobalCapManager")
|
||||||
|
local StageState = require("classes.stageClasses.Stages.StageState")
|
||||||
|
|
||||||
---@class ExtraStage : Stage
|
---@class ExtraStage : Stage
|
||||||
local ExtraStage = {}
|
local ExtraStage = {}
|
||||||
@@ -61,7 +62,7 @@ function ExtraStage:OnStageNumberChanged(number, stageLaneIdentifier)
|
|||||||
self:ActivateStage()
|
self:ActivateStage()
|
||||||
end
|
end
|
||||||
|
|
||||||
if self._currentStageState == Stage.CurrentStageState.BLUE then
|
if self._currentStageState == StageState.BLUE then
|
||||||
self:ActivateBlueStage()
|
self:ActivateBlueStage()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ local logger = Logger.new("DrawingHelper", level)
|
|||||||
local DrawingHelper = {}
|
local DrawingHelper = {}
|
||||||
DrawingHelper.__index = DrawingHelper
|
DrawingHelper.__index = DrawingHelper
|
||||||
|
|
||||||
|
|
||||||
---@param object DrawingObject
|
---@param object DrawingObject
|
||||||
---@return Array<integer> id
|
---@return Array<integer> id
|
||||||
function DrawingHelper.Draw(object)
|
function DrawingHelper.Draw(object)
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ function MissionCommandsHelper:OverviewToGroup(groupID)
|
|||||||
for code, enabled in pairs(self.enabledByCode) do
|
for code, enabled in pairs(self.enabledByCode) do
|
||||||
if enabled == true then
|
if enabled == true then
|
||||||
local mission = self.missionsByCode[code]
|
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)
|
table.insert(primaryMissions, mission)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -232,7 +232,7 @@ function MissionCommandsHelper:OverviewToGroup(groupID)
|
|||||||
for code, enabled in pairs(self.enabledByCode) do
|
for code, enabled in pairs(self.enabledByCode) do
|
||||||
if enabled == true then
|
if enabled == true then
|
||||||
local mission = self.missionsByCode[code]
|
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)
|
table.insert(secondaryMissions, mission)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -347,7 +347,7 @@ function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID)
|
|||||||
for code, enabled in pairs(self.enabledByCode) do
|
for code, enabled in pairs(self.enabledByCode) do
|
||||||
if enabled == true then
|
if enabled == true then
|
||||||
local mission = self.missionsByCode[code]
|
local mission = self.missionsByCode[code]
|
||||||
if mission and mission.priority == "primary" then
|
if mission and mission:GetPriority() == "primary" then
|
||||||
table.insert(primaryMissions, mission)
|
table.insert(primaryMissions, mission)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -376,7 +376,7 @@ function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID)
|
|||||||
for code, enabled in pairs(self.enabledByCode) do
|
for code, enabled in pairs(self.enabledByCode) do
|
||||||
if enabled == true then
|
if enabled == true then
|
||||||
local mission = self.missionsByCode[code]
|
local mission = self.missionsByCode[code]
|
||||||
if mission and mission.priority == "secondary" then
|
if mission and mission:GetPriority() == "secondary" then
|
||||||
table.insert(secondaryMissions, mission)
|
table.insert(secondaryMissions, mission)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -418,7 +418,7 @@ function MissionCommandsHelper:addMissionCommands(groupId, path, mission)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local missionFolderName = "[" ..
|
local missionFolderName = "[" ..
|
||||||
mission.code .. "]" .. distance .. mission.name .. "( " .. mission.missionTypeDisplay .. " )"
|
mission.code .. "]" .. distance .. mission.name .. "(" .. mission.missionTypeDisplay .. ")"
|
||||||
missionCommands.addSubMenuForGroup(groupId, missionFolderName, path)
|
missionCommands.addSubMenuForGroup(groupId, missionFolderName, path)
|
||||||
table.insert(path, missionFolderName)
|
table.insert(path, missionFolderName)
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ local SupplyConfigHelper = {}
|
|||||||
---@return SupplyConfig?
|
---@return SupplyConfig?
|
||||||
function SupplyConfigHelper.fromObjectName(name)
|
function SupplyConfigHelper.fromObjectName(name)
|
||||||
for configName, config in pairs(SupplyConfig) do
|
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
|
return config
|
||||||
end
|
end
|
||||||
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())
|
||||||
self.name = "Resupply"
|
|
||||||
|
local splitTargetZoneName = Util.split_string(targetZone.name, "_")
|
||||||
|
if splitTargetZoneName and splitTargetZoneName[3] and splitTargetZoneName[3] ~= "" then
|
||||||
|
self.name = splitTargetZoneName[3]
|
||||||
|
else
|
||||||
|
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" ..
|
||||||
@@ -237,7 +258,7 @@ function BuildableMission:CheckCratesInZone()
|
|||||||
|
|
||||||
local crates = self._supplyUnitsTracker:GetCargoCratesDropped()
|
local crates = self._supplyUnitsTracker:GetCargoCratesDropped()
|
||||||
for _, staticObject in pairs(crates) do
|
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()
|
local pos = staticObject:getPoint()
|
||||||
|
|
||||||
if Util.is3dPointInZone(pos, self._dropOffZone) then
|
if Util.is3dPointInZone(pos, self._dropOffZone) then
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ local DcsUtil = require("classes.util.DcsUtil")
|
|||||||
---@field private _completeAtIndex number
|
---@field private _completeAtIndex number
|
||||||
---@field private _parentStage Stage
|
---@field private _parentStage Stage
|
||||||
---@field private _battleManager? BattleManager
|
---@field private _battleManager? BattleManager
|
||||||
---@field private _lastContactMarkerID number;
|
---@field private _lastContactMarkerID number
|
||||||
local ZoneMission = {}
|
local ZoneMission = {}
|
||||||
|
|
||||||
--- @class MissionGroups
|
--- @class MissionGroups
|
||||||
@@ -24,7 +24,7 @@ local ZoneMission = {}
|
|||||||
--- @field unitsAlive table<string, table<string, boolean>>
|
--- @field unitsAlive table<string, table<string, boolean>>
|
||||||
--- @field targetsAlive table<string, table<string, boolean>>
|
--- @field targetsAlive table<string, table<string, boolean>>
|
||||||
--- @field sceneryTargets Array<SpearheadSceneryObject>
|
--- @field sceneryTargets Array<SpearheadSceneryObject>
|
||||||
--- @field groupNamesPerunit table<string,string>
|
--- @field groupNamesPerUnit table<string,string>
|
||||||
|
|
||||||
---@class ParsedMissionName
|
---@class ParsedMissionName
|
||||||
---@field missionName string
|
---@field missionName string
|
||||||
@@ -36,7 +36,7 @@ local ZoneMission = {}
|
|||||||
local function ParseZoneName(input)
|
local function ParseZoneName(input)
|
||||||
local split_name = Util.split_string(input, "_")
|
local split_name = Util.split_string(input, "_")
|
||||||
local split_length = Util.tableLength(split_name)
|
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")
|
MissionEditorWarnings.Add("Random Mission with zonename " .. input .. " not in right format")
|
||||||
return nil
|
return nil
|
||||||
elseif split_length < 3 then
|
elseif split_length < 3 then
|
||||||
@@ -53,9 +53,10 @@ local function ParseZoneName(input)
|
|||||||
if inputType == "cas" then parsedType = "CAS" end
|
if inputType == "cas" then parsedType = "CAS" end
|
||||||
if inputType == "bai" then parsedType = "BAI" end
|
if inputType == "bai" then parsedType = "BAI" end
|
||||||
if inputType == "sam" then parsedType = "SAM" end
|
if inputType == "sam" then parsedType = "SAM" end
|
||||||
|
if inputType == "deepstrike" then parsedType = "DEEPSTRIKE" end
|
||||||
|
|
||||||
if parsedType == "nil" then
|
if parsedType == "nil" then
|
||||||
MissionEditorWarnings.Add("Mission with zonename '" ..
|
MissionEditorWarnings.Add("Mission with zoneName '" ..
|
||||||
input .. "' has an unsupported type '" .. (type or "nil"))
|
input .. "' has an unsupported type '" .. (type or "nil"))
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -66,8 +67,6 @@ local function ParseZoneName(input)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
MINIMAL_UNITS_ALIVE_RATIO = 0.21
|
|
||||||
|
|
||||||
---comment
|
---comment
|
||||||
---@param zoneName string
|
---@param zoneName string
|
||||||
---@param priority MissionPriority
|
---@param priority MissionPriority
|
||||||
@@ -112,7 +111,7 @@ function ZoneMission.new(zoneName, priority, database, logger, parentStage, spaw
|
|||||||
unitsAlive = {},
|
unitsAlive = {},
|
||||||
targetsAlive = {},
|
targetsAlive = {},
|
||||||
hasTargets = false,
|
hasTargets = false,
|
||||||
groupNamesPerunit = {},
|
groupNamesPerUnit = {},
|
||||||
sceneryTargets = {}
|
sceneryTargets = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,17 +149,17 @@ function ZoneMission.new(zoneName, priority, database, logger, parentStage, spaw
|
|||||||
local spearheadGroup = SpearheadGroup.New(groupName, spawnManager, true)
|
local spearheadGroup = SpearheadGroup.New(groupName, spawnManager, true)
|
||||||
table.insert(self._missionGroups.redGroups, spearheadGroup)
|
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
|
for _, unit in pairs(spearheadGroup:GetObjects()) do
|
||||||
local unitName = unit:getName()
|
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
|
if self._missionGroups.unitsAlive[groupName] == nil then
|
||||||
self._missionGroups.unitsAlive[groupName] = {}
|
self._missionGroups.unitsAlive[groupName] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
self._missionGroups.unitsAlive[groupName][unitName] = true
|
self._missionGroups.unitsAlive[groupName][unitName] = true
|
||||||
self._missionGroups.groupNamesPerunit[unitName] = groupName
|
self._missionGroups.groupNamesPerUnit[unitName] = groupName
|
||||||
|
|
||||||
if isGroupTarget == true or isUnitTarget == true then
|
if isGroupTarget == true or isUnitTarget == true then
|
||||||
self._missionGroups.hasTargets = true
|
self._missionGroups.hasTargets = true
|
||||||
@@ -180,7 +179,6 @@ function ZoneMission.new(zoneName, priority, database, logger, parentStage, spaw
|
|||||||
|
|
||||||
if self.missionType == "CAS" then
|
if self.missionType == "CAS" then
|
||||||
self._battleManager = BattleManager.New(self._missionGroups.redGroups, self._missionGroups.blueGroups, self.zoneName, self._logger.LogLevel)
|
self._battleManager = BattleManager.New(self._missionGroups.redGroups, self._missionGroups.blueGroups, self.zoneName, self._logger.LogLevel)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self._logger:debug("Mission " .. self.name .. " group count: " .. Util.tableLength(missionData.RedGroups))
|
self._logger:debug("Mission " .. self.name .. " group count: " .. Util.tableLength(missionData.RedGroups))
|
||||||
@@ -354,6 +352,19 @@ end
|
|||||||
function ZoneMission:SpawnInactive()
|
function ZoneMission:SpawnInactive()
|
||||||
self._logger:info("PreActivating " .. self.name)
|
self._logger:info("PreActivating " .. self.name)
|
||||||
|
|
||||||
|
if self.missionType == "DEEPSTRIKE" then
|
||||||
|
local missionData = self._database:getMissionDataForZone(self.zoneName)
|
||||||
|
---@type MissionPriority
|
||||||
|
local priority = "secondary"
|
||||||
|
if missionData and missionData.primaryOverwrite ~= nil then
|
||||||
|
if missionData.primaryOverwrite == true then
|
||||||
|
priority = "primary"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self._priority = priority
|
||||||
|
self._missionCommandsHelper:AddMissionToCommands(self)
|
||||||
|
end
|
||||||
|
|
||||||
for _, group in pairs(self._missionGroups.redGroups) do
|
for _, group in pairs(self._missionGroups.redGroups) do
|
||||||
group:Spawn()
|
group:Spawn()
|
||||||
end
|
end
|
||||||
@@ -390,6 +401,17 @@ function ZoneMission:SpawnActive()
|
|||||||
self._battleManager:Start()
|
self._battleManager:Start()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self._missionCommandsHelper:RemoveMissionToCommands(self) -- Remove first
|
||||||
|
if self.missionType == "DEEPSTRIKE" then
|
||||||
|
local missionData = self._database:getMissionDataForZone(self.zoneName)
|
||||||
|
local priority = "primary"
|
||||||
|
if missionData and missionData.primaryOverwrite ~= nil then
|
||||||
|
if missionData.primaryOverwrite == false then
|
||||||
|
priority = "secondary"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self._priority = priority
|
||||||
|
end
|
||||||
self._missionCommandsHelper:AddMissionToCommands(self)
|
self._missionCommandsHelper:AddMissionToCommands(self)
|
||||||
|
|
||||||
self:StartCheckingContinuous()
|
self:StartCheckingContinuous()
|
||||||
@@ -480,7 +502,7 @@ function ZoneMission:OnUnitLost(object)
|
|||||||
local unitName = object:getName()
|
local unitName = object:getName()
|
||||||
self._logger:debug("UnitName:" .. unitName)
|
self._logger:debug("UnitName:" .. unitName)
|
||||||
|
|
||||||
local groupName = self._missionGroups.groupNamesPerunit[unitName]
|
local groupName = self._missionGroups.groupNamesPerUnit[unitName]
|
||||||
self._missionGroups.unitsAlive[groupName][unitName] = false
|
self._missionGroups.unitsAlive[groupName][unitName] = false
|
||||||
|
|
||||||
if self._missionGroups.targetsAlive[groupName] and self._missionGroups.targetsAlive[groupName][unitName] then
|
if self._missionGroups.targetsAlive[groupName] and self._missionGroups.targetsAlive[groupName][unitName] then
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ local GlobalConfig = require("classes.configuration.GlobalConfig")
|
|||||||
---@field zoneName string
|
---@field zoneName string
|
||||||
---@field missionType MissionType
|
---@field missionType MissionType
|
||||||
---@field missionTypeDisplay string
|
---@field missionTypeDisplay string
|
||||||
---@field priority MissionPriority
|
---@field protected _priority MissionPriority
|
||||||
---@field location Vec2?
|
---@field location Vec2?
|
||||||
---@field code string
|
---@field code string
|
||||||
---@field protected _state MissionState
|
---@field protected _state MissionState
|
||||||
@@ -40,7 +40,7 @@ function Mission.newSuper(self, zoneName, missionName, missionType, missionBrief
|
|||||||
self.zoneName = zoneName
|
self.zoneName = zoneName
|
||||||
self.name = missionName
|
self.name = missionName
|
||||||
self.missionType = missionType
|
self.missionType = missionType
|
||||||
self.priority = priority
|
self._priority = priority
|
||||||
self._state = "NEW"
|
self._state = "NEW"
|
||||||
self._logger = logger
|
self._logger = logger
|
||||||
self._database = database
|
self._database = database
|
||||||
@@ -64,6 +64,11 @@ end
|
|||||||
|
|
||||||
--region PUBLIC
|
--region PUBLIC
|
||||||
|
|
||||||
|
---@return MissionPriority
|
||||||
|
function Mission:GetPriority()
|
||||||
|
return self._priority
|
||||||
|
end
|
||||||
|
|
||||||
function Mission:SpawnPersistedState() end
|
function Mission:SpawnPersistedState() end
|
||||||
function Mission:SpawnActive() end
|
function Mission:SpawnActive() end
|
||||||
|
|
||||||
@@ -112,7 +117,7 @@ end
|
|||||||
function Mission:NotifyMissionComplete()
|
function Mission:NotifyMissionComplete()
|
||||||
self._missionCommandsHelper:RemoveMissionToCommands(self)
|
self._missionCommandsHelper:RemoveMissionToCommands(self)
|
||||||
self._logger:info("Mission Completed: " .. self.zoneName)
|
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
|
for _, listener in pairs(self._completeListeners) do
|
||||||
pcall(function()
|
pcall(function()
|
||||||
@@ -120,7 +125,7 @@ function Mission:NotifyMissionComplete()
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
local succ, err = pcall(function()
|
local success, err = pcall(function()
|
||||||
SpearheadAPI.Internal.notifyMissionComplete(self.zoneName)
|
SpearheadAPI.Internal.notifyMissionComplete(self.zoneName)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@@ -153,6 +158,7 @@ do --aliases
|
|||||||
--- @alias MissionType
|
--- @alias MissionType
|
||||||
--- | "nil"
|
--- | "nil"
|
||||||
--- | "STRIKE"
|
--- | "STRIKE"
|
||||||
|
--- | "DEEPSTRIKE"
|
||||||
--- | "CAS"
|
--- | "CAS"
|
||||||
--- | "BAI"
|
--- | "BAI"
|
||||||
--- | "DEAD"
|
--- | "DEAD"
|
||||||
|
|||||||
@@ -644,7 +644,7 @@ do -- INIT DCS_UTIL
|
|||||||
---@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
|
||||||
@@ -654,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
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
---@class Util
|
---@class Util
|
||||||
local UTIL = {}
|
local UTIL = {}
|
||||||
do -- INIT UTIL
|
do -- INIT UTIL
|
||||||
---splits a string in sub parts by seperator
|
---splits a string in sub parts by separator
|
||||||
---@param input string
|
---@param input string
|
||||||
---@param seperator string
|
---@param separator string
|
||||||
---@return table result list of strings
|
---@return table result list of strings
|
||||||
function UTIL.split_string(input, seperator)
|
function UTIL.split_string(input, separator)
|
||||||
if seperator == nil then
|
if separator == nil then
|
||||||
seperator = " "
|
separator = " "
|
||||||
end
|
end
|
||||||
|
|
||||||
local result = {}
|
local result = {}
|
||||||
@@ -15,7 +15,7 @@ do -- INIT UTIL
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
for str in string.gmatch(input, "[^" .. seperator .. "]+") do
|
for str in string.gmatch(input, "[^" .. separator .. "]+") do
|
||||||
table.insert(result, str)
|
table.insert(result, str)
|
||||||
end
|
end
|
||||||
return result
|
return result
|
||||||
@@ -120,7 +120,7 @@ do -- INIT UTIL
|
|||||||
---@param findable string
|
---@param findable string
|
||||||
---@param ignoreCase boolean?
|
---@param ignoreCase boolean?
|
||||||
---@return boolean
|
---@return boolean
|
||||||
UTIL.startswith = function(str, findable, ignoreCase)
|
UTIL.startsWith = function(str, findable, ignoreCase)
|
||||||
if ignoreCase == true then
|
if ignoreCase == true then
|
||||||
return string.lower(str):find('^' .. string.lower(findable)) ~= nil
|
return string.lower(str):find('^' .. string.lower(findable)) ~= nil
|
||||||
end
|
end
|
||||||
@@ -150,7 +150,7 @@ do -- INIT UTIL
|
|||||||
---@return boolean
|
---@return boolean
|
||||||
UTIL.startswithAny = function(str, findableTable)
|
UTIL.startswithAny = function(str, findableTable)
|
||||||
for key, value in pairs(findableTable) do
|
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
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user