From 5277c5e5660434660e63addb7651182e9186cc16 Mon Sep 17 00:00:00 2001
From: dutchie031
Date: Thu, 30 Jul 2026 14:53:33 +0200
Subject: [PATCH] updated docs
---
.docs/web/index.html | 33 +-
.docs/web/js/components/code-block.js | 58 +--
.docs/web/js/components/code-inline.js | 64 +--
.../js/components/latest-version-download.js | 4 +-
.docs/web/js/components/note.js | 70 ++--
.docs/web/js/components/sidebar.js | 394 +++++++++---------
.docs/web/js/prism.js | 20 +-
.docs/web/js/site.js | 180 ++++----
.docs/web/pages/about_us.html | 6 +-
.docs/web/pages/first-start.html | 4 +-
.docs/web/pages/reference.html | 13 +-
.docs/web/pages/spearheadapi.html | 118 +++---
.docs/web/pages/tutorials.html | 2 +-
.docs/web/style/prism.css | 6 +-
14 files changed, 493 insertions(+), 479 deletions(-)
diff --git a/.docs/web/index.html b/.docs/web/index.html
index 3ba81de..511d204 100644
--- a/.docs/web/index.html
+++ b/.docs/web/index.html
@@ -32,23 +32,28 @@
-
Welcome to Spearhead!
+
Welcome to Spearhead!
+
+
Welcome to the story teller friendly mission framework in DCS (at least, that's what we hope to create).
+
Together with mission editors we've tried to build a framework that makes creating multiplayer missions as easy as possible.
+
+ With the help of naming conventions, trigger zones, pre-configured logic and custom configuration items, it gives a huge amount of versatility.
+ we're trying to strike a balance between no-code and low-code with the possibility to hook into it for the hard core scripters (like ourselves).
+
+
+ For the scripters : If you yourself are a scripter, and you're missing interfaces, please reach out to us! We want to make sure that the framework is as easy to use for scripters as it is for non-scripters, and we can't do that without your help!
+
+
+
+ Whether this is your first mission or your hundredth, we hope Spearhead will make your life easier.
+
+
+
+
-
Welcome to the story teller friendly mission framework in DCS (at least, that's what we hope to create).
-
Together with mission editors we've tried to build a framework that
- makes creating multiplayer missions as easy as possible.
- With the help of naming conventions, trigger zones, pre-configured
- logic and custom configuration items, it gives a huge amount of versatility.
- we're trying to strike a balance between no-code and low-code with the possibility to hook into it for
- the hard core scripters.
-
-
- Whether this is your first mission or your hundredth, we hope Spearhead will make your life easier.
-
-
-
+
diff --git a/.docs/web/js/components/code-block.js b/.docs/web/js/components/code-block.js
index d21ec5d..90146f5 100644
--- a/.docs/web/js/components/code-block.js
+++ b/.docs/web/js/components/code-block.js
@@ -1,29 +1,29 @@
-class CodeBlock extends HTMLElement {
- connectedCallback() {
- // Get the code content as text, preserving whitespace
- let code = this.textContent.replace(/\r\n?/g, "\n");
- // Remove leading/trailing blank lines
- code = code.replace(/^\s*\n/, '').replace(/\n\s*$/, '');
- // Find leading spaces from the first non-empty line
- const lines = code.split("\n");
- const firstLine = lines.find(line => line.trim().length > 0) || '';
- const leadingSpaces = firstLine.match(/^\s*/)[0].length;
- // Remove that many leading spaces from all lines
- const stripped = lines.map(line => line.slice(leadingSpaces)).join("\n");
- // Escape HTML special characters
- const escaped = stripped
- .replace(/&/g, "&")
- .replace(//g, ">");
- const lang = this.getAttribute('lang') || '';
- const langClass = lang ? `language-${lang}` : '';
- this.innerHTML = `${escaped} `;
- // If Prism or highlight.js is present, trigger highlighting
- if (window.Prism && Prism.highlightElement) {
- Prism.highlightElement(this.querySelector('code'));
- } else if (window.hljs && hljs.highlightElement) {
- hljs.highlightElement(this.querySelector('code'));
- }
- }
-}
-customElements.define('code-block', CodeBlock);
+class CodeBlock extends HTMLElement {
+ connectedCallback() {
+ // Get the code content as text, preserving whitespace
+ let code = this.textContent.replace(/\r\n?/g, "\n");
+ // Remove leading/trailing blank lines
+ code = code.replace(/^\s*\n/, '').replace(/\n\s*$/, '');
+ // Find leading spaces from the first non-empty line
+ const lines = code.split("\n");
+ const firstLine = lines.find(line => line.trim().length > 0) || '';
+ const leadingSpaces = firstLine.match(/^\s*/)[0].length;
+ // Remove that many leading spaces from all lines
+ const stripped = lines.map(line => line.slice(leadingSpaces)).join("\n");
+ // Escape HTML special characters
+ const escaped = stripped
+ .replace(/&/g, "&")
+ .replace(//g, ">");
+ const lang = this.getAttribute('lang') || '';
+ const langClass = lang ? `language-${lang}` : '';
+ this.innerHTML = `${escaped} `;
+ // If Prism or highlight.js is present, trigger highlighting
+ if (window.Prism && Prism.highlightElement) {
+ Prism.highlightElement(this.querySelector('code'));
+ } else if (window.hljs && hljs.highlightElement) {
+ hljs.highlightElement(this.querySelector('code'));
+ }
+ }
+}
+customElements.define('code-block', CodeBlock);
diff --git a/.docs/web/js/components/code-inline.js b/.docs/web/js/components/code-inline.js
index a5f1627..6e890ea 100644
--- a/.docs/web/js/components/code-inline.js
+++ b/.docs/web/js/components/code-inline.js
@@ -1,32 +1,32 @@
-class CodeInline extends HTMLElement {
- connectedCallback() {
- // Get the code content as text
- let code = this.textContent;
-
- // Escape HTML special characters
- code = code
- .replace(/&/g, "&")
- .replace(//g, ">");
-
- // Highlight variables: $variable, {variable}, or %variable%
- code = code.replace(/(\$[a-zA-Z_][\w]*)|(\{[^\}]+\})|(%[^%]+%)/g, match =>
- `${match} `
- );
-
- // Get language attribute for potential syntax highlighting
- const lang = this.getAttribute('lang') || '';
- const langClass = lang ? `language-${lang}` : '';
-
- this.innerHTML = `${code}`;
-
- // If Prism or highlight.js is present, trigger highlighting
- if (window.Prism && Prism.highlightElement) {
- Prism.highlightElement(this.querySelector('code'));
- } else if (window.hljs && hljs.highlightElement) {
- hljs.highlightElement(this.querySelector('code'));
- }
- }
-}
-
-customElements.define('code-inline', CodeInline);
+class CodeInline extends HTMLElement {
+ connectedCallback() {
+ // Get the code content as text
+ let code = this.textContent;
+
+ // Escape HTML special characters
+ code = code
+ .replace(/&/g, "&")
+ .replace(//g, ">");
+
+ // Highlight variables: $variable, {variable}, or %variable%
+ code = code.replace(/(\$[a-zA-Z_][\w]*)|(\{[^\}]+\})|(%[^%]+%)/g, match =>
+ `${match} `
+ );
+
+ // Get language attribute for potential syntax highlighting
+ const lang = this.getAttribute('lang') || '';
+ const langClass = lang ? `language-${lang}` : '';
+
+ this.innerHTML = `${code}`;
+
+ // If Prism or highlight.js is present, trigger highlighting
+ if (window.Prism && Prism.highlightElement) {
+ Prism.highlightElement(this.querySelector('code'));
+ } else if (window.hljs && hljs.highlightElement) {
+ hljs.highlightElement(this.querySelector('code'));
+ }
+ }
+}
+
+customElements.define('code-inline', CodeInline);
diff --git a/.docs/web/js/components/latest-version-download.js b/.docs/web/js/components/latest-version-download.js
index 6c3cc8b..4d465e3 100644
--- a/.docs/web/js/components/latest-version-download.js
+++ b/.docs/web/js/components/latest-version-download.js
@@ -66,7 +66,7 @@ class DownloadScript extends HTMLElement {
var version = "?";
var timestamp = "?";
var size = "?";
- var href = "https://git.dutchie031.com/Spearhead/spearhead/releases"
+ var href = "https://git.dutchie031.com/api/v1/repos/Spearhead/spearhead/releases"
const latestRelease = await this.fetchLatestRelease();
if (latestRelease) {
@@ -105,7 +105,7 @@ class DownloadScript extends HTMLElement {
${version} (${timestamp})
Download (${size})
- See All Versions here
+ See All Versions here
diff --git a/.docs/web/js/components/note.js b/.docs/web/js/components/note.js
index 8bd79f7..9f84344 100644
--- a/.docs/web/js/components/note.js
+++ b/.docs/web/js/components/note.js
@@ -1,35 +1,35 @@
-class Note extends HTMLElement {
- connectedCallback() {
- // Get the note content
- const content = this.innerHTML;
-
- // Get optional type attribute for different note styles
- const type = this.getAttribute('type') || 'default';
-
- // Get optional title attribute
- const title = this.getAttribute('title');
-
- // Build the note HTML
- let noteHTML = '';
-
- // Add title if provided
- if (title) {
- noteHTML += `
${title} `;
- }
-
- // Add the content
- noteHTML += content;
- noteHTML += '
';
-
- this.innerHTML = noteHTML;
- }
-}
-
-customElements.define('note-box', Note);
+class Note extends HTMLElement {
+ connectedCallback() {
+ // Get the note content
+ const content = this.innerHTML;
+
+ // Get optional type attribute for different note styles
+ const type = this.getAttribute('type') || 'default';
+
+ // Get optional title attribute
+ const title = this.getAttribute('title');
+
+ // Build the note HTML
+ let noteHTML = '';
+
+ // Add title if provided
+ if (title) {
+ noteHTML += `
${title} `;
+ }
+
+ // Add the content
+ noteHTML += content;
+ noteHTML += '';
+
+ this.innerHTML = noteHTML;
+ }
+}
+
+customElements.define('note-box', Note);
diff --git a/.docs/web/js/components/sidebar.js b/.docs/web/js/components/sidebar.js
index f4e146f..3724238 100644
--- a/.docs/web/js/components/sidebar.js
+++ b/.docs/web/js/components/sidebar.js
@@ -1,198 +1,198 @@
-class Sidebar extends HTMLElement {
- constructor() {
- super();
- this.navItems = [];
- }
-
- connectedCallback() {
- this.render();
- this.scanHeaders();
- this.setupScrollListener();
- this.highlightActiveSection();
- }
-
- scanHeaders() {
- // Clear existing nav items
- this.navItems = [];
-
- // Find all h2, h3, and h4 elements with IDs in the content area
- const contentWrapper = document.querySelector('.content-wrapper');
- if (!contentWrapper) return;
-
- const headers = contentWrapper.querySelectorAll('h2[id], h3[id], h4[id]');
-
- headers.forEach(header => {
- const id = header.getAttribute('id');
- const text = header.textContent.trim();
- const level = header.tagName.toLowerCase();
-
- this.navItems.push({
- id,
- text,
- level,
- element: header
- });
- });
-
- this.renderNavigation();
- }
-
- renderNavigation() {
- const ul = this.querySelector('ul');
- if (!ul) return;
-
- // Clear existing content
- ul.innerHTML = '';
-
- let currentH2Li = null;
- let currentH3Li = null;
-
- this.navItems.forEach(item => {
- if (item.level === 'h2') {
- // Create h2 item
- const li = document.createElement('li');
- const a = document.createElement('a');
- a.href = `#${item.id}`;
- a.className = 'side-nav-h2';
- a.textContent = item.text;
- a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
-
- li.appendChild(a);
- ul.appendChild(li);
- currentH2Li = li;
- currentH3Li = null;
- } else if (item.level === 'h3' && currentH2Li) {
- // Create h3 item under current h2
- let subUl = currentH2Li.querySelector('ul');
- if (!subUl) {
- subUl = document.createElement('ul');
- currentH2Li.appendChild(subUl);
- }
-
- const li = document.createElement('li');
- const a = document.createElement('a');
- a.href = `#${item.id}`;
- a.className = 'side-nav-h3';
- a.textContent = item.text;
- a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
-
- li.appendChild(a);
- subUl.appendChild(li);
- currentH3Li = li;
- } else if (item.level === 'h4' && currentH3Li) {
- // Create h4 item under current h3
- let subUl = currentH3Li.querySelector('ul');
- if (!subUl) {
- subUl = document.createElement('ul');
- currentH3Li.appendChild(subUl);
- }
-
- const li = document.createElement('li');
- const a = document.createElement('a');
- a.href = `#${item.id}`;
- a.className = 'side-nav-h4';
- a.textContent = item.text;
- a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
-
- li.appendChild(a);
- subUl.appendChild(li);
- }
- });
- }
-
- handleNavClick(e, targetId) {
- e.preventDefault();
-
- // Remove active class from all links
- this.querySelectorAll('a').forEach(link => {
- link.classList.remove('active');
- });
-
- // Add active class to clicked link
- e.target.classList.add('active');
-
- // Smooth scroll to target
- const targetElement = document.getElementById(targetId);
- if (targetElement) {
- targetElement.scrollIntoView({
- behavior: 'smooth',
- block: 'start'
- });
- }
- }
-
- setupScrollListener() {
- let ticking = false;
-
- const handleScroll = () => {
- if (!ticking) {
- requestAnimationFrame(() => {
- this.highlightActiveSection();
- ticking = false;
- });
- ticking = true;
- }
- };
-
- window.addEventListener('scroll', handleScroll);
- }
-
- highlightActiveSection() {
- const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
- const offset = 100; // Offset for highlighting
-
- let activeId = '';
-
- // Find the currently visible section
- this.navItems.forEach(item => {
- const element = item.element;
- const rect = element.getBoundingClientRect();
- const elementTop = rect.top + scrollTop;
-
- if (elementTop <= scrollTop + offset) {
- activeId = item.id;
- }
- });
-
- // Update active state
- this.querySelectorAll('a').forEach(link => {
- link.classList.remove('active');
- });
-
- if (activeId !== nil && activeId !== '') {
- const activeLink = this.querySelector(`a[href="#${activeId}"]`);
- if (activeLink) {
- activeLink.classList.add('active');
- }
- }
- }
-
- render() {
- this.innerHTML = `
-
- `;
- }
-
- // Method to refresh the sidebar when content changes
- refresh() {
- this.scanHeaders();
- }
-
- // Method to set the sidebar title
- setTitle(title) {
- const titleElement = this.querySelector('.side-nav-title');
- if (titleElement) {
- titleElement.textContent = title;
- }
- }
-}
-
-// Register the custom element
-customElements.define('app-sidebar', Sidebar);
-
+class Sidebar extends HTMLElement {
+ constructor() {
+ super();
+ this.navItems = [];
+ }
+
+ connectedCallback() {
+ this.render();
+ this.scanHeaders();
+ this.setupScrollListener();
+ this.highlightActiveSection();
+ }
+
+ scanHeaders() {
+ // Clear existing nav items
+ this.navItems = [];
+
+ // Find all h2, h3, and h4 elements with IDs in the content area
+ const contentWrapper = document.querySelector('.content-wrapper');
+ if (!contentWrapper) return;
+
+ const headers = contentWrapper.querySelectorAll('h2[id], h3[id], h4[id]');
+
+ headers.forEach(header => {
+ const id = header.getAttribute('id');
+ const text = header.textContent.trim();
+ const level = header.tagName.toLowerCase();
+
+ this.navItems.push({
+ id,
+ text,
+ level,
+ element: header
+ });
+ });
+
+ this.renderNavigation();
+ }
+
+ renderNavigation() {
+ const ul = this.querySelector('ul');
+ if (!ul) return;
+
+ // Clear existing content
+ ul.innerHTML = '';
+
+ let currentH2Li = null;
+ let currentH3Li = null;
+
+ this.navItems.forEach(item => {
+ if (item.level === 'h2') {
+ // Create h2 item
+ const li = document.createElement('li');
+ const a = document.createElement('a');
+ a.href = `#${item.id}`;
+ a.className = 'side-nav-h2';
+ a.textContent = item.text;
+ a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
+
+ li.appendChild(a);
+ ul.appendChild(li);
+ currentH2Li = li;
+ currentH3Li = null;
+ } else if (item.level === 'h3' && currentH2Li) {
+ // Create h3 item under current h2
+ let subUl = currentH2Li.querySelector('ul');
+ if (!subUl) {
+ subUl = document.createElement('ul');
+ currentH2Li.appendChild(subUl);
+ }
+
+ const li = document.createElement('li');
+ const a = document.createElement('a');
+ a.href = `#${item.id}`;
+ a.className = 'side-nav-h3';
+ a.textContent = item.text;
+ a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
+
+ li.appendChild(a);
+ subUl.appendChild(li);
+ currentH3Li = li;
+ } else if (item.level === 'h4' && currentH3Li) {
+ // Create h4 item under current h3
+ let subUl = currentH3Li.querySelector('ul');
+ if (!subUl) {
+ subUl = document.createElement('ul');
+ currentH3Li.appendChild(subUl);
+ }
+
+ const li = document.createElement('li');
+ const a = document.createElement('a');
+ a.href = `#${item.id}`;
+ a.className = 'side-nav-h4';
+ a.textContent = item.text;
+ a.addEventListener('click', (e) => this.handleNavClick(e, item.id));
+
+ li.appendChild(a);
+ subUl.appendChild(li);
+ }
+ });
+ }
+
+ handleNavClick(e, targetId) {
+ e.preventDefault();
+
+ // Remove active class from all links
+ this.querySelectorAll('a').forEach(link => {
+ link.classList.remove('active');
+ });
+
+ // Add active class to clicked link
+ e.target.classList.add('active');
+
+ // Smooth scroll to target
+ const targetElement = document.getElementById(targetId);
+ if (targetElement) {
+ targetElement.scrollIntoView({
+ behavior: 'smooth',
+ block: 'start'
+ });
+ }
+ }
+
+ setupScrollListener() {
+ let ticking = false;
+
+ const handleScroll = () => {
+ if (!ticking) {
+ requestAnimationFrame(() => {
+ this.highlightActiveSection();
+ ticking = false;
+ });
+ ticking = true;
+ }
+ };
+
+ window.addEventListener('scroll', handleScroll);
+ }
+
+ highlightActiveSection() {
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
+ const offset = 100; // Offset for highlighting
+
+ let activeId = '';
+
+ // Find the currently visible section
+ this.navItems.forEach(item => {
+ const element = item.element;
+ const rect = element.getBoundingClientRect();
+ const elementTop = rect.top + scrollTop;
+
+ if (elementTop <= scrollTop + offset) {
+ activeId = item.id;
+ }
+ });
+
+ // Update active state
+ this.querySelectorAll('a').forEach(link => {
+ link.classList.remove('active');
+ });
+
+ if (activeId !== nil && activeId !== '') {
+ const activeLink = this.querySelector(`a[href="#${activeId}"]`);
+ if (activeLink) {
+ activeLink.classList.add('active');
+ }
+ }
+ }
+
+ render() {
+ this.innerHTML = `
+
+ `;
+ }
+
+ // Method to refresh the sidebar when content changes
+ refresh() {
+ this.scanHeaders();
+ }
+
+ // Method to set the sidebar title
+ setTitle(title) {
+ const titleElement = this.querySelector('.side-nav-title');
+ if (titleElement) {
+ titleElement.textContent = title;
+ }
+ }
+}
+
+// Register the custom element
+customElements.define('app-sidebar', Sidebar);
+
export default Sidebar;
\ No newline at end of file
diff --git a/.docs/web/js/prism.js b/.docs/web/js/prism.js
index 78f88d1..0be31c9 100644
--- a/.docs/web/js/prism.js
+++ b/.docs/web/js/prism.js
@@ -1,10 +1,10 @@
-/* Prism.js core and Lua support (minified for brevity, real project should use CDN or npm for updates) */
-// This is a placeholder. In production, use the official Prism.js CDN or npm package for updates and more languages.
-// For demo purposes, you can use the CDN below in your HTML:
-//
-//
-//
-/* PrismJS 1.30.0
-https://prismjs.com/download#themes=prism-okaidia&languages=lua */
-var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=g.reach);A+=w.value.length,w=w.next){var P=w.value;if(n.length>e.length)return;if(!(P instanceof i)){var E,S=1;if(y){if(!(E=l(b,A,e,m))||E.index>=e.length)break;var L=E.index,O=E.index+E[0].length,C=A;for(C+=w.value.length;L>=C;)C+=(w=w.next).value.length;if(A=C-=w.value.length,w.value instanceof i)continue;for(var j=w;j!==n.tail&&(Cg.reach&&(g.reach=W);var I=w.prev;if(_&&(I=u(n,I,_),A+=_.length),c(n,I,S),w=u(n,I,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),S>1){var T={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,T),g&&T.reach>g.reach&&(g.reach=T.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a"+i.content+""+i.tag+">"},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
-Prism.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[^z]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+(?:\.[a-f\d]*)?(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|(?:\.\d*)?(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,function:/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/};
+/* Prism.js core and Lua support (minified for brevity, real project should use CDN or npm for updates) */
+// This is a placeholder. In production, use the official Prism.js CDN or npm package for updates and more languages.
+// For demo purposes, you can use the CDN below in your HTML:
+//
+//
+//
+/* PrismJS 1.30.0
+https://prismjs.com/download#themes=prism-okaidia&languages=lua */
+var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=g.reach);A+=w.value.length,w=w.next){var P=w.value;if(n.length>e.length)return;if(!(P instanceof i)){var E,S=1;if(y){if(!(E=l(b,A,e,m))||E.index>=e.length)break;var L=E.index,O=E.index+E[0].length,C=A;for(C+=w.value.length;L>=C;)C+=(w=w.next).value.length;if(A=C-=w.value.length,w.value instanceof i)continue;for(var j=w;j!==n.tail&&(Cg.reach&&(g.reach=W);var I=w.prev;if(_&&(I=u(n,I,_),A+=_.length),c(n,I,S),w=u(n,I,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),S>1){var T={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,T),g&&T.reach>g.reach&&(g.reach=T.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a"+i.content+""+i.tag+">"},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
+Prism.languages.lua={comment:/^#!.+|--(?:\[(=*)\[[\s\S]*?\]\1\]|.*)/m,string:{pattern:/(["'])(?:(?!\1)[^\\\r\n]|\\z(?:\r\n|\s)|\\(?:\r\n|[^z]))*\1|\[(=*)\[[\s\S]*?\]\2\]/,greedy:!0},number:/\b0x[a-f\d]+(?:\.[a-f\d]*)?(?:p[+-]?\d+)?\b|\b\d+(?:\.\B|(?:\.\d*)?(?:e[+-]?\d+)?\b)|\B\.\d+(?:e[+-]?\d+)?\b/i,keyword:/\b(?:and|break|do|else|elseif|end|false|for|function|goto|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,function:/(?!\d)\w+(?=\s*(?:[({]))/,operator:[/[-+*%^&|#]|\/\/?|<[<=]?|>[>=]?|[=~]=?/,{pattern:/(^|[^.])\.\.(?!\.)/,lookbehind:!0}],punctuation:/[\[\](){},;]|\.+|:+/};
diff --git a/.docs/web/js/site.js b/.docs/web/js/site.js
index 0375401..035a762 100644
--- a/.docs/web/js/site.js
+++ b/.docs/web/js/site.js
@@ -1,91 +1,91 @@
-
-document.addEventListener('DOMContentLoaded', function() {
- const themeToggle = document.getElementById('theme-toggle');
- const sunIcon = document.getElementById('sun-icon');
- const moonIcon = document.getElementById('moon-icon');
- if (!themeToggle || !sunIcon || !moonIcon) return;
-
- function setTheme(theme) {
- document.documentElement.setAttribute('data-theme', theme);
- localStorage.setItem('theme', theme);
- sunIcon.style.display = theme === 'light' ? 'block' : 'none';
- moonIcon.style.display = theme === 'light' ? 'none' : 'block';
- }
-
- themeToggle.addEventListener('click', function() {
- const current = document.documentElement.getAttribute('data-theme') || 'dark';
- setTheme(current === 'dark' ? 'light' : 'dark');
- });
-
- // Initialize
- const saved = localStorage.getItem('theme') || 'dark';
- setTheme(saved);
-
- // Set side-nav-title to the first h1's text
- var h1 = document.querySelector('.content-wrapper h1');
- var sideNavTitle = document.querySelector('.side-nav-title');
- if (h1 && sideNavTitle) {
- sideNavTitle.textContent = h1.textContent;
- }
-});
-
-// Highlight sidenav link on scroll (shared for all pages)
-function setupSideNavHighlight() {
- const navLinks = document.querySelectorAll('.side-nav a');
- if (!navLinks.length) return;
- const sections = Array.from(navLinks).map(link => {
- const id = link.getAttribute('href').replace('#', '');
- return document.getElementById(id);
- });
- function getHeaderOffset() {
- const header = document.querySelector('header');
- return header ? header.offsetHeight : 0;
- }
- // Custom scroll on nav click
- navLinks.forEach((link, i) => {
- link.addEventListener('click', function(e) {
- const section = sections[i];
- if (section) {
- e.preventDefault();
- const headerOffset = getHeaderOffset();
- const targetY = window.innerHeight * 0.10;
- const sectionTop = section.getBoundingClientRect().top + window.scrollY;
- const scrollTo = sectionTop - headerOffset - targetY;
- window.scrollTo({ top: scrollTo, behavior: 'smooth' });
- }
- });
- });
- function onScroll() {
- const headerOffset = getHeaderOffset();
- const targetY = window.innerHeight * 0.1; // 30% from the top
- let closestIdx = 0;
- let minDist = Infinity;
- for (let i = 0; i < sections.length; i++) {
- const section = sections[i];
- if (section) {
- const dist = Math.abs(section.getBoundingClientRect().top - headerOffset - targetY);
- if (dist < minDist) {
- minDist = dist;
- closestIdx = i;
- }
- }
- }
- navLinks.forEach((link, i) => {
- if (i === closestIdx) {
- link.classList.add('active');
- } else {
- link.classList.remove('active');
- }
- });
- }
- window.addEventListener('scroll', onScroll, { passive: true });
- window.addEventListener('resize', onScroll);
- onScroll(); // Initial call
-}
-
-// Run on DOMContentLoaded
-if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', setupSideNavHighlight);
-} else {
- setupSideNavHighlight();
+
+document.addEventListener('DOMContentLoaded', function() {
+ const themeToggle = document.getElementById('theme-toggle');
+ const sunIcon = document.getElementById('sun-icon');
+ const moonIcon = document.getElementById('moon-icon');
+ if (!themeToggle || !sunIcon || !moonIcon) return;
+
+ function setTheme(theme) {
+ document.documentElement.setAttribute('data-theme', theme);
+ localStorage.setItem('theme', theme);
+ sunIcon.style.display = theme === 'light' ? 'block' : 'none';
+ moonIcon.style.display = theme === 'light' ? 'none' : 'block';
+ }
+
+ themeToggle.addEventListener('click', function() {
+ const current = document.documentElement.getAttribute('data-theme') || 'dark';
+ setTheme(current === 'dark' ? 'light' : 'dark');
+ });
+
+ // Initialize
+ const saved = localStorage.getItem('theme') || 'dark';
+ setTheme(saved);
+
+ // Set side-nav-title to the first h1's text
+ var h1 = document.querySelector('.content-wrapper h1');
+ var sideNavTitle = document.querySelector('.side-nav-title');
+ if (h1 && sideNavTitle) {
+ sideNavTitle.textContent = h1.textContent;
+ }
+});
+
+// Highlight sidenav link on scroll (shared for all pages)
+function setupSideNavHighlight() {
+ const navLinks = document.querySelectorAll('.side-nav a');
+ if (!navLinks.length) return;
+ const sections = Array.from(navLinks).map(link => {
+ const id = link.getAttribute('href').replace('#', '');
+ return document.getElementById(id);
+ });
+ function getHeaderOffset() {
+ const header = document.querySelector('header');
+ return header ? header.offsetHeight : 0;
+ }
+ // Custom scroll on nav click
+ navLinks.forEach((link, i) => {
+ link.addEventListener('click', function(e) {
+ const section = sections[i];
+ if (section) {
+ e.preventDefault();
+ const headerOffset = getHeaderOffset();
+ const targetY = window.innerHeight * 0.10;
+ const sectionTop = section.getBoundingClientRect().top + window.scrollY;
+ const scrollTo = sectionTop - headerOffset - targetY;
+ window.scrollTo({ top: scrollTo, behavior: 'smooth' });
+ }
+ });
+ });
+ function onScroll() {
+ const headerOffset = getHeaderOffset();
+ const targetY = window.innerHeight * 0.1; // 30% from the top
+ let closestIdx = 0;
+ let minDist = Infinity;
+ for (let i = 0; i < sections.length; i++) {
+ const section = sections[i];
+ if (section) {
+ const dist = Math.abs(section.getBoundingClientRect().top - headerOffset - targetY);
+ if (dist < minDist) {
+ minDist = dist;
+ closestIdx = i;
+ }
+ }
+ }
+ navLinks.forEach((link, i) => {
+ if (i === closestIdx) {
+ link.classList.add('active');
+ } else {
+ link.classList.remove('active');
+ }
+ });
+ }
+ window.addEventListener('scroll', onScroll, { passive: true });
+ window.addEventListener('resize', onScroll);
+ onScroll(); // Initial call
+}
+
+// Run on DOMContentLoaded
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', setupSideNavHighlight);
+} else {
+ setupSideNavHighlight();
}
\ No newline at end of file
diff --git a/.docs/web/pages/about_us.html b/.docs/web/pages/about_us.html
index 298cd7b..afd97cf 100644
--- a/.docs/web/pages/about_us.html
+++ b/.docs/web/pages/about_us.html
@@ -37,10 +37,8 @@
Even though, at the time of writing this, I've written every single line of code myself, I could not have done it without the help of these members.
Therefore it's something WE created.
- Our goal was very simple, make it possible to make big dynamic missions, without having to either give away all controll or having to get knee deep into scripting.
- We struck a balance.
-
-
+ Our goal was very simple, make it possible to make big dynamic missions, without having to either give away all control or having to get knee deep into scripting.
+ We struck a balance.
diff --git a/.docs/web/pages/first-start.html b/.docs/web/pages/first-start.html
index 4c68496..917e450 100644
--- a/.docs/web/pages/first-start.html
+++ b/.docs/web/pages/first-start.html
@@ -90,13 +90,13 @@
Missions are also defined by trigger zones.
They'll be picked up by Spearhead when named according to the naming convention:
MISSION_[Type]_[FreeForm]
- Where [Type] is the type of mission.
+ Where [Type] is the type of mission. See all
CAS
- Personally CAS is one of our favorite mission types.
+ Personally CAS is one of my favorite mission types.
Mostly because it's easy to set up and creates a truly immersive experience.
diff --git a/.docs/web/pages/reference.html b/.docs/web/pages/reference.html
index 01e2bf8..34a1228 100644
--- a/.docs/web/pages/reference.html
+++ b/.docs/web/pages/reference.html
@@ -80,11 +80,22 @@
Example: MISSION_DEAD_BYRON
- Missions are completable objectives with specific types, such as DEAD, BAI, STRIKE, or SAM.
+ Missions are completable objectives with specific types.
Randomized missions can be defined using the format: RANDOMMISSION_[Type]_[Name]_[Index] .
+
+ Valid Types:
+
+ SAM
+ DEAD
+ BAI
+ CAS
+ STRIKE
+
+
+
CAP Routes
Format: CAPROUTE_[routeID]_[Name]
diff --git a/.docs/web/pages/spearheadapi.html b/.docs/web/pages/spearheadapi.html
index 3965b3f..3ce88c9 100644
--- a/.docs/web/pages/spearheadapi.html
+++ b/.docs/web/pages/spearheadapi.html
@@ -1,60 +1,60 @@
-
-
-
-
-
-
- Spearhead API
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Spearhead API
-
-
-
NOTE: The Spearhead.API space is only released in the Beta branch at the moment.
-
-
-
Introduction
-
- The Spearhead.API space is specifically created to make sure mission makers can interact with the framework.
-
-
- Simply alter logic, get the current state in Spearhead, and give the whole Mission Editor more control.
-
-
- For example, late activate the entire framework by calling Spearhead.API.Stages.changeStage (1 ) later or on demand and setting the starting config stage to -1 in the Spearhead configuration file.
-
-
-
Stages
-
- @@API_CODE@@
-
-
-
-
-
- © 2025 Spearhead Project
-
-
-
-
+
+
+
+
+
+
+ Spearhead API
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Spearhead API
+
+
+
NOTE: The Spearhead.API space is only released in the Beta branch at the moment.
+
+
+
Introduction
+
+ The Spearhead.API space is specifically created to make sure mission makers can interact with the framework.
+
+
+ Simply alter logic, get the current state in Spearhead, and give the whole Mission Editor more control.
+
+
+ For example, late activate the entire framework by calling Spearhead.API.Stages.changeStage (1 ) later or on demand and setting the starting config stage to -1 in the Spearhead configuration file.
+
+
+
Stages
+
+ @@API_CODE@@
+
+
+
+
+
+ © 2025 Spearhead Project
+
+
+
+
\ No newline at end of file
diff --git a/.docs/web/pages/tutorials.html b/.docs/web/pages/tutorials.html
index 218cbbb..7ae7177 100644
--- a/.docs/web/pages/tutorials.html
+++ b/.docs/web/pages/tutorials.html
@@ -41,7 +41,7 @@
Download the latest version of Spearhead. You can choose which version you feel comfortable with.
Versions that end in -rc are not stable. Versions that do not have the "release candidate" (rc) tag are.
- See All releases here
+ See All releases here
diff --git a/.docs/web/style/prism.css b/.docs/web/style/prism.css
index f3b8295..6d98055 100644
--- a/.docs/web/style/prism.css
+++ b/.docs/web/style/prism.css
@@ -1,3 +1,3 @@
-/* PrismJS 1.30.0
-https://prismjs.com/download#themes=prism-okaidia&languages=lua */
-code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
+/* PrismJS 1.30.0
+https://prismjs.com/download#themes=prism-okaidia&languages=lua */
+code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}