Skip to content

Commit f572b31

Browse files
committed
Merge branch 'development' into piemenu-behavior
2 parents 83557ee + 0e1d345 commit f572b31

File tree

855 files changed

+404151
-90954
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

855 files changed

+404151
-90954
lines changed

.github/workflows/meson.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ jobs:
178178
echo "::group::Installing pkg-config"
179179
sudo apt install pkg-config
180180
echo "::group::Installing mac deps"
181-
omp install libsdl2 onetbb lz4 libpng minizip luajit flac
181+
omp install libsdl2 libsdl2_image onetbb lz4 libpng minizip luajit flac
182182
echo "OSXCROSS_PKG_CONFIG_PATH=${{env.OSXCROSS_TARGET}}/macports/pkgs/opt/local/libexec/onetbb/lib/pkgconfig" >> $GITHUB_ENV
183183
echo "::endgroup::"
184184
echo "::group::Installing meson"

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"request": "launch",
1414
"program": "${workspaceFolder}/${config:mesonbuild.buildFolder}/CortexCommand",
1515
"cwd": "${workspaceFolder}",
16-
"preLaunchTask": "meson Build Release",
16+
"preLaunchTask": "Meson: Build all targets",
1717
"envFile": "${workspaceFolder}/${config:mesonbuild.buildFolder}/meson-vscode.env",
1818
"presentation": {
1919
"group": "unix"

CHANGELOG.md

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,45 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5050

5151
- New `AEmitter` and `PEmitter` INI and Lua (R/W) property `PlayBurstSound` which denotes whether the BurstSound should play when appropriate. This should not be confused for a trigger - it's just a enable/disable toggle to avoid having to remove and add BurstSound altogether.
5252

53+
- New `MOSprite` INI and Lua (R/W) integer property `ForcedHFlip` which forces a certain flippedness and disallows anything else from ever changing it without clearing the forced value first. 0 is forced not flipped, 1 forced flipped, and -1 is no force.
54+
55+
- New hotkey bindings.
56+
On Mouse+KB PC the defaults are: Weapon Primary Hotkey on V, Weapon Auxiliary Hotkey on H, Actor Primary Hotkey on X, Actor Auxiliary Hotkey on O.
57+
Added new `Controller` states `WEAPON_PRIMARY_HOTKEYSTART`, `WEAPON_AUXILIARY_HOTKEYSTART`, `ACTOR_PRIMARY_HOTKEYSTART`, `ACTOR_AUXILIARY_HOTKEYSTART`, `WEAPON_PRIMARY_HOTKEY`, `WEAPON_AUXILIARY_HOTKEY`, `ACTOR_PRIMARY_HOTKEY`, `ACTOR_AUXILIARY_HOTKEY`
58+
59+
- New hotkey system for `Actor` and `HeldDevice`.
60+
Pressing a certain new hotkey will mark it as activated on `Actor` and `HeldDevice`, letting scripts make use of the new bindings easily.
61+
`Enum` binding for `HeldDevice.HeldDeviceHotkeyType`: `PRIMARY = 0, AUXILIARY = 1, HELDDEVICEHOTKEYTYPECOUNT = 2`.
62+
`Enum` binding for `Actor.ActorHotkeyType`: `PRIMARY = 0, AUXILIARY = 1, ACTORHOTKEYTYPECOUNT = 2`.
63+
Both `Actor` and `HeldDevice` have the following functions:
64+
`HotkeyActionIsActivated(hotkeyType)` returns whether a certain hotkey action is being activated or not.
65+
`ActivateHotkeyAction(hotkeyType)` activates a certain hotkey action.
66+
`DeactivateHotkeyAction(hotkeyType)` deactivates a certain hotkey action.
67+
68+
- New `GAScripted` Lua script method `IsCompatibleScene(scene)` to allow Activities to generically decide which Scenes are eligible by returning a boolean value.
69+
New `GAScripted` INI enumerating property `AddRequiredArea`, replacing Lua file scanning, to allow Activities to explicitly state which areas are strictly required.
70+
As before, these work in tandem. Both the required areas, if defined, and script conditional method, if defined, must pass for the scene to qualify.
71+
72+
- New `GameActivity` INI properties `TeamNTechSwitchEnabled` which determine whether activity team factions are configurable by the user. This is most useful for communicating what the player is not intended to change, or what inputs would be ignored otherwise.
73+
5374
- Allow lua scripts to use LuaJIT's BitOp module (see https://bitop.luajit.org/api.html)
5475

76+
- New `Emission` INI and Lua (R/W) property `ParticleCount` which sets how many particles the Emission spawns per emission. Defaults to 1.
77+
78+
- New `Gib` and `Emission` INI and Lua (R/W) property `InheritsAngularVel`, which determines how much of the parent MO's angular velocity they inherit. Defaults to 1 for gibs, 0 for emissions.
79+
80+
- New `Attachable` INI and Lua (R/W) properties `InheritsVelWhenDetached` and `InheritsAngularVelWhenDetached`, which determine how much of these velocities an attachable inherits from its parent when detached. Defaults to 1.
81+
82+
- New `ACraft` INI and Lua (R/W) property `CanEnterOrbit`, which determines whether a craft can enter orbit (and refund gold appropriately) or not. If false, default out-of-bounds deletion logic applies.
83+
5584
</details>
5685

5786
<details><summary><b>Changed</b></summary>
5887

5988
- Improved navigation, making running and fast walkpaths much more consistent.
6089

6190
- Increased fog-of-war resolution in all vanilla activities, and conquest, from 20x20 to 4x4.
62-
The Ronin Scrambler, the basic scanner, and `SceneMan:CastUnseenRay` have been changed to accomodate fog-of-war resolutions as fine as 1x1 and as course as 20x20.
91+
The Ronin Scrambler, the basic scanner, and `SceneMan:CastUnseenRay` have been changed to accomodate fog-of-war resolutions as fine as 1x1 and as coarse as 20x20.
6392
The fog-of-war revealing code is now multithreaded to increase performance.
6493

6594
- All vanilla scenario activities have had their settings polished, respecting settings which make sense and disabling settings which don't.
@@ -81,7 +110,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
81110

82111
- The `LimbPath` property `NormalTravelSpeed` has been renamed to just `TravelSpeed`.
83112

84-
- Almost all ctrl+* special inputs functionality (i.e restarting activity, world dumps, showing performance stats) are now mapped to right alt, to not interfere with default crouching inputs. The only exception is ctrl+arrow keys for changing console size.
113+
- `GameActivity` INI properties `TeamNTech` values switched to lazy eval, allowing them to be validated once all modules are loaded.
114+
As well, the scenario menu activity configuration screen now respects defaults set in INI, where possible.
115+
116+
- Internal GUI element `ComboBox` no longer displays dropdown combobutton when disabled, to communicate visually that it's setting is not modifiable.
117+
118+
- Almost all ctrl+\* special inputs functionality (i.e restarting activity, world dumps, showing performance stats) are now mapped to right alt, to not interfere with default crouching inputs. The only exception is ctrl+arrow keys for changing console size.
119+
120+
- `Gib`s and detached `Attachable`s now inherit the parent's angular velocity by default.
121+
122+
- `InheritsVel` now accounts for the angular velocity of the parent MO, resulting in offset gibs and emissions being flung further away.
123+
124+
- `InheritsVel` and its ilk have been uncapped, allowing users to set them outside of 0-1.
125+
126+
- `Scene` Lua functions `AddNavigatableArea(areaName)` and `ClearNavigatableAreas()` have been renamed/corrected to `AddNavigableArea(areaName)` and `ClearNavigableAreas()`, respectively.
127+
128+
- `MOSRotating` Lua function `AddWound` now additionally accepts the format `MOSRotating:AddWound(AEmitter* woundToAdd, const Vector& parentOffsetToSet, bool checkGibWoundLimit, bool isEntryWound, bool isExitWound)`, allowing modders to specify added wounds as entry- or exit wounds, for the purpose of not playing multiple burst sounds on the same frame. These new arguments are optional.
129+
130+
- Techion Laser Rifle now has a constant range rather than being dependent on game resolution.
131+
132+
- Various performance improvements.
85133

86134
</details>
87135

@@ -99,6 +147,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
99147

100148
- Fixed an issue where an `Actor`'s MovementState wasn't correctly accessible from script.
101149

150+
- Fixed mounted HeldDevices not respecting InheritedRotAngleOffset.
151+
152+
- Fixed an issue where internal Lua functions OriginalDoFile, OriginalLoadFile, and OriginalRequire were polluting the global namespace. They have now been made inaccessible.
153+
154+
- Various fixes and improvements to inventory management when dual-wielding or carrying a shield, to stop situations where the actor unexpectedly puts their items away.
155+
156+
- Fixed issue where MOSR `Gib`s, `AEmitter` or `PEmitter` `Emission`s, and MetaMan `Player`s were not correctly accessible from script.
157+
158+
- Fixed a crash on launch when the `SupportedGameVersion` INI property was not set.
159+
102160
</details>
103161

104162
<details><summary><b>Removed</b></summary>
@@ -108,6 +166,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
108166

109167
- The Signal Hunt activity no longer has a preview image, as it was not formatted correctly and spoiled the interior structure of the cave.
110168

169+
- Removed `GAScripted` Lua script method `SceneTest()` as the new Lua function `IsCompatibleScene(scene)` is more capable.
170+
Removed `GAScripted` C++ functionality that would scan the Lua script file to determine which areas are required. `AddRequiredArea` in the INI should be used instead.
171+
Removed `Scene` Lua function `GetOptionalArea` as it functioned identically to `GetArea` aside from triggering the aforementioned (and now removed) Lua script file scanning.
172+
111173
- Removed `AHuman` property `MaxCrouchRotation`. `CrouchRotAngleTarget` is now used instead.
112174

113175
- Deprecated `LimbPath` properties `SlowTravelSpeed`, `NormalTravelSpeed` and `FastTravelSpeed`. For the sake of backwards compatibility they will not crash the game and `NormalTravelSpeed` is a valid synonym for the new `TravelSpeed`.
@@ -2625,7 +2687,7 @@ This can be accessed via the new Lua (R/W) `SettingsMan` property `AIUpdateInter
26252687

26262688
- `TDExplosive.ActivatesWhenReleased` now works properly.
26272689

2628-
- Various bug fixed related to all the Attachable and Emitter changes, so they can now me affected reliably and safely with lua.
2690+
- Various bugs fixed related to all the Attachable and Emitter changes, so they can again be affected reliably and safely with lua.
26292691

26302692
- Various minor other things that have gotten lost in the shuffle.
26312693

Data/Base.rte/AI/SharedBehaviors.lua

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@ function SharedBehaviors.GoToWpt(AI, Owner, Abort)
848848
end
849849
else
850850
-- do we have a target we want to shoot at?
851-
if (AI.Target and AI.canHitTarget and AI.BehaviorName ~= "AttackTarget") then
851+
if Owner.Head and AI.Target and AI.canHitTarget and AI.BehaviorName ~= "AttackTarget" then
852852
-- are we also flying
853853
if AI.flying and Owner.Jetpack.JetpackType == AEJetpack.Standard then
854854
-- predict jetpack movement when jumping and there is a target (check one direction)
@@ -864,28 +864,28 @@ function SharedBehaviors.GoToWpt(AI, Owner, Abort)
864864

865865
-- test jumping
866866
local JetAccel = Accel + Vector(-jetStrength, 0):RadRotate(Owner.RotAngle+1.375*math.pi+Owner:GetAimAngle(false)*0.25);
867-
local JumpPos = Owner.Head.Pos + PixelVel + JetAccel * (t*t*0.5);
867+
local JumpPos = (Owner.Head and Owner.Head.Pos or Owner.Pos) + PixelVel + JetAccel * (t*t*0.5);
868868

869869
-- a burst add a one time boost to acceleration
870870
if Owner.Jetpack:CanTriggerBurst() then
871871
JumpPos = JumpPos + Vector(-AI.jetBurstFactor, 0):AbsRotateTo(JetAccel);
872872
end
873873

874874
-- check for obstacles from the head
875-
Trace = SceneMan:ShortestDistance(Owner.Head.Pos, JumpPos, false);
876-
local jumpScore = SceneMan:CastObstacleRay(Owner.Head.Pos, Trace, JumpPos, Vector(), Owner.ID, Owner.IgnoresWhichTeam, rte.grassID, 3);
875+
Trace = SceneMan:ShortestDistance((Owner.Head and Owner.Head.Pos or Owner.Pos), JumpPos, false);
876+
local jumpScore = SceneMan:CastObstacleRay((Owner.Head and Owner.Head.Pos or Owner.Pos), Trace, JumpPos, Vector(), Owner.ID, Owner.IgnoresWhichTeam, rte.grassID, 3);
877877
if jumpScore < 0 then -- no obstacles: calculate the distance from the future pos to the wpt
878878
jumpScore = SceneMan:ShortestDistance(Waypoint.Pos, JumpPos, false).Magnitude;
879879
else -- the ray hit terrain or start inside terrain: avoid
880880
jumpScore = SceneMan:ShortestDistance(Waypoint.Pos, JumpPos, false).Largest * 2;
881881
end
882882

883883
-- test falling
884-
local FallPos = Owner.Head.Pos + PixelVel + Accel * (t*t*0.5);
884+
local FallPos = (Owner.Head and Owner.Head.Pos or Owner.Pos) + PixelVel + Accel * (t*t*0.5);
885885

886886
-- check for obstacles when falling/walking
887-
local Trace = SceneMan:ShortestDistance(Owner.Head.Pos, FallPos, false);
888-
SceneMan:CastObstacleRay(Owner.Head.Pos, Trace, FallPos, Vector(), Owner.ID, Owner.IgnoresWhichTeam, rte.grassID, 3);
887+
local Trace = SceneMan:ShortestDistance((Owner.Head and Owner.Head.Pos or Owner.Pos), FallPos, false);
888+
SceneMan:CastObstacleRay((Owner.Head and Owner.Head.Pos or Owner.Pos), Trace, FallPos, Vector(), Owner.ID, Owner.IgnoresWhichTeam, rte.grassID, 3);
889889

890890
if SceneMan:ShortestDistance(Waypoint.Pos, FallPos, false):MagnitudeIsLessThan(jumpScore) then
891891
AI.jump = false;

Data/Base.rte/Activities.ini

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ AddActivity = GAScripted
5757
RequireClearPathToOrbitSwitchEnabled = 1
5858
FogOfWarSwitchEnabled = 1
5959
DeployUnitsSwitchEnabled = 1
60+
AddRequiredArea = Red Brain
61+
AddRequiredArea = Green Brain
6062
6163
6264
AddActivity = GAScripted
@@ -109,6 +111,8 @@ AddActivity = GAScripted
109111
RequireClearPathToOrbitSwitchEnabled = 1
110112
FogOfWarSwitchEnabled = 1
111113
DeployUnitsSwitchEnabled = 1
114+
AddRequiredArea = LZ Attacker
115+
AddRequiredArea = Main Bunker
112116
113117
114118
AddActivity = GAScripted
@@ -126,6 +130,8 @@ AddActivity = GAScripted
126130
RequireClearPathToOrbitSwitchEnabled = 1
127131
FogOfWarSwitchEnabled = 1
128132
DeployUnitsSwitchEnabled = 1
133+
AddRequiredArea = LZ Team 1
134+
AddRequiredArea = LZ All
129135
130136
131137
AddActivity = GAScripted
@@ -149,6 +155,8 @@ AddActivity = GAScripted
149155
RequireClearPathToOrbitSwitchEnabled = 0
150156
FogOfWarSwitchEnabled = 1
151157
DeployUnitsSwitchEnabled = 1
158+
AddRequiredArea = LZ Team 1
159+
AddRequiredArea = LZ All
152160
153161
154162
AddActivity = GAScripted
@@ -172,7 +180,8 @@ AddActivity = GAScripted
172180
RequireClearPathToOrbitSwitchEnabled = 0
173181
FogOfWarSwitchEnabled = 1
174182
DeployUnitsSwitchEnabled = 1
175-
183+
AddRequiredArea = LZ Team 1
184+
AddRequiredArea = LZ All
176185
177186
178187
AddActivity = GAScripted
@@ -197,8 +206,9 @@ AddActivity = GAScripted
197206
RequireClearPathToOrbitSwitchEnabled = 0
198207
FogOfWarSwitchEnabled = 0
199208
DeployUnitsSwitchEnabled = 0
209+
AddRequiredArea = OneManArmyZeroGCompatibilityArea
210+
200211
201-
// Path to orbit guaranteed by currently being in orbit.
202212
AddActivity = GAScripted
203213
PresetName = One-Man Army (Diggers, 0-G)
204214
Description = Survive with only one unit and no backups in a Zero-G void! The enemy will only use diggers, but the harder the difficulty the less potent weaponry you start out with, and the longer you have to survive.
@@ -237,6 +247,8 @@ AddActivity = GAScripted
237247
RequireClearPathToOrbitSwitchEnabled = 1
238248
FogOfWarSwitchEnabled = 1
239249
DeployUnitsSwitchEnabled = 1
250+
AddRequiredArea = LZ Team 1
251+
AddRequiredArea = LZ All
240252
241253
242254
AddActivity = GAScripted
@@ -253,6 +265,8 @@ AddActivity = GAScripted
253265
RequireClearPathToOrbitSwitchEnabled = 1
254266
FogOfWarSwitchEnabled = 1
255267
DeployUnitsSwitchEnabled = 1
268+
AddRequiredArea = LZ Team 1
269+
AddRequiredArea = LZ All
256270
257271
258272
AddActivity = GAScripted
@@ -270,6 +284,8 @@ AddActivity = GAScripted
270284
RequireClearPathToOrbitSwitchEnabled = 0
271285
FogOfWarSwitchEnabled = 1
272286
DeployUnitsSwitchEnabled = 1
287+
AddRequiredArea = LZ Team 1
288+
AddRequiredArea = LZ All
273289
274290
275291
///////////////////////////////////////////////////////////////////////

Data/Base.rte/Activities/BunkerBreach.lua

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ function BunkerBreach:SetupDefenderBrains()
8484
end
8585

8686
defenderBrain = self:CreateBrainBot(self.defenderTeam);
87-
defenderBrain.Pos = SceneMan.Scene:GetOptionalArea("Brain"):GetCenterPoint();
87+
defenderBrain.Pos = SceneMan.Scene:GetArea("Brain"):GetCenterPoint();
8888
MovableMan:AddActor(defenderBrain);
8989
else
9090
-- Pick the defender brain randomly from among those created by deployments, then delete the others and clean up most of their guards.
@@ -99,7 +99,7 @@ function BunkerBreach:SetupDefenderBrains()
9999
table.remove(deploymentBrains, brainIndexToChoose);
100100

101101
if SceneMan.Scene:HasArea("Brain Chamber") then
102-
self.brainChamber = SceneMan.Scene:GetOptionalArea("Brain Chamber");
102+
self.brainChamber = SceneMan.Scene:GetArea("Brain Chamber");
103103
end
104104
for _, unchosenDeploymentBrain in pairs(deploymentBrains) do
105105
unchosenDeploymentBrain.ToDelete = true;
@@ -167,7 +167,7 @@ function BunkerBreach:SetupDefenderActors()
167167
for _, loadoutName in pairs({"Light", "Heavy", "Sniper", "Engineer", "Mecha", "Turret"}) do
168168
if SceneMan.Scene:HasArea(loadoutName .. " Defenders") then
169169
hasSpawnAreas = true;
170-
local defenderArea = SceneMan.Scene:GetOptionalArea(loadoutName .. " Defenders");
170+
local defenderArea = SceneMan.Scene:GetArea(loadoutName .. " Defenders");
171171
if defenderArea ~= nil then
172172
for defenderBox in defenderArea.Boxes do
173173
local guard;
@@ -226,7 +226,7 @@ end
226226

227227
function BunkerBreach:SetupDefenderInternalReinforcementAreas()
228228
if self.AI.isDefenderTeam then
229-
local internalReinforcementsArea = SceneMan.Scene:GetOptionalArea("Internal Reinforcements");
229+
local internalReinforcementsArea = SceneMan.Scene:GetArea("Internal Reinforcements");
230230
if internalReinforcementsArea ~= nil then
231231
self.AI.internalReinforcementsDoorParticle = CreateMOSRotating("Background Door", "Base.rte");
232232
self.AI.internalReinforcementPositions = {};
@@ -248,7 +248,7 @@ function BunkerBreach:StartActivity(isNewGame)
248248
local attackerLZ = SceneMan.Scene:GetArea("LZ Attacker");
249249
self:SetLZArea(self.attackerTeam, attackerLZ);
250250
if SceneMan.Scene:HasArea("LZ Defender") then
251-
self:SetLZArea(self.defenderTeam, SceneMan.Scene:GetOptionalArea("LZ Defender"));
251+
self:SetLZArea(self.defenderTeam, SceneMan.Scene:GetArea("LZ Defender"));
252252
end
253253
self.mainBunkerArea = SceneMan.Scene:GetArea("Main Bunker");
254254

Data/Base.rte/Activities/Siege.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ function Siege:StartActivity()
6565
--end
6666

6767
if SceneMan.Scene:HasArea("Brain") then
68-
playerBrainsLocation = SceneMan.Scene:GetOptionalArea("Brain"):GetCenterPoint();
68+
playerBrainsLocation = SceneMan.Scene:GetArea("Brain"):GetCenterPoint();
6969
else
7070
-- Look for a brain among actors created by the deployments
7171
for actor in MovableMan.AddedActors do
@@ -98,7 +98,7 @@ function Siege:StartActivity()
9898
end
9999

100100
if SceneMan.Scene:HasArea("Brain Chamber") then
101-
self.BrainChamber = SceneMan.Scene:GetOptionalArea("Brain Chamber");
101+
self.BrainChamber = SceneMan.Scene:GetArea("Brain Chamber");
102102

103103
-- Set all useless actors, i.e. those who should guard brain in the brain chamber but their brain is in another castle
104104
-- to delete themselves, because otherwise they are most likely to stand there for the whole battle and waste MOs
@@ -112,7 +112,7 @@ function Siege:StartActivity()
112112
end
113113

114114
if SceneMan.Scene:HasArea("Perimeter") then
115-
self.Perimeter = SceneMan.Scene:GetOptionalArea("Perimeter");
115+
self.Perimeter = SceneMan.Scene:GetArea("Perimeter");
116116
--print ("Perimeter defined");
117117
end
118118

Data/Base.rte/Activities/Utility/DeliveryCreationHandler.lua

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,23 @@ function DeliveryCreationHandler:CreateEliteSquad(team, squadCountOrTypeTable, s
10261026

10271027
end
10281028

1029+
function DeliveryCreationHandler:CreateCraft(team, forceRocketUsage)
1030+
1031+
local craftGroup = "Craft - Dropships";
1032+
if forceRocketUsage then
1033+
craftGroup = "Craft - Rockets";
1034+
end
1035+
presetName, createFunc, techName = self:SelectPresetByGroupPair(team, craftGroup, craftGroup, craftGroup, craftGroup);
1036+
1037+
local craft = _G[createFunc](presetName, techName);
1038+
craft.Team = team;
1039+
--print(craft)
1040+
1041+
local goldCost = ToSceneObject(craft):GetTotalValue(self.teamTechIDTable[team], 1);
1042+
1043+
return craft, goldCost
1044+
end
1045+
10291046
function DeliveryCreationHandler:CreateSquadWithCraft(team, forceRocketUsage, squadCountOrTypeTable, squadType)
10301047

10311048
local craftGroup = "Craft - Dropships";

0 commit comments

Comments
 (0)