Support for Carsten's Arty Spotter script (#357)

* Added Cartsens Arty Script

* Added Options to Arty script

Added all options and for configuration.

* Carstens Arty Spotter with options

* Finishing touch

---------

Co-authored-by: Raffson <Raffson@users.noreply.github.com>
This commit is contained in:
Turbolious 2024-07-01 14:43:17 -05:00 committed by GitHub
parent d0a1a01b12
commit d84a0ebc78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 787 additions and 1 deletions

View File

@ -90,5 +90,6 @@ Excellent lua scripts DCS Liberation/Retribution uses as plugins:
* For the JTAC feature, DCS Retribution embeds Ciribob's JTAC Autolase [script](https://github.com/ciribob/DCS-JTACAutoLaze).
* Walder's [Skynet-IADS](https://github.com/walder/Skynet-IADS) is used for Integrated Air Defense System.
* Carstens Arty Spotter https://www.digitalcombatsimulator.com/en/files/3339128/ is an amazing force multiplyer to drop the hammer on enemies.
Please also show some support to these projects !

View File

@ -20,7 +20,8 @@
* **[UX]** Allow changing squadrons in flight's edit dialog
* **[Cheats]** Sink/Resurrect carriers instead of showing an error during cheat-capture (use AWCD-cheat to add squadrons upon resurrection)
* **[UI/UX]** Allow changing conditions such as Time, Date & Weather
* * **[Modding]** Added support for Su-15 Flagon mod (v1.0)
* **[Modding]** Added support for Su-15 Flagon mod (v1.0)
* **[Plugins]** Support for Carsten's Arty Spotter script
## Fixes
* **[UI/UX]** A-10A flights can be edited again

View File

