merged main

This commit is contained in:
2025-04-25 14:49:54 +02:00
14 changed files with 1518 additions and 634 deletions
-249
View File
@@ -1,249 +0,0 @@
# Spearhead
> **_Spearhead last updated at:_** ##!lastupdatetime!##
## Get Started
This guide is to get you started building your first Spearhead mission. <br/>
Spearhead was created to enable the mission maker to worry as little about the running, timing and scripting and most about the setting and looks and feel of the mission. <br/>
In the example we'll show how you can create a simple island hopping mission
## Include Script
Firstly include the script.
<a download="spearhead.lua" href="./spearhead.lua" target="_blank" rel="noopener noreferrer">Download Script</a>
<br/>Or if you want to use the latest beta version:
<a download="spearhead.lua" href="./beta/spearhead.lua" target="_blank" rel="noopener noreferrer">Download Beta Script</a>
Then run the script in the mission. <br/>
Please do exactly as it's done below. <br/>
![Spearhead install](./img/script_install.png)
> Spearhead does not require any dependencies (eg. MIST or MOOSE). Compatibility with other frameworks is not tested at this time, so cannot be guaranteed, but there should be no conflicts if they are not controlling the same units.
## Stages
So first of all think about the stages. Read the details about them here: [Stages](./Reference.html#stage)<br/>
These are logically ordered zones that will activate one by one based on the mission status in them. <br/>
There is a little more to it, but you'll find out. <br/>
Stages need to be named according to the convention: `MISSIONSTAGE_<OrderNumber>_<FreeForm>` <br/>
The first stage will be called `MISSIONSTAGE_1` or `MISSIONSTAGE_1_EAST` for example. <br/>
For this mission we started with the three stages: `MISSIONSTAGE_1_GROUND`, `MISSIONSTAGE_1_WATER` and `MISSIONSTAGE_2_AIRBASE` as you see in the image. <br/>
<img src="img/starting_stages.png" alt="drawing" width="1000"/>
In this example `_GROUND` and `_WATER` stages will be actived at the start of the mission. <br/>
`_AIRBASE` will however not be activated since the order number is 2 <br/>
`MISSIONSTAGE_3` will be used as part of this example as well. It's a stage even further away. <br/>
## Setting up CAP
If you don't want to use the CAP managers withing Spearhead you can skip this and continue to [setting up the missions](#setting-up-the-missions). <br/>
However CAP is one of the painpoints in a lot of missions and setting up a dynamic feeling airspace can be quite the challenge. <br/>
With the CAP managers we've tried to make this a lot easier. <br/>
A CAP group needs to follow the following naming convention: `CAP_<A|B><CONFIG>_<Free Form>`
For details on config read this: [CAP Group Config](./Reference.html#cap-group-config)
For now I set up 3 groups with the following names. `CAP_A[1]1_Rota1` , `CAP_A[1]1_Rota1-1` , `CAP_B[1]1_Rota1` <br/>
The first two are marked with `A` and will therefore be primary CAP units. They will be scheduled and make up for the total count. <br/>
Meaning that for this airbase there is 2 CAP units max at a time flying out. <br/>
In this case all groups have `[1]1` in the name, (This would be the same as `[1]A`) which means that when stage 1 is active the groups will activate and fly out to stage 1.
I also set up a few groups further back. One example: `CAP_A[1-3]3_Group1`. This group will protect zone 3 when zones 1 through 3 are active.
CAP units fly out, fly their CAP zone for x amount of minutes and will then RTB. <br/>
Before they actually RTB an event is triggered 10 minutes before the actual RTB task. This event will trigger a backup unit to startup and fly out to take over. <br/>
Best is to test it out and see for yourself. <br/>
### Creating CAP routes
Creating cap routes is not needed per se, but with a multi-stage stage (we have 2 stages with `_1_`) it is recommended. <br/>
Similarly with huge stages. <br/>
If there is multiple zones is will "round-robin" over them. <br/>
If no CAP route is present the unit will fly a route generated differently per zone: <br/>
`quad zone` => race-track between the corner closest to the origin airbase to the center point of the zone <br/>
`circle zone` => race-track between the closest point on circle to the origin airbase to the center <br/>
If you want to create you own CAP Routes you can! <br/>
For this example I created 2 CAP routes inside of the 2 `_1_` stages. <br/>
As you can see below there's a nice feature you can exploit. As long as the `X` of the zone is inside of the the `CAPROUTE` will be used for that stage!
![CAP Routes Image](./img/cap_routes.png)
Now all you need to do is start the mission (single player works just fine) and see the AI fly around. <br/>
Tip: Speeding up the simulation speed to 10x or 15x can help you see how the AI will fly and how it will behave. <br/>
Well, nice, we're don setting up the initial CAP effort. <br/>
If you want to change values for the CAP routes please read about how to configure it here: [Cap Config](./Reference.html#cap-config)
> **_NOTE:_** Stages that have CAP units active on their airbases will have all Airbase units and `SAM` missions activated. This is to give the possibility to protect the enemy CAP units
## Setting up the Missions
Now the part where you as a mission maker can really get into the nitty gritty. <br/>
Missions are managed and monitored by Spearhead. <br/>
Statics, groups and single units all alike. <br/>
> **_NOTE:_** While static are the same as groups in this context, they are not within DCS, please refrain from using static groups. A `static` in DCS has a 1:1 relation for group:unit
For this example I'll set up two missions. The first one is `DEAD` mission and will consist of an SA-2 site with an additional "control center".
#### Mission 1: DEAD
As you can see on the left image the template of the SA-2 was placed. Then dragged around to only fce south. <br/>
An additional track radar and search radar was added and all launchers were surrounded by sandbags. <br/>
On top of this there was a sort of control center added with walls, vehicles and some tents.
On the right you can see the end result. Which is a very nice SA-2 site with static units spawned. <br/>
<div style="display: flex">
<div style = "flex: 50%">
<img src="./img/sa2_mission_editor.png"/>
</div>
<div style = "flex: 50%">
<img src="./img/sa2_result.png"/>
</div>
</div>
Important to note. It's all inside the triggerzone `MISSION_DEAD_BYRON`. Which means it's a `MISSION` of type `DEAD` and with name `BYRON`. <br/>
At the start Spearhead will detect the triggerzone, take all units and despawn them and only spawn when needed for better performance. <br/>
The current list of mission types are:
```
DEAD
BAI
STRIKE
SAM -- Special type that will also activate on "pre-activated stages"
```
Each type has some additional completion logic to it. <br/>
`DEAD` and `SAM` missions will be marked complete when all air defences are destroyed. This includes Tracking Radars, Self tracking launchers and AAA guns if they are inside the zone. <br/>
If you want to add the Search radar or another random unit like the command tent to the target list you can add a `TGT_` prefix to the unit or group you want destroyed. <br/>
Please be aware that adding `TGT_` to a group will make the entire group a target and therefore each unit needs to be destroyed. <br/>
#### Mission 2: STRIKE
To show the power of `TGT_` targets I'll create a strike mission next.
A nice supply strike mission will do. Add a ship, some containers and some additional units. <br/>
Even some SHORADS to spice the whole thing up. <br/>
In the picture below all units that are selected and who show up as white (they are actually red) have the prefix `TGT_` in front of their name. <br/>
This will make it so the mission will be marked as complete when those units are destroyed. The rest of the units will exist until the entire stage is cleaned up. <br/>
<img src="./img/strike_target.png"/><br/>
## Mission Briefings
So now we've created some missions we also want to add briefings to them. This is pretty easy with Spearhead. <br/>
To do so click on `draw` on the left hand pane in the mission editor. This opens up the drawing tools in the editor. <br/>
On the right click `TextBox` and click somewhere inside the zone to which you want to add the briefing. <br/>
Give the briefing a name (It's not used, but can be nice to use to reference the briefing later) and add the briefing. <br/>
The text box is quite small, but can have a lot of text. Easiest is to edit the text in an editor of choice and paste it into the box afterwards. <br/>
Keep the binding layer to "Author" only. That way it doesn't show up for anyone other than in the mission editor.
See the two images below. The left shows the `Text Box` drawing. The right shows the briefing as shown in the mission.
> **_TIP:_** You can make both the `Color` and `Fill` have a `0` value for `a`. This will make the weird box be invisible. Make sure to add the name of the mission to the text box name to easily find it back.
<div style="display: flex">
<div style = "flex: 50%">
<img src="./img/briefing_me.png"/>
</div>
<div style = "flex: 50%">
<img src="./img/briefing_mission.png"/>
</div>
</div>
## Airbase and Miscelaneous units.
You don't have to place units inside of mission zones only. Misc units and Airbase units are also managed. <br/>
But use these smartly as they can add up very quickly. <br/>
As with the other zones, static units are just as supported as normal groups.
### Airbase units
On top of `SAM` units that get activated when CAP bases are activated in a zone the airbase itself also gets activated. <br/>
All units inside of the ring (about 6600m) around the airfield will be registered as Airbase units. <br/>
### Misc units
All units in a `Stage` zone that are not in an `Airbase` will be registered as miscelaneous units. <br/>
These will be activated the moment a stage gets "Active". (Not pre-activated) <br/>
It can be friendly forces driving around. A FARP with surrounding units and tents.
## Airbases, Farps and Carriers
On top of units and missions, airbases, farps and carriers are big parts of a mission.
### Airbases
Airbases are very important in a flying simulator. Not less so in missions. <br/>
Spearhead will be able to manage Airbases for you by activating/deactivating and changing it's coalition while stages are completed. <br/>
Ofcourse you don't want all bases to be flipped. So the behaviour is based on the starting coalition. <br/>
Neutral &emsp;=> Will stay neutral the entire mission. <br/>
BLUE &emsp;&emsp; => Will turn RED when the stage is red and will turn BLUE when captured <br/>
RED &emsp;&emsp;&emsp;=> Will stay RED and when the stage is captured it will turn NEUTRAL <br/>
#### Airbase Units
Units on these airbases are also managed. This gives a very nice opportunity to create dynamic airbases that have a true RED/BLUE feeling. <br/>
For this example we've setup Kutaisi as a "capturable" Airbase. See the image below (left)<br/>
As you can see there's a mix and match of RED and BLUE units. Luckily the framework makes sure those cannot be spawned at the same time. <br/>
On the image on the right you can see the setup of a little loading/unloading ramp. The Neutral objects will be spawned at the start and will be untouched. <br/>
On the two images below that you can see the before and after of that loading doc after the stage was taken. <br/>
Of course all other blue units will also be spawned. <br/>
This way you can have a blue SAM site, EWR, some blue static aircraft scattered around and the correct refueling and rearming trucks. <br/>
This hopefully will make the Airbases feel less desolate on longer campaigns. <br/>
<div style="display: flex">
<div style = "flex: 50%">
<img src="./img/kutaisi_me.png"/>
</div>
<div style = "flex: 50%">
<img src="./img/kutaisi_loading_dock.png"/>
</div>
</div>
<div style="display: flex">
<div style = "flex: 50%">
<img src="./img/kutaisi_dock_before.png"/>
</div>
<div style = "flex: 50%">
<img src="./img/kutaisi_dock_after.png"/>
</div>
</div>
### Carriers
Aircraft carriers and fleets are very nice, but what use have they if they won't move along with the front line? <br/>
For a carrier fleet to be managed it needs to abide to the name `CARRIERGROUP_<name>_<freeform>` <br/>
For example, we have a single carrier here with the groupname: `CARRIERGROUP_ALPHA_fleet` <br/>
To let the framework know where you want the carrier to be at which stages of the mission you can create `CARRIERROUTE_<name>_[<number>-<number>]_<freeform>` zones. <br/>
In the image below we have 2 zones. `CARRIERROUTE_ALPHA_[1-2]_ROUTE` and `CARRIERROUTE_ALPHA_[3-4]_ROUTE`. <br/>
This tells the framework where carriergroup `ALPHA` should go so you can have multiple smaller subfleets. <br/>
![carrierroutes](img/carrierroutes.png)
### Farps
Farp logic is in the works, but still needs some refinement.
-77
View File
@@ -1,77 +0,0 @@
# Spearhead Persistence
> **_NOTE:_** Persistence is only released in the Beta branch at the moment.
Spearhead comes with a custom Persistence option. <br/>
It will even save burned out vehicles to give players a consistent battlefield even after the restart. <br/>
Most is pretty straight forward, however, some zones are somewhat special. <br/>
Underneath you'll see all special zones listed.
## Settings
To see the full config check: [Reference](./Reference.html#Configuration)
## Feedback
Since this feature is still very much in development, please let any issues know as soon as possible and as consice as possible so a fix can be made quickly.
Currently implemented is local file storage. <br/>
If enough interest is expressed cloud based persistence would be possible. <br/>
```lua
... Rest of config
Persistence = {
--- io and lfs cannot be sanitized in the MissionScripting.lua
--- enables or disables the persistence logic in spearhead
enabled = false,
--- sets the directory where the persistence file is stored
--- if nil then lfs.writedir() will be used.
--- which will
directory = nil ,
--- the filename of the persistence file. Should end with .json for convention, but any text extension should do.
fileName = "Spearhead_Persistence.json"
}
... Rest of config
```
## Basic behavior
While playing the mission Spearhead is keeping track of all units killed. <br/>
These units are stored in memory internally and written to file. <br/>
This happens every 2 minutes AND during "onMissionStop" event to make sure the mission is as up to date as possible without having to call IO methods on each event.<br/>
## Misc units
Miscelaneous units will follow basic behaviour. <br/>
These are units that are part of a stage, but are not in a mission or airbase. <br/>
These units will be replaced by a static "DEAD" unit after a mission restart at the location it was killed. <br/>
Due to blue units spawning afterwards it's generally best to not have these units move through or over areas where BLUESAMS and Airbase units will spawn after a stage completion.
## Missions
Missions follow the same logic as Misc Units. <br/>
## Blue SAMs
For Blue SAMs, due to placements easily overlapping between red and blue units within a BLUESAM trigger zone red units that overlap with blue units will be deleted.
<br/>
This will ensure that the blue units are placed as needed. <br/>
## Airbases
Airbase units will also be checked for overlap. As the blue units will be spawned after the RED unit. <br/>
Units that were alive when the stage was completed will be removed. Units that died will have corpses spawned. <br/>
## Warehouses
Currently warehouses are not implemented and therefore warehouses are not persisted. <br/>
When supply missions and logistics get implemented warehouses will be persisted as well. <br/>
-233
View File
@@ -1,233 +0,0 @@
# Spearhead Reference
> **_Spearhead last updated at:_** ##!lastupdatetime!##
## For the Story tellers
Spearhead. A framework created for the mission maker. <br/>
For those who do want to create a mission with a story and progress, but do not want to get into scripting. Creating an engaging mission can be an incredible feat. First think of the mission, the submission, the placement, the time. Once the concept is done you'll need to place all the objects into the editor. Not too many, but also not too little. Then comes the scripts to make it feel engaging and organic. The latter is probably the biggest hurdle.
Spearhead is created to try and make this entire process a lot easier.
It keeps track of completed missions, moves the stages forward once all mission are complete. <br/> Manages CAP in an easy to setup way (no scripting required) and gives a lot of possibilities to the mission maker. <br/>
The goal is for the mission maker to focus on the story and the detailed missions, without having to worry about all the triggers and mission management the scripts normally take care off.
## Get Started
This page will give you a detailed overview of all options, moving parts and logic that goes into Spearhead. <br/>
If you however want to go right to the Get Started guide click here: [here](./GetStarted.html#completion) <br/>
You can always come back later here. <br/>
The Get Started guide will not show all details and reasoning. <br/>
## Configuration
Spearhead will always try to be as configurable as possible. <br/>
Underneath you can see all configuration values. Be aware there are nested tables. <br/>
The values are the default values in case no configuration was found. <br/>
You can also choose to programatically overwrite only the parts that you want, but be aware of `nil` references and order of files.
Overwrite the values in your own script (before spearhead runs) or <a download="spearheadConfig.lua" href="./spearheadConfig.lua" target="_blank" rel="noopener noreferrer">Download Config File</a> to edit
```lua
##!config!##
```
## The Spearhead API
> **_NOTE:_** The Spearhead.API space is only release in the Beta branch at the moment.
You can not only use Spearhead, but you can also interact with it via your own scripts.
See all the reference, explanation here: [SpearheadAPI](./SpearheadApi.html)
## All Trigger zone name options:
<details>
<summary>MISSIONSTAGE_</summary>
A mission stage that encapsulates multiple missions, airbases and other objects.
</details>
<details>
<summary>WAITINGSTAGE_</summary>
A stage that functions as a logic delay or timer. <br/>
With this you can add a wait before or in between stages.
Naming Convention: `WAITINGSTAGE_<order>_<amount of seconds>`
Example: `WAITINGSTAGE_2_180`
A waiting stage can be part of the same stage order as other stages. <br/>
This will first activate the DELAYSTAGE and only when the DELAYSTAGE is completed will the other stages be activated. <br/>
This is so you can easily add delays later in your mission development, without havint to rename all subsequent stages.
</details>
<details>
<summary>MISSION_</summary>
</details>
<details>
<summary>BLUESAM_</summary>
</details>
<details>
<summary>CAPROUTE_</summary>
</details>
<details>
<summary>CAPZONE_</summary>
</details>
## Stage
A stage is a logical part of a mission. It's isn't anything special per se, but everything revolves around stages in Spearhead. <br/>
Everything is tied to at a stage. <br/>
## Mission
A mission is a completable objective with a state and a continuous check to see if itself is completed. <br/>
The delay between checks is quite big, but it also is checked on unit deaths and other events.
### Placement
The placement of MISSION trigger zones can be anywhere. <br/>
The order of unit detection is `CAP` > `MISSION` > `AIRBASE` > `STAGE` <br/>
This means that if a unit has a name that starts with `"CAP_"` it will not be included in a mission. <br/>
But all other units in a `MISSION` trigger zone will be managed as part of that mission.
Units inside a `MISSION` do not have to stay within the triggerzone. <br/>
They just need to be inside the zone at the start of the mission. <br/>
You can for example let a `BAI` mission drive back and forth between airbases. The `MISSIONZONE` only needs to be around the units that are part of the objective, not the waypoints.
### Naming
`MISSION_<type>_<name>` <br/>
`RANDOMMISSION_<type>_<name>_<index>` (Read RANDOMISATION below)
With: <br/>
`name` = A name that is easy to remember and type. Like a codename. Exmaples: BYRON, PLUKE, etc. <br/>
`type` = any of the below described types. Special types are marked with an *
TIP: You can click on the type to get more details
<details>
<summary>SAM*</summary>
&emsp; SAM Sites are managed a little different. SAM Sites can be used to guide players and to protect airfields. <br/>
&emsp; In the future when deepstrike missions might come into scope these SAM sites will also be more important. <br/>
&emsp; SAM sites will be activated when a zone is "Pre-Active". <br/>
&emsp; A stage is "Pre-Active" when there is a CAP base active, or there is other things to do that would need the SAM site to be live (OCA, DEEPSTRIKE, EXTRACTION \<= all feature development)<br/>
&emsp; If you want a SAM site to become active ONLY when the stage is fully active, then `DEAD` is the type for you!
&emsp; <u>Completion logic</u> <br/>
&emsp; TODO: documentation: Completion logic
</details>
<details>
<summary>DEAD</summary>
&emsp; DEAD missions will be spawned on activation of the stage. <br/>
&emsp; ALL DEAD missions will be activated right at the start of a stage. <br/>
&emsp; This might be against the "randomisation" feel, but it is to make sure mission don't get activated randomly and players get ambushed by a random spawn. <br/>
&emsp; <u>Completion logic</u> <br/>
&emsp; TODO: documentation: Completion logic
</details>
<details>
<summary>BAI</summary>
</details>
<details>
<summary>STRIKE</summary>
&emsp; STRIKE missions will be activated randomly until all of them are completed. <br/>
&emsp; A strike mission can be placed anywhere, even on airbases
&emsp; <u>Completion logic</u> <br/>
&emsp; TODO: documentation: Completion logic
</details>
### TGT targets
There is 2 ways a mission can complete which depends on the precense
### Randomisation
You can randomize missions. <br/>
Spearhead will pick up all mission zones that start with `"RANDOMMISSION_"` <br/>
Then it will combine each `RANDOMMISSION` in a zone with the same `<name>` and pick a random one. <br/>
It will always pick 1 and only 1.
This means you have some options for randomisation. <br/>
For example, if you have 1 missionzone with name `RANDOMMISSION_SAM_PLUKE_1` that is filled with an SA-2 and another zone with `RANDOMMISSION_SAM_PLUKE_2` filled with an SA-3 then some runs of the mission it will spawn an SA-3 and sometimes spawn an SA-3. (works for any mission type)
What you can also do is add empty `RANDOMMISSION_` zones next to the filled `RANDOMMISSION_` zone.
For example. You have a `RANDOMMISSION_DEAD_BYRON_1` filled with an SA-19 driving around and 2 more `RANDOMMISSION_DEAD_BYRON_<2 & 3>` zones then it will have a 33% chance of being spawned.
If a zone is empty it will not be briefed, activated or count towards completion of the `STAGE`
### CAP
#### CAP Config:
--[[
TODO: CAP CONFIG
]]
Naming: CAP\_\<"A" | B"\>\<Config\>_\<Free form name\>
##### CAP Group Config:
```
1 at x: [<activeStage>]<capStage>
n and n at x: [<activeStage>,<activeStage>]<capStage>
n till n at x: [<activeStage>-<activeStage>]<capStage>
n till n and n at x: [<activeStage>-<activeStage>,<activeStage>]<capStage>
n till n at Active: [<activeStage>-<activeStage>]A
divider: |
examples:
CAP_A[1-4,6]7|[5,7]8_SomeName => Will fly CAP at stage 7 when stages 1 through 4 and 6 are active and will fly CAP at 8 when 5 and 7 are active
CAP_A[2-5]5|[6]6_SomeName => Will fly CAP at stage 5 when stages 2 through 5 active and will fly CAP at 6 when 6 is active
CAP_A[1-5]A|[6]7_SomeName => Will fly CAP at the ACTIVE stage if Stages 1-5 are active. Basically following the active stages. Then when 6 is active it will fly in 7
CAP_B[1-5]A|[6]7_SomeName => Will fly BACKUP CAP for the active zones 1 through 5 and back up for 7 when 6 is active.
```
#### How many? And how to add backups?
To fascilitate a nice flow of the mission and also make sure it doesn't oversaturate the zones with aircraft the script works with a Active/Backup system in the naming. <br/>
This really doesn't mean much per se once the mission runs, but most importantly is that the A units define how many groups there should be max in a zone at a time. <br/>
The B units will simply be used to fill that amount if the A units can't due to RTB, Death, Rearming etc. <br/>
#### Example
Take the units:
```
CAP_A[1-5]A_SomeName1
CAP_A[1-5]A_SomeName2
CAP_B[1-3,5]A_SomeName
```
`CAP_A...` units are primary units where the `CAP_B...` units are the backups. <br/>
In this case the CAP manager sees that for stages 1 through 5 this configuration requires 2 groups in the active zone. <br/>
If one of those 2 groups dies or is going back to base the B group will be used to top up the CAP units at that zone. <br/>
After scheduling the B units the A units that are back at base ready on the ramp will also not be scheduled until the CAP units that are active in the zone (inlcuding B units) drop below the required CAP unit (of 2 in this example)
In this example there is no Backup unit for zone 4. This might quiet down the CAP a little as the Active groups will have to rearm and refuel without there being any backup.
#### What the cap manager does:
- Spawn aircraft on the ramp (or despawn when they are not needed anymore for culling)
- Send out aircraft based on where they are supposed to be
- Send Aircraft RTB after X time. <br/>
RTB in this sense means back to its base of origin. Not the closest friendly base like DCS does.
- Simulates Rearming and then sending them out when needed.
- Delays aircraft for X amount of time before spawning and rearming after a groups demise.
- Aircraft are spawned on the ramp so OCA does have effect. (Be sure to also take a look at the Airbase and SAM spawning for defences)
#### Future Ideas
- Aircraft rearm hubs with finite spawns on other airbases that get replenished by aircraft flying in.
-37
View File
@@ -1,37 +0,0 @@
# Spearhead.API
> **_NOTE:_** The Spearhead.API space is only release in the Beta branch at the moment.
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 ME more control.
eg. 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
```lua
---Changes the active stage of spearhead.
--- All other stages will change based on the normal logic. (CAP, BLUE etc.)
---@param stageNumber number the stage number you want changed
---@return boolean success indicator of success
---@return string message error message
Spearhead.API.Stages.changeStage = function(stageNumber) end
---Returns the current stange number
---Returns nil when the stagenumber was not set before ever, which means Spearhead was not started.
---@return number | nil
Spearhead.API.Stages.getCurrentStage = function() end
---returns whether a stage (by index) is complete.
---@param stageNumber number
---@return boolean | nil
---@return string
Spearhead.API.Stages.isStageComplete = function(stageNumber) end
```
+75
View File
@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Spearhead</title>
<link rel="stylesheet" href="style/style.css">
<script src="js/site.js"></script>
</head>
<body>
<header>
<div class="header-box">
<a class="logo" href="index.html">Spearhead</a>
<div class="header-right">
<nav>
<a href="index.html">Home</a>
<a href="pages/tutorials.html">Tutorials</a>
<a href="pages/persistence.html">Persistence</a>
<a href="pages/reference.html">Reference</a>
<a href="pages/spearheadapi.html">API</a>
</nav>
<button id="theme-toggle" class="theme-toggle" title="Toggle light/dark theme">
<svg id="moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M12 11.807A9.002 9.002 0 0 1 10.049 2a9.942 9.942 0 0 0-5.12 2.735c-3.905 3.905-3.905 10.237 0 14.142 3.906 3.906 10.237 3.905 14.143 0a9.946 9.946 0 0 0 2.735-5.119A9.003 9.003 0 0 1 12 11.807z"/>
</svg>
<svg id="sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="display: none;">
<path d="M6.995 12c0 2.761 2.246 5.007 5.007 5.007s5.007-2.246 5.007-5.007-2.246-5.007-5.007-5.007S6.995 9.239 6.995 12zM12 8.993c1.658 0 3.007 1.349 3.007 3.007S13.658 15.007 12 15.007 8.993 13.658 8.993 12 10.342 8.993 12 8.993zM10.998 19H12.998V22H10.998zM10.998 2H12.998V5H10.998zM1.998 11H4.998V13H1.998zM18.998 11H21.998V13H18.998z"/>
<path transform="rotate(-45.017 5.986 18.01)" d="M4.986 17.01H6.986V19.01H4.986z"/>
<path transform="rotate(-45.001 18.008 5.99)" d="M17.008 4.99H19.008V6.99H17.008z"/>
<path transform="rotate(-134.983 5.988 5.99)" d="M4.988 4.99H6.988V6.99H4.988z"/>
<path transform="rotate(134.999 18.008 18.01)" d="M17.008 17.01H19.008V19.01H17.008z"/>
</svg>
</button>
</div>
</div>
</header>
<main>
<div class="reference-container">
<div class="side-nav">
<h4>Quick Links</h4>
<ul>
<li><a href="pages/tutorials.html" class="side-nav-h2">Tutorials</a></li>
<li><a href="pages/persistence.html" class="side-nav-h2">Persistence</a></li>
<li><a href="pages/reference.html" class="side-nav-h2">Reference</a></li>
<li><a href="pages/spearheadapi.html" class="side-nav-h2">API</a></li>
</ul>
</div>
<div class="content-wrapper">
<h1 id="welcome">Welcome to Spearhead!</h1>
<p>Welcome to the story teller friendly mission framework in DCS (at least, that's what we hope to create).</p>
<p>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.</p>
<p id="latest-version">Latest Version: #{VERSION}# created at: #{VERSION_DATE}#</p>
<p id="latest-version">Latest Beta Version: #{BETA_VERSION}# created at: #{BETA_VERSION_DATE}#</p>
<a style="text-decoration: underline;" target="_blank" href="https://github.com/dutchie031/Spearhead/releases">See All releases here</a>
</div>
</div>
</main>
<footer>
<p>&copy; 2025 Spearhead Project</p>
</footer>
</body>
</html>
+22
View File
@@ -0,0 +1,22 @@
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);
});
-38
View File
@@ -1,38 +0,0 @@
<div id="menu">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<div style="position:fixed;
left:80%;
top:80%;
height:15%;
width:15%;
padding:10px;
background-color: #00053B;
border-radius: 8px;">
<div style="margin-bottom: 8px;">
<a href="/Spearhead/Reference.html" style="color: white; font-size: 18px; ">
<i class="bi bi-file-earmark-richtext"></i>
&ensp;Reference
</a>
</div>
<div style="margin-bottom: 8px;">
<a href="/Spearhead/GetStarted.html" style="color: white; font-size: 18px;">
<i class="bi bi-rocket-takeoff"></i>
&ensp;Get Started
</a>
</div>
<div style="margin-bottom: 8px;">
<a href="/Spearhead/Persistence.html" style="color: white; font-size: 18px;">
<i class="bi bi-database-check"></i>
&ensp;Persistence
</a>
</div>
<div style="margin-bottom: 8px;">
<a href="/Spearhead/SpearheadApi.html" style="color: white; font-size: 18px;">
<i class="bi bi-gear"></i>
&ensp;API
</a>
</div>
</div>
</div>
View File
+142
View File
@@ -0,0 +1,142 @@
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Spearhead Persistence</title>
<link rel="stylesheet" href="../style/style.css">
<script src="../js/site.js"></script>
</head>
<body>
<header>
<div class="header-box">
<a class="logo" href="../index.html">Spearhead</a>
<div class="header-right">
<nav>
<a href="../index.html">Home</a>
<a href="../pages/tutorials.html">Tutorials</a>
<a href="../pages/persistence.html">Persistence</a>
<a href="../pages/reference.html">Reference</a>
<a href="../pages/spearheadapi.html">API</a>
</nav>
<button id="theme-toggle" class="theme-toggle" title="Toggle light/dark theme">
<svg id="moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M12 11.807A9.002 9.002 0 0 1 10.049 2a9.942 9.942 0 0 0-5.12 2.735c-3.905 3.905-3.905 10.237 0 14.142 3.906 3.906 10.237 3.905 14.143 0a9.946 9.946 0 0 0 2.735-5.119A9.003 9.003 0 0 1 12 11.807z"/>
</svg>
<svg id="sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="display: none;">
<path d="M6.995 12c0 2.761 2.246 5.007 5.007 5.007s5.007-2.246 5.007-5.007-2.246-5.007-5.007-5.007S6.995 9.239 6.995 12zM12 8.993c1.658 0 3.007 1.349 3.007 3.007S13.658 15.007 12 15.007 8.993 13.658 8.993 12 10.342 8.993 12 8.993zM10.998 19H12.998V22H10.998zM10.998 2H12.998V5H10.998zM1.998 11H4.998V13H1.998zM18.998 11H21.998V13H18.998z"/>
<path transform="rotate(-45.017 5.986 18.01)" d="M4.986 17.01H6.986V19.01H4.986z"/>
<path transform="rotate(-45.001 18.008 5.99)" d="M17.008 4.99H19.008V6.99H17.008z"/>
<path transform="rotate(-134.983 5.988 5.99)" d="M4.988 4.99H6.988V6.99H4.988z"/>
<path transform="rotate(134.999 18.008 18.01)" d="M17.008 17.01H19.008V19.01H17.008z"/>
</svg>
</button>
</div>
</div>
</header>
<main>
<div class="reference-container">
<div class="side-nav">
<h4>Contents</h4>
<ul>
<li><a href="#settings" class="side-nav-h2">Settings</a></li>
<li><a href="#feedback" class="side-nav-h2">Feedback</a></li>
<li><a href="#basic-behavior" class="side-nav-h2">Basic Behavior</a></li>
<li><a href="#misc-units" class="side-nav-h2">Misc Units</a></li>
<li><a href="#missions" class="side-nav-h2">Missions</a></li>
<li><a href="#blue-sams" class="side-nav-h2">Blue SAMs</a></li>
<li><a href="#airbases" class="side-nav-h2">Airbases</a></li>
<li><a href="#warehouses" class="side-nav-h2">Warehouses</a></li>
</ul>
</div>
<div class="content-wrapper">
<h1>Spearhead Persistence</h1>
<p>
Spearhead comes with a custom Persistence option. <br/>
It will even save burned out vehicles to give players a consistent battlefield even after the restart. <br/>
</p>
<p>
Most is pretty straightforward, however, some zones are somewhat special. <br/>
Underneath you'll see all special zones listed.
</p>
<h2 id="settings">Settings</h2>
<p>
To see the full config check: <a href="./Reference.html#Configuration">Reference</a>
</p>
<h2 id="feedback">Feedback</h2>
<p>
Since this feature is still very much in development, please let any issues be known as soon as possible and as concise as possible so a fix can be made quickly. <br/>
Currently implemented is local file storage. <br/>
If enough interest is expressed, cloud-based persistence would be possible. <br/>
</p>
<pre>
<span class="lua-comment">... Rest of config</span>
<span class="lua-variable">Persistence</span> <span class="lua-operator">=</span> {
<span class="lua-comment">--- io and lfs cannot be sanitized in the MissionScripting.lua</span>
<span class="lua-comment">--- enables or disables the persistence logic in spearhead</span>
<span class="lua-variable">enabled</span> <span class="lua-operator">=</span> <span class="lua-keyword">false</span>,
<span class="lua-comment">--- sets the directory where the persistence file is stored
--- if nil then lfs.writedir() will be used.</span>
<span class="lua-variable">directory</span> <span class="lua-operator">=</span> <span class="lua-keyword">nil</span>,
<span class="lua-comment">--- the filename of the persistence file. Should end with .json for convention, but any text extension should do.</span>
<span class="lua-variable">fileName</span> <span class="lua-operator">=</span> <span class="lua-string">"Spearhead_Persistence.json"</span>
}
<span class="lua-comment">... Rest of config</span>
</pre>
<h2 id="basic-behavior">Basic Behavior</h2>
<p>
While playing the mission, Spearhead is keeping track of all units killed. <br/>
These units are stored in memory internally and written to file. <br/>
This happens every 2 minutes AND during the "onMissionStop" event to make sure the mission is as up-to-date as possible without having to call IO methods on each event.<br/>
</p>
<h2 id="misc-units">Misc Units</h2>
<p>
Miscellaneous units will follow basic behavior. <br/>
These are units that are part of a stage but are not in a mission or airbase. <br/>
These units will be replaced by a static "DEAD" unit after a mission restart at the location it was killed. <br/>
Due to blue units spawning afterwards, it's generally best to not have these units move through or over areas where BLUESAMS and Airbase units will spawn after a stage completion.
</p>
<h2 id="missions">Missions</h2>
<p>
Missions follow the same logic as Misc Units. <br/>
</p>
<h2 id="blue-sams">Blue SAMs</h2>
<p>
For Blue SAMs, due to placements easily overlapping between red and blue units within a BLUESAM trigger zone, red units that overlap with blue units will be deleted. <br/>
This will ensure that the blue units are placed as needed. <br/>
</p>
<h2 id="airbases">Airbases</h2>
<p>
Airbase units will also be checked for overlap. As the blue units will be spawned after the RED unit. <br/>
Units that were alive when the stage was completed will be removed. Units that died will have corpses spawned. <br/>
</p>
<h2 id="warehouses">Warehouses</h2>
<p>
Currently, warehouses are not implemented and therefore warehouses are not persisted. <br/>
When supply missions and logistics get implemented, warehouses will be persisted as well. <br/>
</p>
</div>
</div>
</main>
<footer>
<p>&copy; 2025 Spearhead Project</p>
</footer>
</body>
</html>
+299
View File
@@ -0,0 +1,299 @@
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Spearhead Reference</title>
<link rel="stylesheet" href="../style/style.css">
<script src="../js/site.js"></script>
</head>
<body>
<header>
<div class="header-box">
<a class="logo" href="../index.html">Spearhead</a>
<div class="header-right">
<nav>
<a href="../index.html">Home</a>
<a href="../pages/tutorials.html">Tutorials</a>
<a href="../pages/persistence.html">Persistence</a>
<a href="../pages/reference.html">Reference</a>
<a href="../pages/spearheadapi.html">API</a>
</nav>
<button id="theme-toggle" class="theme-toggle" title="Toggle light/dark theme">
<svg id="moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M12 11.807A9.002 9.002 0 0 1 10.049 2a9.942 9.942 0 0 0-5.12 2.735c-3.905 3.905-3.905 10.237 0 14.142 3.906 3.906 10.237 3.905 14.143 0a9.946 9.946 0 0 0 2.735-5.119A9.003 9.003 0 0 1 12 11.807z"/>
</svg>
<svg id="sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="display: none;">
<path d="M6.995 12c0 2.761 2.246 5.007 5.007 5.007s5.007-2.246 5.007-5.007-2.246-5.007-5.007-5.007S6.995 9.239 6.995 12zM12 8.993c1.658 0 3.007 1.349 3.007 3.007S13.658 15.007 12 15.007 8.993 13.658 8.993 12 10.342 8.993 12 8.993zM10.998 19H12.998V22H10.998zM10.998 2H12.998V5H10.998zM1.998 11H4.998V13H1.998zM18.998 11H21.998V13H18.998z"/>
<path transform="rotate(-45.017 5.986 18.01)" d="M4.986 17.01H6.986V19.01H4.986z"/>
<path transform="rotate(-45.001 18.008 5.99)" d="M17.008 4.99H19.008V6.99H17.008z"/>
<path transform="rotate(-134.983 5.988 5.99)" d="M4.988 4.99H6.988V6.99H4.988z"/>
<path transform="rotate(134.999 18.008 18.01)" d="M17.008 17.01H19.008V19.01H17.008z"/>
</svg>
</button>
</div>
</div>
</header>
<main>
<div class="reference-container">
<div class="side-nav">
<h4>Contents</h4>
<ul>
<li><a href="#configuration" class="side-nav-h2">Configuration</a></li>
<li><a href="#general-naming-conventions" class="side-nav-h2">General Naming Conventions</a>
<ul>
<li><a href="#stage-zones" class="side-nav-h3">Stage Zones</a></li>
<li><a href="#waiting-stages" class="side-nav-h3">Waiting Stages</a></li>
<li><a href="#mission-zones" class="side-nav-h3">Mission Zones</a></li>
<li><a href="#cap-routes" class="side-nav-h3">CAP Routes</a></li>
<li><a href="#cap-zones" class="side-nav-h3">CAP Zones</a></li>
</ul>
</li>
<li><a href="#mission-types" class="side-nav-h2">Mission Types</a>
<ul>
<li><a href="#sam" class="side-nav-h3">SAM</a></li>
<li><a href="#dead" class="side-nav-h3">DEAD</a></li>
<li><a href="#bai" class="side-nav-h3">BAI</a></li>
<li><a href="#strike" class="side-nav-h3">STRIKE</a></li>
</ul>
</li>
<li><a href="#cap-configuration" class="side-nav-h2">CAP Configuration</a>
<ul>
<li><a href="#cap-group-naming" class="side-nav-h3">CAP Group Naming</a></li>
<li><a href="#cap-group-config" class="side-nav-h3">CAP Group Config</a></li>
<li><a href="#active-and-backup-cap" class="side-nav-h3">Active and Backup CAP</a></li>
</ul>
</li>
<li><a href="#randomization" class="side-nav-h2">Randomization</a></li>
</ul>
</div>
<div class="content-wrapper">
<h1>Spearhead Reference</h1>
<p>
This page provides a detailed overview of all settings, naming conventions, and logic used in
Spearhead. <br />
For a quick start guide, visit the <a href="./tutorials.html">Tutorials</a> page.
</p>
<h2 id="configuration">Configuration</h2>
<p>
For the configuration you can reference the configuration as it is below:
</p>
<pre>
<span class="lua-variable">SpearheadConfig</span> <span class="lua-operator">=</span> {
<span class="lua-variable">CapConfig</span> <span class="lua-operator">=</span> {
<span class="lua-comment">--quickly enable of disable the entire CAP Logic</span>
<span class="lua-comment">--(you can also just rename all units to not be named "CAP_")</span>
<span class="lua-variable">enabled</span> <span class="lua-operator">=</span> <span class="lua-keyword">true</span>, <span class="lua-comment">-- default true</span>
<span class="lua-comment">--min ground speed for CAP aircraft during patrol</span>
<span class="lua-comment">-- unit: knots</span>
<span class="lua-variable">minSpeed</span> <span class="lua-operator">=</span> <span class="lua-variable">400</span>, <span class="lua-comment">-- default 400</span>
<span class="lua-comment">--max speed for CAP aircraft during patrol</span>
<span class="lua-comment">-- unit: knots</span>
<span class="lua-variable">maxSpeed</span> <span class="lua-operator">=</span> <span class="lua-variable">500</span>, <span class="lua-comment">-- default 500</span>
<span class="lua-comment">--minAlt for aircraft on patrol</span>
<span class="lua-comment">-- unit: feet</span>
<span class="lua-variable">minAlt</span> <span class="lua-operator">=</span> <span class="lua-variable">18000</span>, <span class="lua-comment">-- default 18000</span>
<span class="lua-comment">--maxAlt for aircraft on patrol</span>
<span class="lua-comment">-- unit: feet</span>
<span class="lua-variable">maxAlt</span> <span class="lua-operator">=</span> <span class="lua-variable">28000</span>, <span class="lua-comment">-- default 28000</span>
<span class="lua-comment">--Delay for aircraft from touchdown to off the chocks.</span>
<span class="lua-comment">-- unit: seconds</span>
<span class="lua-variable">rearmDelay</span> <span class="lua-operator">=</span> <span class="lua-variable">600</span>, <span class="lua-comment">-- default 600</span>
<span class="lua-comment">--Delay for aircraft from death to takeoff.</span>
<span class="lua-comment">--When the seconds remaining is the same at the rearmDelay it will be spawned on the ramp and follow the rearm logic.</span>
<span class="lua-comment">-- !! Can not be lower than rearmDelay</span>
<span class="lua-comment">-- unit: seconds</span>
<span class="lua-variable">deathDelay</span> <span class="lua-operator">=</span> <span class="lua-variable">1800</span>, <span class="lua-comment">-- default 1800</span>
},
<span class="lua-variable">StageConfig</span> <span class="lua-operator">=</span> {
<span class="lua-comment">-- management of stages and its missions.</span>
<span class="lua-comment">-- This is not related to CAP managers which will continue to work even if stage management is disabled</span>
<span class="lua-variable">enabled</span> <span class="lua-operator">=</span> <span class="lua-keyword">true</span>, <span class="lua-comment">-- default true</span>
<span class="lua-comment">--Will draw the active and the next stage</span>
<span class="lua-variable">drawStages</span> <span class="lua-operator">=</span> <span class="lua-keyword">true</span>, <span class="lua-comment">-- default true</span>
<span class="lua-comment">--AutoStages will continue to the next stage automatically on completion of the missions within the stage.</span>
<span class="lua-comment">-- If you want to make it so the next stage triggers only when you want to disable it here and manually implement the actions needed.</span>
<span class="lua-comment">--[
TODO: Add manual stage transition documentation
]]</span>
<span class="lua-variable">autoStages</span> <span class="lua-operator">=</span> <span class="lua-keyword">true</span>, <span class="lua-comment">--default true</span>
<span class="lua-comment">--Maximum missions per stage (includes all types of missions)</span>
<span class="lua-variable">maxMissionStage</span> <span class="lua-operator">=</span> <span class="lua-variable">10</span>,
<span class="lua-comment">--Stage starting number</span>
<span class="lua-variable">startingStage</span> <span class="lua-operator">=</span> <span class="lua-variable">1</span>,
<span class="lua-comment">---DEBUG logging. Consider keeping this disabled</span>
<span class="lua-variable">debugEnabled</span> <span class="lua-operator">=</span> <span class="lua-keyword">false</span>
},
<span class="lua-variable">Persistence</span> <span class="lua-operator">=</span> {
<span class="lua-comment">--- io and lfs cannot be sanitized in the MissionScripting.lua</span>
<span class="lua-comment">--- enables or disables the persistence logic in spearhead</span>
<span class="lua-variable">enabled</span> <span class="lua-operator">=</span> <span class="lua-keyword">false</span>,
<span class="lua-comment">--- sets the directory where the persistence file is stored</span>
<span class="lua-comment">--- if nil then lfs.writedir() will be used.</span>
<span class="lua-comment">--- which will</span>
<span class="lua-variable">directory</span> <span class="lua-operator">=</span> <span class="lua-keyword">nil</span>,
<span class="lua-comment">--- the filename of the persistence file. Should end with .json for convention, but any text extension should do.</span>
<span class="lua-variable">fileName</span> <span class="lua-operator">=</span> <span class="lua-string">"Spearhead_Persistence.json"</span>
}
}</pre>
<h2 id="general-naming-conventions">General Naming Conventions</h2>
<p>
Spearhead uses specific naming conventions for zones, missions, and CAP configurations. These
conventions are critical for the framework to function correctly.
</p>
<h3 id="stage-zones">Stage Zones</h3>
<p>
<strong>Format:</strong> <span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_[OrderNumber]_[FreeForm]</span></span>
<br />
<strong>Example:</strong> <span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_1_EAST</span></span>
</p>
<p>
Stages are logical parts of a mission. They encapsulate multiple missions, airbases, and other
objects. <br />
Secondary stages can be defined using the format: <span
class="inline-lua"><span class="lua-variable">MISSIONSTAGE_x[OrderNumber]</span></span>.
</p>
<h3 id="waiting-stages">Waiting Stages</h3>
<p>
<strong>Format:</strong> <span class="inline-lua"><span class="lua-variable">WAITINGSTAGE_[Order]_[Seconds]</span></span> <br />
<strong>Example:</strong> <span class="inline-lua"><span class="lua-variable">WAITINGSTAGE_2_180</span></span>
</p>
<p>
Waiting stages introduce delays between stages. They activate only after the previous stage is
completed.
</p>
<h3 id="mission-zones">Mission Zones</h3>
<p>
<strong>Format:</strong> <span class="inline-lua"><span class="lua-variable">MISSION_[Type]_[Name]</span></span> <br />
<strong>Example:</strong> <span class="inline-lua"><span class="lua-variable">MISSION_DEAD_BYRON</span></span>
</p>
<p>
Missions are completable objectives with specific types, such as DEAD, BAI, STRIKE, or SAM. <br />
Randomized missions can be defined using the format: <span
class="inline-lua"><span class="lua-variable">RANDOMMISSION_[Type]_[Name]_[Index]</span></span>.
</p>
<h3 id="cap-routes">CAP Routes</h3>
<p>
<strong>Format:</strong> <span class="inline-lua"><span class="lua-variable">CAPROUTE_[Name]</span></span> <br />
<strong>Example:</strong> <span class="inline-lua"><span class="lua-variable">CAPROUTE_ALPHA</span></span>
</p>
<p>
CAP routes define the patrol paths for CAP units. They are tied to specific stages and zones.
</p>
<h3 id="cap-zones">CAP Zones</h3>
<p>
<strong>Format:</strong> <span class="inline-lua"><span class="lua-variable">CAPZONE_[Name]</span></span> <br />
<strong>Example:</strong> <span class="inline-lua"><span class="lua-variable">CAPZONE_BRAVO</span></span>
</p>
<p>
CAP zones are areas where CAP units operate. They are linked to CAP routes and stages.
</p>
<h2 id="mission-types">Mission Types</h2>
<p>
Each mission type has specific logic and completion criteria. Below are the supported types:
</p>
<h3 id="sam">SAM</h3>
<p>
SAM missions involve surface-to-air missile sites. These missions are activated when a stage is
"Pre-Active." <br />
<strong>Completion Logic:</strong> Destroy all air defenses in the zone.
</p>
<h3 id="dead">DEAD</h3>
<p>
DEAD missions target enemy air defenses. They are activated at the start of a stage. <br />
<strong>Completion Logic:</strong> Destroy all designated targets in the zone.
</p>
<h3 id="bai">BAI</h3>
<p>
BAI missions involve battlefield air interdiction. These missions target enemy ground forces.
</p>
<h3 id="strike">STRIKE</h3>
<p>
STRIKE missions target strategic objectives, such as supply depots or command centers. <br />
<strong>Completion Logic:</strong> Destroy all designated targets in the zone.
</p>
<h2 id="cap-configuration">CAP Configuration</h2>
<p>
CAP (Combat Air Patrol) units are managed using specific naming conventions and configurations.
</p>
<h3 id="cap-group-naming">CAP Group Naming</h3>
<p>
<strong>Format:</strong> <span class="inline-lua"><span class="lua-variable">CAP_[A|B][Config]_[FreeForm]</span></span> <br />
<strong>Example:</strong> <span class="inline-lua"><span class="lua-variable">CAP_A[1-4]5_SomeName</span></span>
</p>
<h3 id="cap-group-config">CAP Group Config</h3>
<pre>
<span class="lua-comment">1 at x:</span> <span class="lua-variable">[&lt;activeStage&gt;]&lt;capStage&gt;</span>
<span class="lua-comment">n and n at x:</span> <span class="lua-variable">[&lt;activeStage&gt;,&lt;activeStage&gt;]&lt;capStage&gt;</span>
<span class="lua-comment">n till n at x:</span> <span class="lua-variable">[&lt;activeStage&gt;-&lt;activeStage&gt;]&lt;capStage&gt;</span>
<span class="lua-comment">n till n and n at x:</span> <span class="lua-variable">[&lt;activeStage&gt;-&lt;activeStage&gt;,&lt;activeStage&gt;]&lt;capStage&gt;</span>
<span class="lua-comment">n till n at Active:</span> <span class="lua-variable">[&lt;activeStage&gt;-&lt;activeStage&gt;]A</span>
<span class="lua-comment">Divider: |</span>
<span class="lua-comment">Examples:</span>
<span class="lua-variable">CAP_A[1-4,6]7|[5,7]8_SomeName</span> <span class="lua-comment">=&gt; Will fly CAP at stage 7 when stages 1 through 4 and 6 are active and will fly CAP at 8 when 5 and 7 are active.</span>
<span class="lua-variable">CAP_A[2-5]5|[6]6_SomeName</span> <span class="lua-comment">=&gt; Will fly CAP at stage 5 when stages 2 through 5 are active and will fly CAP at 6 when 6 is active.</span>
<span class="lua-variable">CAP_A[1-5]A|[6]7_SomeName</span> <span class="lua-comment">=&gt; Will fly CAP at the ACTIVE stage if stages 1-5 are active. Then when 6 is active, it will fly in 7.</span>
</pre>
<h3 id="active-and-backup-cap">Active and Backup CAP</h3>
<p>
<strong>Active Units:</strong> Define the maximum number of groups in a zone at a time. <br />
<strong>Backup Units:</strong> Fill in when active units are unavailable due to RTB, death, or
rearming.
</p>
<h2 id="randomization">Randomization</h2>
<p>
Missions can be randomized using the <span class="inline-lua"><span class="lua-variable">RANDOMMISSION</span></span> prefix. <br />
Spearhead will pick one random mission from zones with the same name.
</p>
</div>
</div>
<div style="clear: both;"></div>
</main>
<footer>
<p>&copy; 2025 Spearhead Project</p>
</footer>
</body>
</html>
+96
View File
@@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Spearhead API</title>
<link rel="stylesheet" href="../style/style.css">
<script src="../js/site.js"></script>
</head>
<body>
<header>
<div class="header-box">
<a class="logo" href="../index.html">Spearhead</a>
<div class="header-right">
<nav>
<a href="../index.html">Home</a>
<a href="../pages/tutorials.html">Tutorials</a>
<a href="../pages/persistence.html">Persistence</a>
<a href="../pages/reference.html">Reference</a>
<a href="../pages/spearheadapi.html">API</a>
</nav>
<button id="theme-toggle" class="theme-toggle" title="Toggle light/dark theme">
<svg id="moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M12 11.807A9.002 9.002 0 0 1 10.049 2a9.942 9.942 0 0 0-5.12 2.735c-3.905 3.905-3.905 10.237 0 14.142 3.906 3.906 10.237 3.905 14.143 0a9.946 9.946 0 0 0 2.735-5.119A9.003 9.003 0 0 1 12 11.807z"/>
</svg>
<svg id="sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="display: none;">
<path d="M6.995 12c0 2.761 2.246 5.007 5.007 5.007s5.007-2.246 5.007-5.007-2.246-5.007-5.007-5.007S6.995 9.239 6.995 12zM12 8.993c1.658 0 3.007 1.349 3.007 3.007S13.658 15.007 12 15.007 8.993 13.658 8.993 12 10.342 8.993 12 8.993zM10.998 19H12.998V22H10.998zM10.998 2H12.998V5H10.998zM1.998 11H4.998V13H1.998zM18.998 11H21.998V13H18.998z"/>
<path transform="rotate(-45.017 5.986 18.01)" d="M4.986 17.01H6.986V19.01H4.986z"/>
<path transform="rotate(-45.001 18.008 5.99)" d="M17.008 4.99H19.008V6.99H17.008z"/>
<path transform="rotate(-134.983 5.988 5.99)" d="M4.988 4.99H6.988V6.99H4.988z"/>
<path transform="rotate(134.999 18.008 18.01)" d="M17.008 17.01H19.008V19.01H17.008z"/>
</svg>
</button>
</div>
</div>
</header>
<main>
<div class="reference-container">
<div class="side-nav">
<h4>Contents</h4>
<ul>
<li><a href="#introduction" class="side-nav-h2">Introduction</a></li>
<li><a href="#stages" class="side-nav-h2">Stages</a></li>
</ul>
</div>
<div class="content-wrapper">
<h1>Spearhead API</h1>
<div class="note">
<p><strong>NOTE:</strong> The Spearhead.API space is only released in the Beta branch at the moment.</p>
</div>
<h2 id="introduction">Introduction</h2>
<p>
The <span class="inline-lua"><span class="lua-variable">Spearhead.API</span></span> space is specifically created to make sure mission makers can interact with the framework.
</p>
<p>
Simply alter logic, get the current state in Spearhead, and give the whole Mission Editor more control.
</p>
<p>
For example, late activate the entire framework by calling <span class="inline-lua"><span class="lua-function">Spearhead.API.Stages.changeStage</span>(<span class="lua-variable">1</span>)</span> later or on demand and setting the starting config stage to -1 in the Spearhead configuration file.
</p>
<h2 id="stages">Stages</h2>
<pre>
<span class="lua-comment">---Changes the active stage of spearhead.
--- All other stages will change based on the normal logic. (CAP, BLUE etc.)
---@param stageNumber number the stage number you want changed
---@return boolean success indicator of success
---@return string message error message</span>
<span class="lua-variable">Spearhead.API.Stages</span>.<span class="lua-function">changeStage</span> <span class="lua-operator">=</span> <span class="lua-keyword">function</span>(<span class="lua-variable">stageNumber</span>) <span class="lua-keyword">end</span>
<span class="lua-comment">---Returns the current stange number
---Returns nil when the stagenumber was not set and spearhead is not started.
---@return number | nil</span>
<span class="lua-variable">Spearhead.API.Stages</span>.<span class="lua-function">getCurrentStage</span> <span class="lua-operator">=</span> <span class="lua-keyword">function</span>() <span class="lua-keyword">end</span>
<span class="lua-comment">---returns whether a stage (by index) is complete.
---@param stageNumber number
---@return boolean | nil
---@return string</span>
<span class="lua-variable">Spearhead.API.Stages</span>.<span class="lua-function">isStageComplete</span> <span class="lua-operator">=</span> <span class="lua-keyword">function</span>(<span class="lua-variable">stageNumber</span>) <span class="lua-keyword">end</span>
</pre>
</div>
</div>
</main>
<footer>
<p>&copy; 2025 Spearhead Project</p>
</footer>
</body>
</html>
+289
View File
@@ -0,0 +1,289 @@
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Spearhead Tutorials</title>
<link rel="stylesheet" href="../style/style.css">
<script src="../js/site.js"></script>
</head>
<body>
<header>
<div class="header-box">
<a class="logo" href="../index.html">Spearhead</a>
<div class="header-right">
<nav>
<a href="../index.html">Home</a>
<a href="../pages/tutorials.html">Tutorials</a>
<a href="../pages/persistence.html">Persistence</a>
<a href="../pages/reference.html">Reference</a>
<a href="../pages/spearheadapi.html">API</a>
</nav>
<button id="theme-toggle" class="theme-toggle" title="Toggle light/dark theme">
<svg id="moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M12 11.807A9.002 9.002 0 0 1 10.049 2a9.942 9.942 0 0 0-5.12 2.735c-3.905 3.905-3.905 10.237 0 14.142 3.906 3.906 10.237 3.905 14.143 0a9.946 9.946 0 0 0 2.735-5.119A9.003 9.003 0 0 1 12 11.807z"/>
</svg>
<svg id="sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="display: none;">
<path d="M6.995 12c0 2.761 2.246 5.007 5.007 5.007s5.007-2.246 5.007-5.007-2.246-5.007-5.007-5.007S6.995 9.239 6.995 12zM12 8.993c1.658 0 3.007 1.349 3.007 3.007S13.658 15.007 12 15.007 8.993 13.658 8.993 12 10.342 8.993 12 8.993zM10.998 19H12.998V22H10.998zM10.998 2H12.998V5H10.998zM1.998 11H4.998V13H1.998zM18.998 11H21.998V13H18.998z"/>
<path transform="rotate(-45.017 5.986 18.01)" d="M4.986 17.01H6.986V19.01H4.986z"/>
<path transform="rotate(-45.001 18.008 5.99)" d="M17.008 4.99H19.008V6.99H17.008z"/>
<path transform="rotate(-134.983 5.988 5.99)" d="M4.988 4.99H6.988V6.99H4.988z"/>
<path transform="rotate(134.999 18.008 18.01)" d="M17.008 17.01H19.008V19.01H17.008z"/>
</svg>
</button>
</div>
</div>
</header>
<main>
<div class="reference-container">
<div class="side-nav">
<h4>Contents</h4>
<ul>
<li><a href="#include-the-script" class="side-nav-h2">Include the Script</a></li>
<li><a href="#stages" class="side-nav-h2">Stages</a></li>
<li><a href="#setting-up-cap" class="side-nav-h2">Setting up CAP</a>
<ul>
<li><a href="#creating-cap-routes" class="side-nav-h3">Creating CAP Routes</a></li>
</ul>
</li>
<li><a href="#setting-up-the-missions" class="side-nav-h2">Setting up the Missions</a>
<ul>
<li><a href="#mission-1-dead" class="side-nav-h3">Mission: DEAD</a></li>
<li><a href="#mission-2-strike" class="side-nav-h3">Mission: STRIKE</a></li>
</ul>
</li>
<li><a href="#mission-briefings" class="side-nav-h2">Mission Briefings</a></li>
</ul>
</div>
<div class="content-wrapper">
<h1>Tutorials</h1>
<p>
This guide is to get you started building your first Spearhead mission. <br />
Spearhead was created to enable the mission maker to worry as little about the running, timing and scripting
and most about the setting and looks and feel of the mission. <br />
In the example we'll show how you can create a simple island hopping mission
</p>
<h2 id="include-the-script">Include the Script</h2>
<p>
Download the latest version of Spearhead. You can choose which version you feel comfortable with. <br />
Versions that end in -rc are not stable. Versions that do not have the "release candidate" (rc) tag are.
<br />
<a style="text-decoration: underline;" target="_blank" href="https://github.com/dutchie031/Spearhead/releases">See All releases here</a>
</p>
<p>
Then run the script in the mission. <br />
Please do exactly as it's done below. <br />
</p>
<div style="width: 100%;">
<img style="width: 100%;" src="../img/script_install.png"></img>
</div>
<div class="note">
<p>
Spearhead does not require any dependencies (eg. MIST or MOOSE). Compatibility with other frameworks is
not tested at this time, so cannot be guaranteed, but there should be no conflicts if they are not
controlling the same units.
</p>
</div>
<h2 id="stages">Stages</h2>
<p>
So first of all think about the stages.<br />
These are logically ordered zones that will activate one by one based on the mission status in them. <br />
There is a little more to it, but you'll find out. <br />
Stages need to be named according to the convention: <span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_[OrderNumber]_[FreeForm]</span></span> <br />
The first stage will be called <span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_1</span></span> or <span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_1_EAST</span></span> for example. <br />
<br /><br />
Stages are divided in primary stages: <span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_[number]</span></span> <br />
or secondary stages: <span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_x[number]</span></span> <br />
Note the x before the number. This marks it as "extra"
</p>
<p>
For this mission we started with the three stages: <span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_1_GROUND</span></span>,
<span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_2_WATER</span></span> and <span
class="inline-lua"><span class="lua-variable">MISSIONSTAGE_1_AIRBASE</span></span> as you see in the image.
</p>
<img src="../img/starting_stages.png" style="width: 100%;"></img>
<p>
<span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_1_GROUND</span></span> will be activated when the mission starts <br />
<span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_1_WATER</span></span> will be also be activated <br />
<span class="inline-lua"><span class="lua-variable">MISSIONSTAGE_2_AIRBASE</span></span> will be activated when the player enters the zone.
<br />
</p>
<h2 id="setting-up-cap">Setting up CAP</h2>
<p>
If you don't want to use the CAP managers withing Spearhead you can skip this and continue to <a href="#setting-up-the-missions">setting up the missions</a>. <br />
However CAP is one of the painpoints in a lot of missions and setting up a dynamic feeling airspace can be
quite the challenge. <br />
With the CAP managers we've tried to make this a lot easier. <br />
A CAP group needs to follow the following naming convention: <span
class="inline-lua"><span class="lua-variable">CAP_[A|B][CONFIG]_[Free Form]</span></span>
For details on config read this: <span class="inline-ref">CAP Group Config</span>
For now I set up 3 groups with the following names. <span class="inline-lua"><span class="lua-variable">CAP_A[1]1_Rota1</span></span>, <span class="inline-lua"><span class="lua-variable">CAP_A[1]1_Rota1-1</span></span>,
<span class="inline-lua"><span class="lua-variable">CAP_B[1]1_Rota1</span></span> <br />
The first two are marked with <span class="inline-lua"><span class="lua-variable">A</span></span> and will therefore be primary CAP units. They will be
scheduled and make up for the total count. <br />
Meaning that for this airbase there is 2 CAP units max at a time flying out. <br />
In this case all groups have <span class="inline-lua"><span class="lua-variable">[1]1</span></span> in the name, (This would be the same as <span class="inline-lua"><span class="lua-variable">[1]A</span></span>) which means
that when stage 1 is active the groups will activate and fly out to stage 1.
I also set up a few groups further back. One example: <span class="inline-lua"><span class="lua-variable">CAP_A[1-3]3_Group1</span></span>. This group will
protect zone 3 when zones 1 through 3 are active.
CAP units fly out, fly their CAP zone for x amount of minutes and will then RTB. <br />
Before they actually RTB an event is triggered 10 minutes before the actual RTB task. This event
will trigger a backup unit to startup and fly out to take over. <br />
</p>
<div class="note">
<p>
TIP ! <br />
You can start a mission, speed up the simulation and make the CAP fly out to see what happens
</p>
</div>
<h3 id="creating-cap-routes">Creating CAP Routes</h3>
<p>
Creating CAP routes is not needed per se, but with a multi-stage stage (we have 2 stages with <span class="inline-lua"><span class="lua-variable">_1_</span></span>) it is recommended. <br/>
Similarly with huge stages. <br/>
If there is multiple zones it will "round-robin" over them. <br/>
</p>
<p>
If no CAP route is present the unit will fly a route generated differently per zone: <br/>
<span class="inline-lua"><span class="lua-variable">quad zone</span></span> => race-track between the corner closest to the origin airbase to the center point of the zone <br/>
<span class="inline-lua"><span class="lua-variable">circle zone</span></span> => race-track between the closest point on circle to the origin airbase to the center <br/>
</p>
<p>
If you want to create your own CAP Routes you can! <br/>
For this example I created 2 CAP routes inside of the 2 <span class="inline-lua"><span class="lua-variable">_1_</span></span> stages. <br/>
</p>
<p>
As you can see below there's a nice feature you can exploit. As long as the <span class="inline-lua"><span class="lua-variable">X</span></span> of the zone is inside of the the <span class="inline-lua"><span class="lua-variable">CAPROUTE</span></span> will be used for that stage!
</p>
<img src="../img/cap_routes.png" alt="CAP Routes Image" style="width: 100%;"></img>
<p>
Well, nice, we're done setting up the initial CAP effort. <br/>
If you want to change values for the CAP routes please read about how to configure it here: <a href="./Reference.html#cap-config">Cap Config</a>
</p>
<h2 id="setting-up-the-missions">Setting up the Missions</h2>
<p>
Now the part where you as a mission maker can really get into the nitty gritty. <br/>
Missions are managed and monitored by Spearhead. <br/>
Statics, groups and single units all alike. <br/>
</p>
<div class="note">
<p>
<strong>NOTE:</strong> While static are the same as groups in this context, they are not within DCS, please refrain from using static groups. A <span class="inline-ref">static</span> in DCS has a 1:1 relation for group:unit.
</p>
</div>
<p>
For this example I'll set up two missions. The first one is <span class="inline-lua"><span class="lua-variable">DEAD</span></span> mission and will consist of an SA-2 site with an additional "control center".
</p>
<h3 id="mission-1-dead">Mission: DEAD</h3>
<p>
As you can see on the left image the template of the SA-2 was placed. Then dragged around to only face south. <br/>
An additional track radar and search radar was added and all launchers were surrounded by sandbags. <br/>
On top of this there was a sort of control center added with walls, vehicles and some tents.
</p>
<div style="display: flex; width: 100%;">
<div style="flex: 50%">
<img style="width: 100%;" src="../img/sa2_mission_editor.png"/>
</div>
<div style="flex: 50%">
<img style="width: 100%;" src="../img/sa2_result.png"/>
</div>
</div>
<p>
Important to note. It's all inside the triggerzone <span class="inline-lua"><span class="lua-variable">MISSION_DEAD_BYRON</span></span>. Which means it's a <span class="inline-lua"><span class="lua-variable">MISSION</span></span> of type <span class="inline-lua"><span class="lua-variable">DEAD</span></span> and with name <span class="inline-lua"><span class="lua-variable">BYRON</span></span>. <br/>
At the start Spearhead will detect the triggerzone, take all units and despawn them and only spawn when needed for better performance. <br/>
</p>
<p>
The current list of mission types are:
<span class="inline-lua"><span class="lua-variable">DEAD</span></span>
<span class="inline-lua"><span class="lua-variable">STRIKE</span></span>
<span class="inline-lua"><span class="lua-variable">BAI</span></span>
<span class="inline-lua"><span class="lua-variable">SAM</span></span> <br/>
For specific differences, please check the reference page.
</p>
<p>
Each type has some additional completion logic to it. <br/>
<span class="inline-lua"><span class="lua-variable">DEAD</span></span> and <span class="inline-lua"><span class="lua-variable">SAM</span></span> missions will be marked complete when all air defences are destroyed. This includes Tracking Radars, Self tracking launchers and AAA guns if they are inside the zone. <br/>
If you want to add the Search radar or another random unit like the command tent to the target list you can add a <span class="inline-lua"><span class="lua-variable">TGT_</span></span> prefix to the unit or group you want destroyed. <br/>
Please be aware that adding <span class="inline-lua"><span class="lua-variable">TGT_</span></span> to a group will make the entire group a target and therefore each unit needs to be destroyed. <br/>
</p>
<h3 id="mission-2-strike">Mission: STRIKE</h3>
<p>
To show the power of <span class="inline-lua"><span class="lua-variable">TGT_</span></span> targets I'll create a strike mission next.
</p>
<p>
A nice supply strike mission will do. Add a ship, some containers and some additional units. <br/>
Even some SHORADS to spice the whole thing up. <br/>
In the picture below all units that are selected and who show up as white (they are actually red) have the prefix <span class="inline-lua"><span class="lua-variable">TGT_</span></span> in front of their name. <br/>
</p>
<p>
This will make it so the mission will be marked as complete when those units are destroyed. The rest of the units will exist until the entire stage is cleaned up. <br/>
</p>
<img src="../img/strike_target.png"/><br/>
<h2 id="mission-briefings">Mission Briefings</h2>
<p>
So now we've created some missions we also want to add briefings to them. This is pretty easy with Spearhead. <br/>
</p>
<p>
To do so click on <span class="inline-ref">draw</span> on the left hand pane in the mission editor. This opens up the drawing tools in the editor. <br/>
On the right click <span class="inline-ref">TextBox</span> and click somewhere inside the zone to which you want to add the briefing. <br/>
Give the briefing a name (It's not used, but can be nice to use to reference the briefing later) and add the briefing. <br/>
The text box is quite small, but can have a lot of text. Easiest is to edit the text in an editor of choice and paste it into the box afterwards. <br/>
</p>
<p>
Keep the binding layer to "Author" only. That way it doesn't show up for anyone other than in the mission editor.
</p>
<p>
See the two images below. The left shows the <span class="inline-ref">Text Box</span> drawing. The right shows the briefing as shown in the mission.
</p>
<div style="display: flex">
<div style="flex: 50%">
<img src="../img/briefing_me.png"/>
</div>
<div style="flex: 50%">
<img src="../img/briefing_mission.png"/>
</div>
</div>
<div class="note">
<p>
<strong>TIP:</strong> You can make both the <span class="inline-ref">Color</span> and <span class="inline-ref">Fill</span> have a <span class="inline-ref">0</span> value for <span class="inline-ref">a</span>. This will make the weird box be invisible. Make sure to add the name of the mission to the text box name to easily find it back.
</p>
</div>
<p>
We are now done creating a first mission. Hit fly and test it. <br/>
Check all references for way more features and keep up to date with the latest changes as they come along! <br/>
</p>
</div>
</div>
</main>
<footer>
<p>&copy; 2025 Spearhead Project</p>
</footer>
</body>
</html>
+595
View File
@@ -0,0 +1,595 @@
:root {
/* Dark Theme (Default) */
--color-bg-primary: #070a17; /* Darkened primary background */
--color-bg-secondary: #121a30; /* Adjusted secondary background */
--color-bg-tertiary: #182040; /* Slightly darkened tertiary */
--color-bg-header: #050715; /* Darkened header */
--color-bg-code: rgba(11, 16, 35, 0.75); /* Increased opacity for code blocks */
--color-bg-note: rgba(18, 28, 58, 0.75); /* Increased opacity for notes */
--color-bg-hover: rgba(86, 100, 210, 0.2); /* Slightly increased hover opacity */
--color-bg-inline-lua: rgba(25, 18, 8, 0.7); /* Background for inline lua code */
--color-bg-note-dark: rgba(50, 40, 15, 0.7); /* Background for note boxes */
--color-text-primary: #ffffff; /* Made whiter (was #f0f3ff) */
--color-text-secondary: #d8e0ff; /* Made whiter (was #bbc8ff) */
--color-text-accent: #90c0ff; /* Made brighter (was #70aaff) */
--color-text-light: #ffffff; /* Unchanged */
--color-border-primary: #3a4980; /* Brightened primary border */
--color-border-accent: #5c75d9; /* Brightened accent border */
--color-link: #90c0ff; /* Made brighter (was #70aaff) */
--color-link-hover: #d0e5ff; /* Made brighter (was #b0d0ff) */
/* Lua syntax highlighting colors with improved contrast */
--color-lua-variable: #ffe080; /* Brighter variable color */
--color-lua-comment: #c0b8a0; /* Brighter comment color */
--color-lua-operator: #ffffff;
--color-lua-keyword: #ffd8a0; /* Brighter keyword color */
--color-lua-string: #c0ffb8; /* Brighter string color */
--color-lua-function: #fff0a0; /* Brighter function color */
/* Shadow and transparency values - unchanged */
--shadow-small: 0 2px 5px rgba(0, 0, 0, 0.3);
--shadow-medium: 0 3px 8px rgba(0, 0, 0, 0.5);
--shadow-large: 0 4px 12px rgba(0, 0, 0, 0.6);
/* Common opacity values */
--opacity-sidenav: 0.85; /* Increased opacity for better contrast */
/* Responsive margins - unchanged */
--margin-left: 20%;
--margin-xlarge: 10%;
--margin-large: 8%;
--margin-medium: 8%;
--margin-small: 5%;
/* Scrollbar colors */
--color-scrollbar-track: rgba(7, 10, 23, 0.8);
--color-scrollbar-thumb-start: #5c75d9;
--color-scrollbar-thumb-end: #3a4980;
--color-scrollbar-thumb-hover-start: #90c0ff;
--color-scrollbar-thumb-hover-end: #5c75d9;
--color-scrollbar-shadow: rgba(144, 192, 255, 0.3);
--color-scrollbar-shadow-hover: rgba(144, 192, 255, 0.5);
}
[data-theme="light"] {
--color-bg-primary: #f5f7ff;
--color-bg-secondary: #e8ecf7;
--color-bg-tertiary: #dce2f0;
--color-bg-header: #f0f2fa;
--color-bg-code: rgba(220, 225, 240, 0.75);
--color-bg-note: rgba(215, 228, 245, 0.75);
--color-bg-hover: rgba(100, 120, 200, 0.1);
--color-bg-inline-lua: rgba(230, 235, 245, 0.7);
--color-bg-note-dark: rgba(235, 240, 250, 0.7);
--color-text-primary: #151720;
--color-text-secondary: #2a2e40;
--color-text-accent: #3050b0;
--color-text-light: #2a2e40;
--color-border-primary: #a0b0e0;
--color-border-accent: #5c75d9;
--color-link: #3050b0;
--color-link-hover: #4060c0;
/* Lua syntax highlighting colors for light theme */
--color-lua-variable: #0050a0;
--color-lua-comment: #606080;
--color-lua-operator: #202030;
--color-lua-keyword: #6030a0;
--color-lua-string: #008060;
--color-lua-function: #0070a0;
/* Shadow values adjusted for light theme */
--shadow-small: 0 2px 5px rgba(0, 0, 0, 0.15);
--shadow-medium: 0 3px 8px rgba(0, 0, 0, 0.2);
--shadow-large: 0 4px 12px rgba(0, 0, 0, 0.25);
/* Common opacity values */
--opacity-sidenav: 0.92;
/* Scrollbar colors */
--color-scrollbar-track: rgba(220, 225, 240, 0.8);
--color-scrollbar-thumb-start: #5c75d9;
--color-scrollbar-thumb-end: #a0b0e0;
--color-scrollbar-thumb-hover-start: #3050b0;
--color-scrollbar-thumb-hover-end: #5c75d9;
--color-scrollbar-shadow: rgba(48, 80, 176, 0.2);
--color-scrollbar-shadow-hover: rgba(48, 80, 176, 0.4);
}
html {
background-color: var(--color-bg-primary);
height: 100%;
scroll-behavior: smooth;
}
body {
color: var(--color-text-primary);
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
height: 100%;
display: flex;
flex-direction: column;
font-size: 16px;
line-height: 1.6;
transition: background-color 0.3s ease, color 0.3s ease;
}
a {
color: var(--color-link);
text-decoration: none;
}
a:hover {
color: var(--color-link-hover);
text-decoration: underline;
}
header {
background: linear-gradient(to right, var(--color-bg-header), var(--color-bg-primary));
box-shadow: var(--shadow-large);
}
.header-box {
padding: 1em;
margin-left: var(--margin-left);
min-height: 5em;
display: flex;
flex-direction: row;
justify-content: start;
align-items: center;
margin-bottom: 0%;
position: relative;
padding: 0 0;
}
.header-right {
width: 50%;
margin-left: 10em;
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 2.5em;
font-weight: 600;
background: linear-gradient(120deg, var(--color-text-secondary), var(--color-text-accent));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
text-shadow: var(--shadow-small);
transition: all 0.3s ease;
}
.logo:hover {
transform: scale(1.02);
text-decoration: none;
}
header nav {
display: flex;
flex-direction: row;
align-items: center;
gap: 1.2rem;
}
nav {
display: flex;
align-items: center;
}
header nav a {
position: relative;
color: var(--color-text-primary);
font-weight: 500;
padding: 0.5em 0.8em;
border-radius: 4px;
transition: all 0.2s ease-in-out;
}
header nav a:hover {
color: var(--color-text-accent);
background-color: var(--color-bg-hover);
text-decoration: none;
}
header nav a::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 2px;
background-color: var(--color-text-accent);
transition: all 0.3s ease;
transform: translateX(-50%);
}
header nav a:hover::after {
width: 80%;
}
header.collapsible {
cursor: pointer;
position: relative;
}
header.collapsible::after {
content: '\25BC'; /* Downward arrow */
position: absolute;
right: 0;
font-size: 0.8em;
color: var(--color-text-light);
}
header.collapsible.collapsed::after {
content: '\25B6'; /* Rightward arrow */
}
h2.collapsible, h3.collapsible {
cursor: pointer;
position: relative;
}
h2.collapsible::before, h3.collapsible::before {
content: '';
margin-right: 0;
width: 0;
display: none;
}
h2.collapsible.collapsed::before, h3.collapsible.collapsed::before {
content: '';
display: none;
}
footer {
padding-left: var(--margin-left);
background-color: var(--color-bg-header);
color: var(--color-text-primary);
padding-top: 1em;
padding-bottom: 1em;
}
main {
flex: 1;
position: relative;
}
/* Side navigation styles */
.reference-container {
margin-top: 2em;
display: flex;
margin-left: var(--margin-left);
flex-direction: row;
gap: 2em;
position: relative;
}
.side-nav {
width: 250px; /* Fixed width instead of percentage */
min-width: 250px; /* Same fixed minimum width */
padding: 1em;
position: sticky;
top: 2em;
min-height: calc(100vh - 20em);
overflow-y: auto;
border-right: 2px solid var(--color-border-accent);
}
.side-nav h4 {
margin-top: 0;
margin-bottom: 0.5em;
}
.side-nav ul {
list-style-type: none;
padding-left: 1em;
margin-top: 0.5em;
}
.side-nav li {
margin-bottom: 0.5em;
}
.side-nav a {
color: var(--color-text-primary);
text-decoration: none;
}
.side-nav a:hover {
color: var(--color-link-hover);
text-decoration: underline;
}
.side-nav-h2 {
color: var(--color-text-primary);
font-weight: bold;
}
.side-nav-h3 {
color: var(--color-text-primary);
padding-left: 1em;
font-size: 0.9em;
}
.content-wrapper {
flex: 1;
max-width: 900px;
}
/* Heading styles */
h1, h2, h3, h4, h5, h6 {
margin-top: 1.5em;
margin-bottom: 0.8em;
color: var(--color-text-secondary);
font-weight: 600;
line-height: 1.3;
}
h1 {
font-size: 2.2em;
border-bottom: 2px solid var(--color-border-primary);
padding-bottom: 0.3em;
}
h2 {
font-size: 1.8em;
border-bottom: 1px solid var(--color-border-primary);
padding-bottom: 0.2em;
}
h3 {
font-size: 1.4em;
color: var(--color-text-accent);
}
h4 {
font-size: 1.2em;
}
p {
margin-bottom: 1.2em;
}
/* List styling for better readability */
ul, ol {
margin: 1em 0 1.5em 0;
padding-left: 2em;
}
li {
margin-bottom: 0.5em;
}
/* Add better spacing between sections */
main > section {
margin-bottom: 2em;
}
/* Improve table styling if tables are used */
table {
border-collapse: collapse;
width: 100%;
margin: 1.5em 0;
overflow-x: auto;
display: block;
}
th, td {
padding: 0.75em 1em;
border: 1px solid var(--color-border-primary);
}
th {
background-color: var(--color-bg-secondary);
font-weight: bold;
}
/* Code and syntax highlighting with improved contrast */
.inline-lua {
background-color: var(--color-bg-inline-lua); /* Darker background for better contrast */
padding: 0.1em 0.3em;
border-radius: 3px;
font-family: 'Courier New', monospace;
white-space: nowrap;
}
/* Code block styling with improved contrast */
pre {
background-color: var(--color-bg-inline-lua); /* Darker background for better contrast */
border: 1px solid var(--color-border-primary);
border-radius: 5px;
padding: 1em;
margin: 1.5em 0;
overflow-x: auto;
font-family: 'Courier New', monospace;
line-height: 1.4;
}
.lua-variable {
color: var(--color-lua-variable); /* Brighter variable color */
}
.lua-comment {
color: var(--color-lua-comment); /* Brighter comment color */
font-style: italic;
}
.lua-operator {
color: var(--color-lua-operator); /* Bright white for better contrast */
}
.lua-keyword {
color: var(--color-lua-keyword); /* Brighter keyword color */
font-weight: bold;
}
.lua-string {
color: var(--color-lua-string); /* Brighter string color */
}
.lua-function {
color: var(--color-lua-function); /* Brighter function color */
font-weight: bold;
}
.inline-ref {
color: var(--color-text-accent);
font-weight: bold;
padding: 0 2px;
}
/* Note boxes */
.note {
background-color: var(--color-bg-note-dark);
border-left: 4px solid var(--color-border-accent);
padding: 0.8em 1em;
margin: 1.5em 0;
border-radius: 0 4px 4px 0;
}
.note p:last-child {
margin-bottom: 0;
}
/* Image styling */
img {
max-width: 100%;
height: auto;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
/* Custom Scrollbar - Enhanced version */
::-webkit-scrollbar {
width: 12px;
height: 12px;
}
::-webkit-scrollbar-track {
background: var(--color-scrollbar-track);
border-radius: 10px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.4);
}
::-webkit-scrollbar-thumb {
background: linear-gradient(to bottom, var(--color-scrollbar-thumb-start), var(--color-scrollbar-thumb-end));
border-radius: 10px;
border: 2px solid var(--color-scrollbar-track);
box-shadow: 0 0 3px var(--color-scrollbar-shadow);
transition: all 0.3s ease;
}
::-webkit-scrollbar-thumb:hover {
background: linear-gradient(to bottom, var(--color-scrollbar-thumb-hover-start), var(--color-scrollbar-thumb-hover-end));
border-width: 1px;
box-shadow: 0 0 5px var(--color-scrollbar-shadow-hover);
}
::-webkit-scrollbar-corner {
background: var(--color-bg-header);
}
/* Firefox scrollbar styling */
* {
scrollbar-width: thin;
scrollbar-color: var(--color-border-accent) var(--color-scrollbar-track);
}
/* Responsive layout adjustments */
@media screen and (max-width: 1500px) {
:root {
--margin-left: var(--margin-xlarge);
}
}
/* Responsive layout adjustments */
@media screen and (max-width: 1200px) {
:root {
--margin-left: var(--margin-large);
}
}
@media screen and (max-width: 900px) {
:root {
--margin-left: var(--margin-small);
}
}
/* Mobile responsive styles */
@media screen and (max-width: 768px) {
:root {
--margin-left: 1em;
}
.side-nav {
display: none; /* Hide side navigation on mobile devices */
}
.content-wrapper {
width: 100%; /* Make content take full width */
}
main {
margin-left: 5%;
margin-right: 5%;
padding-left: 5%;
padding-right: 5%;
}
header {
padding-left: 5%;
padding-right: 5%;
flex-direction: column;
align-items: center;
min-height: auto;
padding-top: 1em;
padding-bottom: 1em;
}
header nav {
margin-left: 0;
margin-top: 1em;
flex-wrap: wrap;
justify-content: center;
}
}
/* Theme Toggle Button */
.theme-toggle {
background: none;
border: none;
color: var(--color-text-primary);
cursor: pointer;
font-size: 1.2rem;
margin-left: 15px;
padding: 5px;
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 50%;
background-color: var(--color-bg-tertiary);
transition: background-color 0.3s ease;
}
.theme-toggle:hover {
background-color: var(--color-bg-hover);
}
.theme-toggle svg {
width: 20px;
height: 20px;
fill: var(--color-text-primary);
}