diff --git a/.github/workflows/evac.yaml b/.github/workflows/evac.yaml new file mode 100644 index 0000000..9e7d467 --- /dev/null +++ b/.github/workflows/evac.yaml @@ -0,0 +1,17 @@ +name: "Gremlin Evac" + +on: + push: + +jobs: + test: + name: Test + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + - uses: ilammy/msvc-dev-cmd@v1 + - uses: leafo/gh-actions-lua@v10 + with: + luaVersion: "5.1" + - run: .\lib\DCS_World_web.exe + - run: .\runtests.bat diff --git a/README.md b/README.md new file mode 100644 index 0000000..b4598f8 --- /dev/null +++ b/README.md @@ -0,0 +1,106 @@ +# Gremlin Scripts + +This is the Gremlin Scripts repo! Everything you need to succeed with DCS mission scripting can be found within. + +## Installation + +Simply copy the contents of the `src` directory to your `Missions` folder in `Saved Games`. If you like, you can also grab MiST from this project's `lib` folder, though it's usually best to grab the latest version [directly from GitHub](https://github.com/mrSkortch/MissionScriptingTools). + +Once you have the files in place, add a trigger to load MiST (follow its documentation for the best ways to do this), a second to load Gremlin Script Tools, and then a third to load the exact script you wish to use, such as Gremlin Evac. Once all three are loaded, the final step is to fully set up the script(s) to do their thing - see the relevant Configuration section, below, for more on this. + +And that's it! The scripts are installed and working from this point on. + +## Components + +### gremlin.lua + +The Gremlin Script Tools file provides common features that all Gremlin Scripts use to do their thing. It must be loaded after MiST, and before any other Gremlin Scripts components. + +### evac.lua + +The Gremlin Evac script sets up your missions to include evacuation scenarios. Simply call `Evac:setup({})` to get sane defualts, or customize everything by filling out the available options you wish to override. + +#### Configuration + +```lua +Evac:setup({ + beaconBatteryLife = 2, + beaconSound = "test.ogg", + carryLimits = { + ["Test"] = 15, + }, + idStart = 5, + loadUnloadPerIndividual = 2, + maxExtractable = { + Refugees = 12, + Infantry = 12, + M249 = 12, + RPG = 12, + StingerIgla = 12, + ["2B11"] = 12, + JTAC = 3, + }, + spawnWeight = 50, + spawnRates = { + test = { + units = 12, + per = 5, + period = Gremlin.Periods.Minute, + }, + }, + startingZones = { + { mode = Evac.modes.EVAC, name = "Test 1", smoke = trigger.smokeColors.Green, side = coalition.side.BLUE }, + { mode = Evac.modes.RELAY, name = "Test 2", smoke = trigger.smokeColors.Orange, side = coalition.side.BLUE }, + { mode = Evac.modes.SAFE, name = "Test 3", smoke = trigger.smokeColors.White, side = coalition.side.BLUE }, + }, +}) +``` + +- `beaconBatteryLife`: How long beacons should broadcast once spawned, in minutes + - Default: `30` + +- `beaconSound`: The audio file name to play for radio beacons + - Default: `beacon.ogg` + +- `carryLimits`: Specifies the maximum capacity loadout per aircraft designator + - Default: `{ ["C-130"] = 90, ["CH-47D"] = 44, ["CH-43E"] = 55, ["Mi-8MT"] = 24, ["Mi-24P"] = 5, ["Mi-24V"] = 5, ["Mi-26"] = 70, ["SH-60B"] = 5, ["UH-1H"] = 8, ["UH-60A"] = 11 }` + +- `idStart`: The lowest ID number that Gremlin Evac will use to create units and groups + - Default: `500` + +- `loadUnloadPerIndividual`: The amount of time it takes to load/unload a single evacuee onto/from an aircraft, in seconds + - Default: `30` + +- `maxExtractable`: Provides a cap for automatically generated evacuees, by type; the script won't create more than allowed here + - Default: `0` for everything + +- `spawnWeight`: The average weight of an evacuee - the exact weight used will vary between 90% and 120% of this value + - Default: `100` + +- `spawnRates`: Describes how and when to spawn evacuee units/groups + - Default: `{ _global = { units = 0, per = 0, period = Gremlin.Periods.Second } }` (everything at mission start) + - Spec + - key: Zone name + - value: table + - `units`: Number or composition of units to spawn + - `per`: Number of periods to wait between spawns + - `0`: At setup time, no repeat + - `< 0`: After `math.abs(per)` periods, no repeat + - `> 0`: Every `per` periods, until `maxExtractable` is reached + - `period`: One of the `Gremlin.Periods` constants indicating how long a single period lasts + +- `startingZones`: Registers zones for evacuation purposes during setup + - Default: `{}` + - Spec + - key: ignored + - value: table + - `mode`: One of the `Evac.modes` constants, indicating what evacuation mode the zone should be registered using + - `name`: Zone name - MUST MATCH THE MISSION EDITOR'S NAME FOR THE ZONE EXACTLY! + - `smoke`: Smoke color, taken from `trigger.smokeColors` + - `side`: Coalition, taken from `coalition.side` + +## Development and Testing + +Gremlin Scripts are fully tested before release. You can run these tests yourself by simply running `runtests.bat` at the top level of this project. It will run _all_ defined tests, at the moment, but that's fine since only Gremlin Evac is available today. + +Development follows standard project rules for Git - create a fork, make your changes on a new branch, submit a PR on GitHub, and we'll review and do our best to merge. If none of these words make any sense to you, let us know and we'll help you figure something out. diff --git a/lib/DCS_World_web.exe b/lib/DCS_World_web.exe new file mode 100644 index 0000000..a2c7e07 Binary files /dev/null and b/lib/DCS_World_web.exe differ diff --git a/test/mock/Mock.lua b/lib/mock/Mock.lua similarity index 90% rename from test/mock/Mock.lua rename to lib/mock/Mock.lua index 11699e1..cdf28c7 100644 --- a/test/mock/Mock.lua +++ b/lib/mock/Mock.lua @@ -3,8 +3,8 @@ -- See @{Spy} and @{ProgrammableFn} for details. -local ProgrammableFn = require 'test.mock.ProgrammableFn' -local Spy = require 'test.mock.Spy' +local ProgrammableFn = require 'lib.mock.ProgrammableFn' +local Spy = require 'lib.mock.Spy' local Mock = {} diff --git a/test/mock/ProgrammableFn.lua b/lib/mock/ProgrammableFn.lua similarity index 97% rename from test/mock/ProgrammableFn.lua rename to lib/mock/ProgrammableFn.lua index fc32c5c..8f060d9 100644 --- a/test/mock/ProgrammableFn.lua +++ b/lib/mock/ProgrammableFn.lua @@ -6,7 +6,7 @@ -- return values. -local ValueMatcher = require 'test.mock.ValueMatcher' +local ValueMatcher = require 'lib.mock.ValueMatcher' local ProgrammableFn = {} diff --git a/test/mock/Spy.lua b/lib/mock/Spy.lua similarity index 98% rename from test/mock/Spy.lua rename to lib/mock/Spy.lua index 6cd2091..293f6eb 100644 --- a/test/mock/Spy.lua +++ b/lib/mock/Spy.lua @@ -3,7 +3,7 @@ -- For each call the arguments and return values are saved. -local ValueMatcher = require 'test.mock.ValueMatcher' +local ValueMatcher = require 'lib.mock.ValueMatcher' local Spy = {} diff --git a/test/mock/ValueMatcher.lua b/lib/mock/ValueMatcher.lua similarity index 100% rename from test/mock/ValueMatcher.lua rename to lib/mock/ValueMatcher.lua diff --git a/mocks/DCS.lua b/mocks/DCS.lua index 0c21b5d..a748aba 100644 --- a/mocks/DCS.lua +++ b/mocks/DCS.lua @@ -1,5 +1,5 @@ -local Mock = require("test.mock.Mock") -local Spy = require("test.mock.Spy") +local Mock = require("lib.mock.Mock") +local Spy = require("lib.mock.Spy") require("Scripts.Common.LuaClass") Object = { diff --git a/src/evac.lua b/src/evac.lua index 460d031..2a488b6 100644 --- a/src/evac.lua +++ b/src/evac.lua @@ -1117,7 +1117,11 @@ function Evac:setup(config) return end - if config ~= nil then + do -- configuration + if config == nil then + config = {} + end + Evac.beaconBatteryLife = config.beaconBatteryLife or 30 Evac.beaconSound = config.beaconSound or "beacon.ogg" Evac.carryLimits = config.carryLimits or { @@ -1163,7 +1167,7 @@ function Evac:setup(config) end end end - end + end -- configuration Evac._internal.beacons.generateVHFrequencies() Evac._internal.beacons.generateUHFrequencies() diff --git a/test/evac.lua b/test/evac.lua index 3015733..071675d 100644 --- a/test/evac.lua +++ b/test/evac.lua @@ -1,6 +1,6 @@ local lu = require("luaunit_3_4") local inspect = require("inspect") -local Spy = require("test.mock.Spy") +local Spy = require("lib.mock.Spy") table.unpack = table.unpack or unpack unpack = table.unpack @@ -1749,11 +1749,22 @@ Test6TopLevel = { test1SetupNone = function() lu.assertEquals(Evac:setup(), nil) - lu.assertEquals(Evac.beaconBatteryLife, 0) - lu.assertEquals(Evac.beaconSound, "") - lu.assertEquals(Evac.carryLimits, {}) - lu.assertEquals(Evac.idStart, 0) - lu.assertEquals(Evac.loadUnloadPerIndividual, 0) + lu.assertEquals(Evac.beaconBatteryLife, 30) + lu.assertEquals(Evac.beaconSound, "beacon.ogg") + lu.assertEquals(Evac.carryLimits, { + ["C-130"] = 90, + ["CH-47D"] = 44, + ["CH-43E"] = 55, + ["Mi-8MT"] = 24, + ["Mi-24P"] = 5, + ["Mi-24V"] = 5, + ["Mi-26"] = 70, + ["SH-60B"] = 5, + ["UH-1H"] = 8, + ["UH-60A"] = 11, + }) + lu.assertEquals(Evac.idStart, 500) + lu.assertEquals(Evac.loadUnloadPerIndividual, 30) lu.assertEquals(Evac.maxExtractable, { Refugees = 0, Infantry = 0, @@ -1763,8 +1774,8 @@ Test6TopLevel = { ["2B11"] = 0, JTAC = 0, }) - lu.assertEquals(Evac.spawnRates, {}) - lu.assertEquals(Evac.spawnWeight, 0) + lu.assertEquals(Evac.spawnRates, { _global = { per = 0, period = 1, units = 0 } }) + lu.assertEquals(Evac.spawnWeight, 100) end, test2SetupBlank = function() lu.assertEquals(Evac:setup({}), nil)