@ -0,0 +1,723 @@
-- Artillery Spotter script - Multiplayer version
-- by Carsten Gurk aka Don Rudi
-- Map for passing settings from Retribution
cg_arty_options = {
["user_fireDelay"] = 10,
["user_quantity"] = 20,
["user_spread"] = 50,
["user_spottingDistance"] = 15,
}
local version = "MP 1.2"
-- User configurable variables
local user_fireDelay = cg_arty_options.user_fireDelay -- time to impcat of the rounds
local user_quantity = cg_arty_options.user_quantity -- how many rounds will be fired in a fire for effect task
local user_spread = cg_arty_options.user_spread -- impact radius of the rounds during fire for effect
local user_spottingDistance = cg_arty_options.user_spottingDistance -- max allowable distance from player to target to prevent cheating. In kilometers.
local user_restrictByType = "" -- Restriction by type ("", "helo", etc.)
local user_restrictByUnitName = "" -- Restriction by unit name ("", "spotter", etc.), not case sensitive
local user_markerPrefix = "" -- Prefix for marker text, for instance "#arty"
-- end of user block
-- Script variables
local SINGLE_ROUND = false -- pilot called single round on marker (from F10 menu)
local artyCall = 0 -- pilot called arty (from F10 menu)
local artyRadius = user_spread -- Artillery Radius
local adjustRadius = 20 -- fire adjustment
local quantity = 1 -- Rounds expanded
local quantity_effect = user_quantity -- Rounds expanded during fire for effect
local tntEquivalent = 12 -- TNT equivalent for explosion
local fireDelay = user_fireDelay -- delay til artillery fires in seconds
local firstShotFired = true
local markerSet = false
local pos = { x = 0, y = 0, z = 0 }
local playerPos = { x = 0, y = 0, z = 0 }
local target = {}
local adjustX = 0
local adjustZ = 0
local adjustDistance = 0 -- Adjust fire (from F10 menu)
local adjustDirection = 0 -- Adjust fire (from F10 menu)
local position = ""
local markerText = ""
local artyTasks = {}
local menuItems = false
-- optional arty enabled user flag, for use in triggers, if the player wants to
trigger.action.setUserFlag( "artyEnabled", 1 )
-- select format of target coordinates MGRS or LAT/LONG
local outputFormat = "MGRS"
--local outputFormat = "LL"
-- set values selected by player through F10 menu
local function setValue( _valueType, _value, _initiatorName )
if _valueType == "arty" then
artyCall = _value
end
if _valueType == "dist" then
adjustDistance = _value
trigger.action.outText("Fire adjusted by "..adjustDistance.." meters", 10)
end
if _valueType == "dir" then
adjustDirection = _value
end
artyAction( _initiatorName )
end
-- Function to add F10 menu items for a specific group and store references
local function addMenuItems(groupId, initiatorName)
menuItems = true
local artyTask = artyTasks[initiatorName]
artyTask.ArtyMenu = missionCommands.addSubMenuForGroup(groupId, 'Artillery Commands')
artyTask.AdjustDistance = missionCommands.addSubMenuForGroup(groupId, 'Adjust distance', artyTask.ArtyMenu)
artyTask.AdjustDirection = missionCommands.addSubMenuForGroup(groupId, 'Adjust direction', artyTask.ArtyMenu)
artyTask.commands = {}
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'request single round', artyTask.ArtyMenu, function() setValue("arty", 1, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'request fire for effect', artyTask.ArtyMenu, function() setValue("arty", 2, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire by 20m', artyTask.AdjustDistance, function() setValue("dist", 20, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire by 50m', artyTask.AdjustDistance, function() setValue("dist", 50, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire by 100m', artyTask.AdjustDistance, function() setValue("dist", 100, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire by 200m', artyTask.AdjustDistance, function() setValue("dist", 200, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire by 500m', artyTask.AdjustDistance, function() setValue("dist", 500, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire North', artyTask.AdjustDirection, function() setValue("dir", 360, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire North-East', artyTask.AdjustDirection, function() setValue("dir", 45, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire East', artyTask.AdjustDirection, function() setValue("dir", 90, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire South-East', artyTask.AdjustDirection, function() setValue("dir", 135, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire South', artyTask.AdjustDirection, function() setValue("dir", 180, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire South-West', artyTask.AdjustDirection, function() setValue("dir", 225, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire West', artyTask.AdjustDirection, function() setValue("dir", 270, initiatorName) end)
artyTask.commands[#artyTask.commands + 1] = missionCommands.addCommandForGroup(groupId, 'adjust fire North-West', artyTask.AdjustDirection, function() setValue("dir", 315, initiatorName) end)
end
-- Function to remove F10 menu items for a specific group
local function removeMenuItems(initiatorName)
local artyTask = artyTasks[initiatorName]
if artyTask then
for _, command in ipairs(artyTask.commands) do
missionCommands.removeItemForGroup(artyTasks[initiatorName].groupID, command)
end
missionCommands.removeItemForGroup(artyTasks[initiatorName].groupID, artyTask.AdjustDistance)
missionCommands.removeItemForGroup(artyTasks[initiatorName].groupID, artyTask.AdjustDirection)
missionCommands.removeItemForGroup(artyTasks[initiatorName].groupID, artyTask.ArtyMenu)
end
menuItems = false
end
-- Calculate distance
local function getDist(_point1, _point2)
local xUnit = _point1.x
local yUnit = _point1.z
local xZone = _point2.x
local yZone = _point2.z
local xDiff = xUnit - xZone
local yDiff = yUnit - yZone
return math.sqrt(xDiff * xDiff + yDiff * yDiff)
end
-- Shelling Zone
local function shellZone ( _initiatorName )
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Arty Task Created - fire incoming "..quantity.." rounds", 10)
if artyCall == 1 then
artyRadius = 5
else
artyRadius = 50
end
local _shellPos = artyTasks[_initiatorName].pos
if firstShotFired == true then
_shellPos.x = _shellPos.x + adjustX
_shellPos.y = _shellPos.y
_shellPos.z = _shellPos.z + adjustZ
end
for i = 1, quantity do
-- Create a random offset within the given radius
local randomX = math.random(-artyRadius, artyRadius)
local randomZ = math.random(-artyRadius, artyRadius)
local strikePos = {
x = _shellPos.x + randomX,
y = _shellPos.y,
z = _shellPos.z + randomZ
}
-- Delay the shelling by 1 second for each shell
timer.scheduleFunction(function()
trigger.action.explosion(strikePos, tntEquivalent) -- Create an explosion at the target position with a predefined power
end, {}, timer.getTime() + i)
end
--[[
if firstShotFired == false then
addMenuItems ()
firstShotFired = true
end
]]--
end
-- MGRS conversion to LL to x,z
local function convertMGRStoPos ( _mrgs )
local lat, lon = coord.MGRStoLL( _mgrs )
local markerPos = coord.LLtoLO( lat, lon, 0 )
return markerPos
end
-- x,z coordinates conversion to LAT/LONG and MGRS
local function convertPos2Coord ( _pos, _reply )
local lat, lon, alt = coord.LOtoLL (_pos)
local lat_degrees = math.floor (lat)
local lat_minutes = (60 * (lat - lat_degrees))
local lat_seconds = math.floor(60 * (lat_minutes - math.floor(lat_minutes)))
lat_minutes = math.floor(lat_minutes)
local lon_degrees = math.floor (lon)
local lon_minutes = (60 * (lon - lon_degrees))
local lon_seconds = math.floor (60 * (lon_minutes - math.floor(lon_minutes)))
lon_minutes = math.floor(lon_minutes)
local coordStringLL = "N" .. lat_degrees .. " " .. lat_minutes .. " " ..lat_seconds.. " E".. lon_degrees .. " " .. lon_minutes .. " ".. lon_seconds
local targetMGRS = coord.LLtoMGRS(lat, lon)
targetMGRS.Easting = math.floor (( targetMGRS.Easting /10 ) + 0.5 )
targetMGRS.Northing = math.floor (( targetMGRS.Northing / 10 ) + 0.5 )
--local coordStringMGRS = targetMGRS.UTMZone.." "..targetMGRS.MGRSDigraph.." "..string.sub(targetMGRS.Easting, 1, -2).." "..string.sub(targetMGRS.Northing, 1, -2)
local coordStringMGRS = targetMGRS.UTMZone.." "..targetMGRS.MGRSDigraph.." "..targetMGRS.Easting.." "..targetMGRS.Northing
if outputFormat == "MGRS" then
coordString = coordStringMGRS
else
coordString = coordStringLL
end
-- return either formated string or MGRS coordinate
if _reply == "string" then
return coordString
elseif _reply == "pos" then
return targetMGRS
end
end
-- Who is the player
-- Function to determine which unit is controlled by the player
--[[
local function getPlayerControlledUnit()
local playerUnit = nil
-- Iterate through all coalitions and their respective player units
for coalitionID = 1, 2 do -- 1 = Red, 2 = Blue
local playerUnits = coalition.getPlayers(coalitionID)
for _, unit in ipairs(playerUnits) do
if unit and unit:getPlayerName() then
playerUnit = unit
break
end
end
if playerUnit then
break
end
end
return playerUnit
end
]]--
-- Check if user has created F10 map marker
artyAction = function ( _initiatorName )
-- Check Call for arty - 1 = single round, 2 = fire for effect
if artyCall == 1 or artyCall == 2 then
if MARKER_FOUND == true and artyTasks[_initiatorName] then
-- check if target is within 15km from player
--trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Arty action marker found.", 10)
--local _player = _initiator
local _playerPos = artyTasks[_initiatorName].playerPos
local _targetPos = artyTasks[_initiatorName].pos
local _dist = math.floor( getDist ( _targetPos, _playerPos ) / 10 ) / 100
if trigger.misc.getUserFlag( "artyEnabled" ) == 1 and _dist <= user_spottingDistance then
position = convertPos2Coord ( _targetPos, "string" )
if artyCall == 1 then
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Arty single round requested on "..position, 10)
quantity = 1
elseif artyCall == 2 then
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Arty fire for effect requested on "..position, 10)
quantity = quantity_effect
end
timer.scheduleFunction(shellZone, _initiatorName, timer.getTime() + fireDelay)
trigger.action.setUserFlag( "artyFired", 1 )
else
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Artillery not available", 10)
end
else
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Arty Requested Without Marker", 10)
end
artyCall = 0
end
-- Check Call for arty direction correction
if adjustDirection == 360 then
adjustX = adjustDistance
adjustZ = 0
artyRadius = 5
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Fire adjusted to the North", 10)
adjustDirection = 0
end
if adjustDirection == 45 then
adjustX = adjustDistance
adjustZ = adjustDistance
artyRadius = 5
adjustDirection = 0
end
if adjustDirection == 90 then
adjustX = 0
adjustZ = adjustDistance
artyRadius = 5
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Fire adjusted to the East", 10)
adjustDirection = 0
end
if adjustDirection == 135 then
adjustX = -adjustDistance
adjustZ = adjustDistance
artyRadius = 5
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Fire adjusted to the South-East", 10)
adjustDirection = 0
end
if adjustDirection == 180 then
adjustX = -adjustDistance
adjustZ = 0
artyRadius = 5
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Fire adjusted to the South", 10)
adjustDirection = 0
end
if adjustDirection == 225 then
adjustX = -adjustDistance
adjustZ = -adjustDistance
artyRadius = 5
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Fire adjusted to the South-West", 10)
adjustDirection = 0
end
if adjustDirection == 270 then
adjustX = 0
adjustZ = -adjustDistance
artyRadius = 5
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Fire adjusted meters to the West", 10)
adjustDirection = 0
end
if adjustDirection == 315 then
adjustX = adjustDistance
adjustZ = -adjustDistance
artyRadius = 5
trigger.action.outTextForUnit( artyTasks[_initiatorName].unitID, "Fire adjusted meters to the North-West", 10)
adjustDirection = 0
end
end
-- Main
trigger.action.outText("Arty spotter script "..version.." loaded", 10)
-- Map Marker Text - read and process
-- Function to remove spaces from a string
local function removeSpaces( _text )
_text = _text:gsub( " ", "" )
_text = _text:gsub( "-", "" )
return _text
end
-- Function to validate the structure of the MGRS coordinate
local function checkValidMGRS( _mgrs, len)
if len == 13 then
-- Pattern: 2 digits 1 letter UTM Zone, 2 letters MGRS Digraph, 4 digits Easting, 4 digits Northing
return _mgrs:match("^%d%d%u%u%u%d%d%d%d%d%d%d%d$")
elseif len == 10 then
-- Pattern: 2 letters MGRS Digraph, 4 digits Easting, 4 digits Northing
return _mgrs:match("^%u%u%d%d%d%d%d%d%d%d$")
elseif len == 8 then
-- Pattern: 4 digits Easting, 4 digits Northing
return _mgrs:match("^%d%d%d%d%d%d%d%d$")
else
return false
end
end
-- Function to validate and complete MGRS coordinates
local function processMGRS( _text, _playerPos, initiatorName )
local _cleanedText = string.upper( removeSpaces( _text ) )
local len = #_cleanedText
local _isValidMGRS = checkValidMGRS( _cleanedText, len)
if _isValidMGRS then
trigger.action.outTextForUnit( artyTasks[initiatorName].unitID, "Processing MGRS: " .. _cleanedText, 10)
if len == 13 then
-- Complete MGRS coordinate
return _cleanedText
elseif len == 10 then
-- Add UTM Zone based on player position
local _utmZone = coord.LLtoMGRS(_playerPos.Lat, _playerPos.Lon).UTMZone
return _utmZone .. _cleanedText
elseif len == 8 then
-- Add UTM Zone and MGRS Digraph based on player position
local _mgrs = coord.LLtoMGRS( _playerPos.Lat, _playerPos.Lon )
return _mgrs.UTMZone .. _mgrs.MGRSDigraph .. _cleanedText
else
-- Invalid MGRS coordinate
return nil
end
else
trigger.action.outTextForUnit( artyTasks[initiatorName].unitID, "Invalid text input: " .. _cleanedText, 10)
return nil
end
end
-- Function to convert a valid MGRS to vec3
local function MGRStoVec3( _mgrs )
local lat, lon = coord.MGRStoLL( _mgrs )
local vec3 = coord.LLtoLO( lat, lon, 0 )
return vec3
end
-- Function to check if the initiator is valid based on restrictions
local function isValidInitiator(initiator)
if not initiator then return false end
-- Check type restriction
if user_restrictByType == "helo" then
if not initiator:getDesc().category == Unit.Category.Helicopter then
return false
end
end
-- Check name restriction
if user_restrictByUnitName ~= "" then
local name = initiator:getName():lower()
if not name:find(user_restrictByUnitName:lower()) then
return false
end
end
return true
end
-- Function to check if the marker text has the required prefix and remove it
local function checkAndRemovePrefix(text)
if user_markerPrefix ~= "" and text:sub(1, #user_markerPrefix) == user_markerPrefix then
return true, text:sub(#user_markerPrefix + 1)
elseif user_markerPrefix == "" then
return true, text
else
return false, text
end
end
-- Event handler for map marker creation
local function onPlayerAddMarker(event)
if event.id == world.event.S_EVENT_MARK_ADDED and user_markerPrefix == "" then
if isValidInitiator(event.initiator) then
--local hasPrefix, cleanedText = checkAndRemovePrefix(event.text)
hasPrefix = true
if hasPrefix then
MARKER_FOUND = true
pos = event.pos
if event.initiator then
local initiatorName = event.initiator:getName()
local playerUnit = event.initiator
local playerPos = playerUnit:getPoint()
-- Store position
if not artyTasks[initiatorName] then
artyTasks[initiatorName] = {}
end
trigger.action.outTextForUnit( event.initiator:getID(), "Marker added", 5)
artyTasks[initiatorName].playerPos = playerPos
artyTasks[initiatorName].pos = pos
artyTasks[initiatorName].unitID = event.initiator:getID()
-- Add menu items for the initiator's group
local groupId = event.initiator:getGroup():getID()
artyTasks[initiatorName].groupID = groupId
if menuItems == false then
addMenuItems(groupId, initiatorName)
end
end
end
else
--trigger.action.outText("You do not have permission to add a marker.", 5)
end
elseif event.id == world.event.S_EVENT_MARK_CHANGE then
if isValidInitiator(event.initiator) then
local hasPrefix, cleanedText = checkAndRemovePrefix(event.text)
if hasPrefix then
MARKER_FOUND = true
local markText = cleanedText
trigger.action.outText("Text: "..markText, 10)
if markText and event.initiator then
local initiatorName = event.initiator:getName()
local playerUnit = event.initiator
if not artyTasks[initiatorName] then
artyTasks[initiatorName] = {}
end
artyTasks[initiatorName].initiator = event.initiator
artyTasks[initiatorName].unitID = event.initiator:getID()
trigger.action.outTextForUnit( event.initiator:getID(), "Marker changed", 5)
if playerUnit then
local playerPos = playerUnit:getPoint()
local lat, lon = coord.LOtoLL(playerPos)
local playerPosition = { Lat = lat, Lon = lon }
local validMGRS = processMGRS(markText, playerPosition, initiatorName)
if validMGRS then
trigger.action.outTextForUnit( artyTasks[initiatorName].unitID, "Valid MGRS: " .. validMGRS, 10)
local tmpMGRS = {
UTMZone = string.sub(validMGRS, 1, 3),
MGRSDigraph = string.sub(validMGRS, 4, 5),
Easting = tonumber(string.sub(validMGRS, 6, 9)) * 10,
Northing = tonumber(string.sub(validMGRS, 10, 13)) * 10
}
local targetPoint = MGRStoVec3(tmpMGRS)
targetPoint.y = land.getHeight({ x = targetPoint.x, y = targetPoint.z })
artyTasks[initiatorName].pos = targetPoint
artyTasks[initiatorName].playerPos = playerPos
else
trigger.action.outTextForUnit( artyTasks[initiatorName].unitID, "Invalid MGRS coordinate entered.", 10)
end
local groupId = event.initiator:getGroup():getID()
artyTasks[initiatorName].groupID = groupId
if menuItems == false then
addMenuItems(groupId, initiatorName)
end
end
end
end
else
--trigger.action.outText("You do not have permission to change this marker.", 5)
end
elseif event.id == world.event.S_EVENT_MARK_REMOVED then
trigger.action.outText("Marker removed", 5)
if event.initiator then
local initiatorName = event.initiator:getName()
if artyTasks[initiatorName] then
removeMenuItems(initiatorName)
artyTasks[initiatorName] = nil
end
end
end
end
-- Register the event handler
local eventHandler = { f = onPlayerAddMarker }
function eventHandler:onEvent(e)
self.f(e)
end
world.addEventHandler(eventHandler)

View File

@ -0,0 +1,22 @@
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- configuration file for Carsten's Arty Spotter Plugin
--
-- This configuration is tailored for a mission generated by DCS Retribution
-- see https://github.com/dcs-retribution/dcs-retribution
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- arty plugin - configuration
if dcsRetribution then
-- retrieve specific options values
if dcsRetribution.plugins then
if dcsRetribution.plugins.arty then
env.info("DCSRetribution|Carsten's Arty Spotter plugin - Setting Up")
cg_arty_options.user_fireDelay = dcsRetribution.plugins.arty.user_fireDelay
cg_arty_options.user_quantity = dcsRetribution.plugins.arty.user_quantity
cg_arty_options.user_spread = dcsRetribution.plugins.arty.user_spread
cg_arty_options.user_spottingDistance = dcsRetribution.plugins.arty.user_spottingDistance
end
end
end

View File

@ -0,0 +1,38 @@
{
"nameInUI": "Carsten's Arty Spotter",
"defaultValue": false,
"specificOptions": [
{
"nameInUI": "Time to impcat of the rounds",
"mnemonic": "user_fireDelay",
"defaultValue": 15
},
{
"nameInUI": "Salvo quantity",
"mnemonic": "user_quantity",
"defaultValue": 5
},
{
"nameInUI": "Impact radius",
"mnemonic": "user_spread",
"defaultValue": 150
},
{
"nameInUI": "Max spotting distance. In kilometers.",
"mnemonic": "user_spottingDistance",
"defaultValue": 15
}
],
"scriptsWorkOrders": [
{
"file": "CG_ArtySpotter_V1_2a_MP.lua",
"mnemonic": "arty"
}
],
"configurationWorkOrders": [
{
"file": "arty-config.lua",
"mnemonic": "arty-config"
}
]
}

View File

@ -1,6 +1,7 @@
[
"base",
"ctld",
"arty",
"dismounts",
"ewrj",
"ewrs",