Migrate all commands to new lib

This commit is contained in:
Cooldude2606
2024-11-08 12:59:46 +00:00
parent c9bf85835f
commit 4b6872c14c
103 changed files with 2415 additions and 3694 deletions

View File

@@ -1,15 +1,19 @@
--[[-- Command Authorities - Roles
Adds a permission authority for exp roles
]]
local Commands = require("modules/exp_commands")
local add, allow, deny = Commands.add_permission_authority, Commands.status.success, Commands.status.unauthorised
local Roles = require("modules/exp_legacy/expcore/roles")
local player_allowed = Roles.player_allowed
local authorities = {}
--- If a command has the flag "character_only" then the command can only be used outside of remote view
authorities.exp_permission =
add(function(player, command)
if not Roles.player_allowed(player, command.flags.exp_permission or ("command/" .. command)) then
if not player_allowed(player, command.flags.exp_permission or ("command/" .. command)) then
return deny{ "exp-commands-authorities_role.deny" }
else
return allow()

View File

@@ -0,0 +1,12 @@
--[[-- Command Rcon - ExpCore
Adds rcon interfaces for the legacy exp core
]]
local Commands = require("modules/exp_commands")
local add_static, add_dynamic = Commands.add_rcon_static, Commands.add_rcon_dynamic
add_static("Group", require("modules.exp_legacy.expcore.permission_groups"))
add_static("Roles", require("modules.exp_legacy.expcore.roles"))
add_static("Gui", require("modules.exp_legacy.expcore.gui"))
add_static("Datastore", require("modules.exp_legacy.expcore.datastore"))
add_static("External", require("modules.exp_legacy.expcore.external"))

View File

@@ -16,20 +16,13 @@ local valid, invalid = Commands.status.success, Commands.status.invalid_input
local Roles = require("modules.exp_legacy.expcore.roles")
local highest_role = Roles.get_player_highest_role
local key_of_roles = Commands.types.key_of(Roles.config.roles)
local types = {}
local types = {} --- @class Commands._types
--- A role defined by exp roles
--- @type Commands.InputParser
types.role =
add("role", function(input, player)
local _, status, rtn = parse(input, player, key_of_roles)
return status, rtn
end)
types.role = add("role", Commands.types.key_of(Roles.config.roles))
--- A role which is lower than the players highest role
--- @type Commands.InputParser
types.lower_role =
add("lower_role", function(input, player)
local success, status, result = parse(input, player, types.role)
@@ -45,7 +38,6 @@ types.lower_role =
end)
--- A player who is of a lower role than the executing player
--- @type Commands.InputParser
types.lower_role_player =
add("lower_role_player", function(input, player)
local success, status, result = parse(input, player, Commands.types.player)
@@ -62,9 +54,8 @@ types.lower_role_player =
end)
--- A player who is of a lower role than the executing player
--- @type Commands.InputParser
types.lower_role_player_online =
add("lower_role_player", function(input, player)
add("lower_role_player_online", function(input, player)
local success, status, result = parse(input, player, Commands.types.player_online)
if not success then return status, result end
--- @cast result LuaPlayer
@@ -80,7 +71,7 @@ types.lower_role_player_online =
--- A player who is of a lower role than the executing player
types.lower_role_player_alive =
add("lower_role_player", function(input, player)
add("lower_role_player_alive", function(input, player)
local success, status, result = parse(input, player, Commands.types.player_alive)
if not success then return status, result end
--- @cast result LuaPlayer

View File

@@ -0,0 +1,22 @@
--[[-- Commands - Admin Chat
Adds a command that allows admins to talk in a private chat
]]
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
--- Sends a message in chat that only admins can see
Commands.new("admin-chat", { "exp-commands_admin-chat.description" })
:argument("message", { "exp-commands_admin-chat.arg-message" }, Commands.types.string)
:enable_auto_concatenation()
:add_aliases{ "ac" }
:add_flags{ "admin_only" }
:register(function(player, message)
--- @cast message string
local player_name = format_player_name(player)
for _, next_player in ipairs(game.connected_players) do
if next_player.admin then
next_player.print{ "exp-commands_admin-chat.format", player_name, message }
end
end
end)

View File

@@ -0,0 +1,96 @@
--[[-- Commands - Artillery
Adds a command that helps shoot artillery
]]
local AABB = require("modules/exp_util/aabb")
local Commands = require("modules/exp_commands")
local Selection = require("modules.exp_legacy.modules.control.selection") --- @dep modules.control.selection
local SelectionName = "ExpCommand_Artillery"
local floor = math.floor
local abs = math.abs
--- @param player LuaPlayer
--- @param area BoundingBox
--- @return boolean
local function location_break(player, area)
local surface = player.surface -- Allow remote view
local is_charted = player.force.is_chunk_charted
if is_charted(surface, { x = floor(area.left_top.x / 32), y = floor(area.left_top.y / 32) }) then
return true
elseif is_charted(surface, { x = floor(area.left_top.x / 32), y = floor(area.right_bottom.y / 32) }) then
return true
elseif is_charted(surface, { x = floor(area.right_bottom.x / 32), y = floor(area.left_top.y / 32) }) then
return true
elseif is_charted(surface, { x = floor(area.right_bottom.x / 32), y = floor(area.right_bottom.y / 32) }) then
return true
else
return false
end
end
--- Toggle player selection mode for artillery
Commands.new("artillery", { "exp-commands_artillery.description" })
:register(function(player)
if Selection.is_selecting(player, SelectionName) then
Selection.stop(player)
return Commands.status.success{ "exp-commands_artillery.exit" }
else
Selection.start(player, SelectionName)
return Commands.status.success{ "exp-commands_artillery.enter" }
end
end)
--- when an area is selected to add protection to the area
Selection.on_selection(SelectionName, function(event)
--- @cast event EventData.on_player_selected_area
local area = AABB.expand(event.area)
local player = game.players[event.player_index]
local surface = event.surface
if not (player.cheat_mode or location_break(player, event.area)) then
player.print{ "exp-commands_artillery.invalid_area" }
return
end
local entities = surface.find_entities_filtered{
area = area,
type = { "unit-spawner", "turret" },
force = "enemy"
}
local count = 0
local hits = {} --- @type MapPosition[]
for _, entity in ipairs(entities) do
local skip = false
for _, pos in ipairs(hits) do
local x = abs(entity.position.x - pos.x)
local y = abs(entity.position.y - pos.y)
if x * x + y * y < 36 then
skip = true
break
end
end
if not skip then
surface.create_entity{
name = "artillery-flare",
position = entity.position,
force = player.force,
life_time = 240,
movement = { 0, 0 },
height = 0,
vertical_speed = 0,
frame_speed = 0
}
count = count + 1
hits[count] = entity.position
if count > 400 then
break
end
end
end
end)

View File

@@ -0,0 +1,28 @@
--[[-- Commands - Bot queue
Adds a command that allows viewing and changing the construction queue limits
]]
local Commands = require("modules/exp_commands")
--- Get / Set the current values for the bot queue
Commands.new("bot-queue", { "exp-commands_bot-queue.description" })
:optional("amount", { "exp-commands_bot-queue.arg-amount" }, Commands.types.integer_range(1, 20))
:add_flags{ "admin_only" }
:register(function(player, amount)
if amount then
player.force.max_successful_attempts_per_tick_per_construction_queue = 3 * amount
player.force.max_failed_attempts_per_tick_per_construction_queue = 5 * amount
game.print{
"exp-commands_bot-queue.set",
player.force.max_successful_attempts_per_tick_per_construction_queue,
player.force.max_failed_attempts_per_tick_per_construction_queue,
}
return Commands.status.success()
end
return Commands.status.success{
"exp-commands_bot-queue.get",
player.force.max_successful_attempts_per_tick_per_construction_queue,
player.force.max_failed_attempts_per_tick_per_construction_queue,
}
end)

View File

@@ -0,0 +1,132 @@
--[[-- Commands - Cheats
Adds commands for cheating such as unlocking all technology or settings always day
]]
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
--- Toggles cheat mode for your player, or another player.
Commands.new("set-cheat-mode", { "exp-commands_cheat.description-cheat-mode" })
:optional("state", { "exp-commands_cheat.arg-state" }, Commands.types.boolean)
:optional("player", { "exp-commands_cheat.arg-player" }, Commands.types.player)
:add_aliases{ "cheat-mode", "toggle-cheat-mode" }
:add_flags{ "admin_only" }
:defaults{
player = function(player) return player end,
}
:register(function(player, state, other_player)
--- @cast state boolean?
--- @cast player LuaPlayer
if state == nil then
other_player.cheat_mode = not other_player.cheat_mode
else
other_player.cheat_mode = state
end
return Commands.status.success{ "exp-commands_cheat.cheat-mode", other_player.cheat_mode }
end)
--- Toggle always day for your surface, or another
Commands.new("set-always-day", { "exp-commands_cheat.description-always-day" })
:optional("state", { "exp-commands_cheat.arg-state" }, Commands.types.boolean)
:optional("surface", { "exp-commands_cheat.arg-surface" }, Commands.types.surface)
:add_aliases{ "always-day", "toggle-always-day" }
:add_flags{ "admin_only" }
:defaults{
surface = function(player) return player.surface end
}
:register(function(player, state, surface)
--- @cast state boolean?
--- @cast surface LuaSurface
if state == nil then
surface.always_day = not surface.always_day
else
surface.always_day = state
end
game.print{ "exp-commands_cheat.always-day", format_player_name(player), surface.localised_name, surface.always_day }
end)
--- Toggles friendly fire for your force or another
Commands.new("set-friendly-fire", { "exp-commands_cheat.description-friendly-fire" })
:optional("state", { "exp-commands_cheat.arg-state" }, Commands.types.boolean)
:optional("force", { "exp-commands_cheat.arg-force-friendly-fire" }, Commands.types.force)
:add_aliases{ "friendly-fire", "toggle-friendly-fire" }
:add_flags{ "admin_only" }
:defaults{
force = function(player) return player.force end
}
:register(function(player, state, force)
--- @cast state boolean?
--- @cast force LuaForce
if state == nil then
force.friendly_fire = not force.friendly_fire
else
force.friendly_fire = state
end
game.print{ "exp-commands_cheat.friendly-fire", format_player_name(player), force.name, force.friendly_fire }
end)
--- Research all technology on your force, or another force.
Commands.new("research-all", { "exp-commands_cheat.description-research-all" })
:optional("force", { "exp-commands_cheat.arg-force-research" }, Commands.types.force)
:add_flags{ "admin_only" }
:defaults{
force = function(player) return player.force end
}
:register(function(player, force)
--- @cast force LuaForce
force.research_all_technologies()
game.print{ "exp-commands_cheat.research-all", format_player_name(player), force.name }
return Commands.status.success()
end)
--- Clear all pollution from your surface or another
Commands.new("clear-pollution", { "exp-commands_cheat.description-clear-pollution" })
:optional("surface", { "exp-commands_cheat.arg-surface" }, Commands.types.surface)
:add_flags{ "admin_only" }
:defaults{
surface = function(player) return player.surface end -- Allow remote view
}
:register(function(player, surface)
--- @cast surface LuaSurface
surface.clear_pollution()
game.print{ "exp-commands_cheat.clear-pollution", format_player_name(player), surface.localised_name }
end)
--- Toggles pollution being enabled in the game
Commands.new("set-pollution-enabled", { "exp-commands_cheat.description-pollution-enabled" })
:optional("state", { "exp-commands_cheat.arg-state" }, Commands.types.boolean)
:add_aliases{ "disable-pollution", "toggle-pollution-enabled" }
:add_flags{ "admin_only" }
:register(function(player, state)
--- @cast state boolean?
if state == nil then
game.map_settings.pollution.enabled = not game.map_settings.pollution.enabled
else
game.map_settings.pollution.enabled = state
end
if game.map_settings.pollution.enabled == false then
for _, surface in pairs(game.surfaces) do
surface.clear_pollution()
end
end
game.print{ "exp-commands_cheat.pollution-enabled", format_player_name(player), game.map_settings.pollution.enabled }
end)
--- Set or get the game speed
Commands.new("set-game-speed", { "exp-commands_cheat.description-game-speed" })
:optional("amount", { "exp-commands_cheat.arg-amount" }, Commands.types.number_range(0.2, 10))
:add_aliases{ "game-speed" }
:add_flags{ "admin_only" }
:register(function(player, amount)
--- @cast amount number?
if amount then
game.speed = math.round(amount, 3)
local player_name = format_player_name(player)
game.print{ "exp-commands_cheat.game-speed-set", player_name, game.speed }
return Commands.status.success()
else
return Commands.status.success{ "exp-commands_cheat.game-speed-get", game.speed }
end
end)

View File

@@ -0,0 +1,26 @@
--[[-- Commands - Clear Inventory
Adds a command that allows admins to clear people's inventory
]]
local ExpUtil = require("modules/exp_util")
local transfer_inventory = ExpUtil.transfer_inventory_to_surface
local Commands = require("modules/exp_commands")
--- Clears a players inventory
Commands.new("clear-inventory", { "exp-commands_clear-inventory.description" })
:argument("player", { "exp-commands_clear-inventory.arg-player" }, Commands.types.lower_role_player)
:add_flags{ "admin_only" }
:register(function(player, other_player)
local inventory = other_player.get_main_inventory()
if not inventory then
return Commands.status.error{ "expcore-commands.reject-player-alive" }
end
transfer_inventory{
inventory = inventory,
surface = game.planets.nauvis.surface,
name = "iron-chest",
allow_creation = true,
}
end)

View File

@@ -0,0 +1,111 @@
--[[-- Commands - Connect
Adds a commands that allows you to request a player move to another server
]]
local Async = require("modules/exp_util/async")
local Commands = require("modules/exp_commands")
local External = require("modules.exp_legacy.expcore.external") --- @dep expcore.external
local request_connection_async = Async.register(External.request_connection)
local concat = table.concat
--- Convert a server name into a server id, is not an Commands.InputParser because it does not accept addresses
--- @param server string
--- @return boolean, LocalisedString # True for success
local function get_server_id(server)
local servers = External.get_servers_filtered(server)
local current_server = External.get_current_server()
local current_version = current_server.version
local server_names_before, server_names = {}, {}
local server_count_before, server_count = 0, 0
for next_server_id, server_details in pairs(servers) do
server_count_before = server_count_before + 1
server_names_before[server_count_before] = server_details.name
if server_details.version == current_version then
server_count = server_count + 1
server_names[server_count] = server_details.name
else
servers[next_server_id] = nil
end
end
if server_count > 1 then
return false, { "exp-commands_connect.too-many-matching", concat(server_names, ", ") }
elseif server_count == 1 then
local server_id, server_details = next(servers)
local status = External.get_server_status(server_id)
if server_id == current_server.id then
return false, { "exp-commands_connect.same-server", server_details.name }
elseif status == "Offline" then
return false, { "exp-commands_connect.offline", server_details.name }
end
return true, server_id
elseif server_count_before > 0 then
return false, { "exp-commands_connect.wrong-version", concat(server_names_before, ", ") }
else
return false, { "exp-commands_connect.none-matching" }
end
end
--- Connect to a different server
Commands.new("connect", { "exp-commands_connect.description" })
:argument("server", { "exp-commands_connect.arg-server" }, Commands.types.string)
:optional("is-address", { "exp-commands_connect.is-address" }, Commands.types.boolean)
:add_aliases{ "join" }
:register(function(player, server, is_address)
--- @cast server string
--- @cast is_address boolean?
if not is_address and External.valid() then
local success, result = get_server_id(server)
if not success then
return Commands.status.invalid_input(result)
end
server = result
end
request_connection_async(player, server, true)
end)
--- Connect another player to a different server
Commands.new("connect-player", { "exp-commands_connect.description-player" })
:argument("player", { "exp-commands_connect.arg-player" }, Commands.types.player_online)
:argument("server", { "exp-commands_connect.arg-server" }, Commands.types.string)
:optional("is-address", { "exp-commands_connect.is-address" }, Commands.types.boolean)
:add_flags{ "admin_only" }
:register(function(player, other_player, server, is_address)
--- @cast other_player LuaPlayer
--- @cast server string
--- @cast is_address boolean?
if not is_address and External.valid() then
local success, result = get_server_id(server)
if not success then
return Commands.status.invalid_input(result)
end
server = result
end
request_connection_async(other_player, server)
end)
--- Connect all players to a different server
Commands.new("connect-all", { "exp-commands_connect.description-all" })
:argument("server", { "exp-commands_connect.arg-server" }, Commands.types.string)
:optional("is-address", { "exp-commands_connect.is-address" }, Commands.types.boolean)
:add_flags{ "admin_only" }
:register(function(player, server, is_address)
--- @cast server string
--- @cast is_address boolean?
if not is_address and External.valid() then
local success, result = get_server_id(server)
if not success then
return Commands.status.invalid_input(result)
end
server = result
end
for _, next_player in pairs(game.connected_players) do
request_connection_async(next_player, server)
end
end)

View File

@@ -0,0 +1,10 @@
--[[-- Commands - Debug
Adds a command that opens the debug frame
]]
local DebugView = require("modules.exp_legacy.modules.gui.debug.main_view") --- @dep modules.gui.debug.main_view
local Commands = require("modules/exp_commands")
--- Opens the debug gui.
Commands.new("debug", { "exp-commands_debug.description" })
:register(DebugView.open_debug)

View File

@@ -0,0 +1,30 @@
--[[-- Commands - Enemy
Adds a commands of handling the enemy force, such as killing all or disabling them
]]
local Commands = require("modules/exp_commands")
--- Kill all enemies
Commands.new("kill-enemies", { "exp-commands_enemy.description-kill" })
:add_aliases{ "kill-biters" }
:add_flags{ "admin_only" }
:register(function(player)
game.forces["enemy"].kill_all_units()
game.print{ "exp-commands_enemy.kill", player.name }
end)
--- Remove all enemies on a surface
Commands.new("remove-enemies", { "exp-commands_enemy.description-remove" })
:optional("surface", { "exp-commands_enemy.arg-surface" }, Commands.types.surface)
:add_aliases{ "remove-biters" }
:add_flags{ "admin_only" }
:defaults{
surface = function(player) return player.surface end
}
:register(function(player, surface)
for _, entity in pairs(surface.find_entities_filtered{ force = "enemy" }) do
entity.destroy()
end
-- surface.map_gen_settings.autoplace_controls["enemy-base"].size = "none" -- TODO make this work for SA
game.print{ "exp-commands_enemy.remove", player.name }
end)

View File

@@ -0,0 +1,116 @@
--[[-- Commands - Home
Adds a command that allows setting and teleporting to your home position
]]
local ExpUtil = require("modules/exp_util")
local teleport = ExpUtil.teleport_player
local Commands = require("modules/exp_commands")
local Storage = require("modules/exp_util/storage")
--- @type table<number, table<number, [MapPosition?, MapPosition?]>>
local homes = {} -- homes[player_index][surface_index] = { home_pos, return_pos }
Storage.register(homes, function(tbl)
homes = tbl
end)
--- Align a position to the grid
--- @param position MapPosition The position to align
--- @return MapPosition, MapPosition
local function align_to_grid(position)
return {
x = math.floor(position.x) + math.sign(position.x) * 0.5,
y = math.floor(position.y) + math.sign(position.x) * 0.5,
}, {
x = math.floor(position.x),
y = math.floor(position.y),
}
end
--- Teleports you to your home location on the current surface
Commands.new("home", { "exp-commands_home.description-home" })
:add_flags{ "character_only" }
:register(function(player)
local surface = player.surface
local player_homes = homes[player.index]
if not player_homes then
return Commands.status.error{ "exp-commands_home.no-home", surface.localised_name }
end
local player_home = player_homes[surface.index]
if not player_home or not player_home[1] then
return Commands.status.error{ "exp-commands_home.no-home", surface.localised_name }
end
local return_position, floor_position = align_to_grid(player.position)
teleport(player, surface, player_home[1])
player_home[2] = return_position
return Commands.status.success{ "exp-commands_home.return-set", surface.localised_name, floor_position.x, floor_position.y }
end)
--- Teleports you to your previous location on the current surface
Commands.new("return", { "exp-commands_home.description-return" })
:add_flags{ "character_only" }
:register(function(player)
local surface = player.surface
local player_homes = homes[player.index]
if not player_homes then
return Commands.status.error{ "exp-commands_home.no-return", surface.localised_name }
end
local player_home = player_homes[surface.index]
if not player_home or not player_home[2] then
return Commands.status.error{ "exp-commands_home.no-return", surface.localised_name }
end
local return_position, floor_position = align_to_grid(player.position)
teleport(player, surface, player_home[2])
player_home[2] = return_position
return Commands.status.success{ "exp-commands_home.return-set", surface.localised_name, floor_position.x, floor_position.y }
end)
--- Sets your home location on your current surface to your current position
Commands.new("set-home", { "exp-commands_home.description-set" })
:add_flags{ "character_only" }
:register(function(player)
local home_position, floor_position = align_to_grid(player.position)
local surface = player.surface
local player_homes = homes[player.index]
if not player_homes then
homes[player.index] = {
[surface.index] = { home_position, nil }
}
return Commands.status.success{ "exp-commands_home.home-set", surface.localised_name, floor_position.x, floor_position.y }
end
local player_home = player_homes[surface.index]
if not player_home then
player_homes[surface.index] = { home_position, nil }
return Commands.status.success{ "exp-commands_home.home-set", surface.localised_name, floor_position.x, floor_position.y }
end
player_home[1] = home_position
return Commands.status.success{ "exp-commands_home.home-set", surface.localised_name, floor_position.x, floor_position.y }
end)
--- Gets your home location on your current surface, is allowed in remote view
Commands.new("get-home", { "exp-commands_home.description-get" })
:register(function(player)
local surface = player.surface
local player_homes = homes[player.index]
if not player_homes then
return Commands.status.error{ "exp-commands_home.no-home", surface.localised_name }
end
local player_home = player_homes[surface.index]
if not player_home or not player_home[1] then
return Commands.status.error{ "exp-commands_home.no-home", surface.localised_name }
end
local _, floor_position = align_to_grid(player_home[1])
return Commands.status.success{ "exp-commands_home.home-get", surface.localised_name, floor_position.x, floor_position.y }
end)

View File

@@ -0,0 +1,43 @@
--[[-- Commands - Jail
Adds a commands that allow admins to jail and unjail
]]
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail
--- Puts a player into jail and removes all other roles.
Commands.new("jail", { "exp-commands_jail.description" })
:argument("player", { "exp-commands_jail.arg-player" }, Commands.types.lower_role_player)
:optional("reason", { "exp-commands_jail.arg-reason" }, Commands.types.string)
:enable_auto_concatenation()
:register(function(player, other_player, reason)
--- @cast other_player LuaPlayer
--- @cast reason string?
if not reason then
reason = "None Given."
end
local player_name = format_player_name(player)
local other_player_name = format_player_name(other_player)
if Jail.jail_player(other_player, player.name, reason) then
game.print{ "exp-commands_jail.jailed", other_player_name, player_name, reason }
else
return Commands.status.error{ "exp-commands_jail.already-jailed", other_player_name }
end
end)
--- Removes a player from jail and restores their old roles.
Commands.new("unjail", { "exp-commands_unjail.description" })
:argument("player", { "exp-commands_unjail.arg-player" }, Commands.types.lower_role_player)
:register(function(player, other_player)
--- @cast other_player LuaPlayer
local player_name = format_player_name(player)
local other_player_name = format_player_name(other_player)
if Jail.unjail_player(other_player, player.name) then
game.print{ "exp-commands_unjail.unjailed", other_player_name, player_name }
else
return Commands.status.error{ "exp-commands_unjail.not-jailed", other_player_name }
end
end)

View File

@@ -0,0 +1,32 @@
--[[-- Commands - Kill
Adds a command that allows players to kill themselves and others
]]
local Commands = require("modules/exp_commands")
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
local highest_role = Roles.get_player_highest_role
--- Kills yourself or another player.
Commands.new("kill", { "exp-commands_kill.description" })
:optional("player", { "exp-commands_kill.arg-player" }, Commands.types.lower_role_player_alive)
:defaults{
player = function(player)
return player.character and player.character.health > 0 and player or nil
end
}
:register(function(player, other_player)
--- @cast other_player LuaPlayer?
if other_player == nil then
-- Can only be nil if the target is the player and they are already dead
return Commands.status.error{ "exp-commands_kill.already-dead" }
elseif other_player == player then
-- You can always kill yourself
other_player.character.die()
elseif highest_role(other_player).index < highest_role(player).index then
-- Can kill lower role players
other_player.character.die()
else
return Commands.status.unauthorised{ "exp-commands_kill.lower-role" }
end
end)

View File

@@ -0,0 +1,52 @@
--[[-- Commands - Lawnmower
Adds a command that clean up biter corpse and nuclear hole
]]
local Commands = require("modules/exp_commands")
local config = require("modules.exp_legacy.config.lawnmower") --- @dep config.lawnmower
Commands.new("lawnmower", { "exp-commands_lawnmower.description" })
:argument("range", { "exp-commands_lawnmower.arg-range" }, Commands.types.integer_range(1, 200))
:register(function(player, range)
--- @cast range number
local surface = player.surface
-- Intentionally left as player.position to allow use in remote view
local entities = surface.find_entities_filtered{ position = player.position, radius = range, type = "corpse" }
for _, entity in pairs(entities) do
if (entity.name ~= "transport-caution-corpse" and entity.name ~= "invisible-transport-caution-corpse") then
entity.destroy()
end
end
local replace_tiles = {}
local tiles = surface.find_tiles_filtered{ position = player.position, radius = range, name = { "nuclear-ground" } }
for i, tile in pairs(tiles) do
replace_tiles[i] = { name = "grass-1", position = tile.position }
end
surface.set_tiles(replace_tiles)
surface.destroy_decoratives{ position = player.position, radius = range }
end)
--- @param event EventData.on_built_entity | EventData.on_robot_built_entity | EventData.script_raised_built | EventData.script_raised_revive
local function destroy_decoratives(event)
local entity = event.entity
if entity.type ~= "entity-ghost" and entity.type ~= "tile-ghost" and entity.prototype.selectable_in_game then
entity.surface.destroy_decoratives{ area = entity.selection_box }
end
end
local e = defines.events
local events = {}
if config.destroy_decoratives then
events[e.on_built_entity] = destroy_decoratives
events[e.on_robot_built_entity] = destroy_decoratives
events[e.script_raised_built] = destroy_decoratives
events[e.script_raised_revive] = destroy_decoratives
end
return {
events = events
}

View File

@@ -0,0 +1,40 @@
--[[-- Commands - Locate
Adds a command that will return the last location of a player
]]
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
local format = string.format
--- Open remote view at a players last location
Commands.new("locate", { "exp-commands_locate.description" })
:add_aliases{ "last-location", "find" }
:argument("player", { "exp-commands_locate.arg-player" }, Commands.types.player)
:optional("remote", { "exp-commands_locate.arg-remote" }, Commands.types.boolean)
:register(function(player, other_player, remote)
--- @cast other_player LuaPlayer
--- @cast remote boolean?
local surface = other_player.physical_surface
local position = other_player.physical_position
if remote and other_player.controller_type == defines.controllers.remote then
surface = other_player.surface
position = other_player.position
end
if player.index > 0 then
-- This check allows rcon to use the command
player.set_controller{
type = defines.controllers.remote,
surface = surface,
position = position,
}
end
return Commands.status.success{
"exp-commands_locate.response",
format_player_name(other_player),
format("%.1f", position.x),
format("%.1f", position.y),
}
end)

View File

@@ -0,0 +1,14 @@
--[[-- Commands - Me
Adds a command that adds * around your message in the chat
]]
local Commands = require("modules/exp_commands")
local format_text = Commands.format_rich_text_color_locale
--- Sends an action message in the chat
Commands.new("me", { "exp-commands_me.description" })
:argument("action", { "exp-commands_me.arg-action" }, Commands.types.string)
:enable_auto_concatenation()
:register(function(player, action)
game.print(format_text({ "exp-commands_me.response", player.name, action, }, player.chat_color))
end)

View File

@@ -0,0 +1,239 @@
--[[-- Commands - Protection
Adds commands that can add and remove protection
]]
local Storage = require("modules/exp_util/storage")
local AABB = require("modules/exp_util/aabb")
local contains_area = AABB.contains_area
local expand_area = AABB.expand
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
local Selection = require("modules.exp_legacy.modules.control.selection") --- @dep modules.control.selection
local EntityProtection = require("modules.exp_legacy.modules.control.protection") --- @dep modules.control.protection
local format_string = string.format
local floor = math.floor
local SelectionName_Entity = "ExpCommand_ProtectEntity"
local SelectionName_Area = "ExpCommand_ProtectArea"
local renders = {} --- @type table<number, table<string, LuaRenderObject>> Stores all renders for a player
Storage.register({
renders = renders,
}, function(tbl)
renders = tbl.renders
end)
--- Get the key used in protected_entities
--- @param entity LuaEntity
--- @return string
local function get_entity_key(entity)
return format_string("%i,%i", floor(entity.position.x), floor(entity.position.y))
end
--- Get the key used in protected_areas
--- TODO expose this from EntityProtection
--- @param area BoundingBox
--- @return string
local function get_area_key(area)
return format_string("%i,%i", floor(area.left_top.x), floor(area.left_top.y))
end
--- Show a protected entity to a player
--- @param player LuaPlayer
--- @param entity LuaEntity
local function show_protected_entity(player, entity)
local key = get_entity_key(entity)
if renders[player.index][key] then return end
local rb = entity.selection_box.right_bottom
renders[player.index][key] = rendering.draw_sprite{
sprite = "utility/notification",
target = entity,
target_offset = {
(rb.x - entity.position.x) * 0.75,
(rb.y - entity.position.y) * 0.75,
},
x_scale = 2,
y_scale = 2,
surface = entity.surface,
players = { player },
}
end
--- Show a protected area to a player
--- @param player LuaPlayer
--- @param surface LuaSurface
--- @param area BoundingBox
local function show_protected_area(player, surface, area)
local key = get_area_key(area)
if renders[player.index][key] then return end
renders[player.index][key] = rendering.draw_rectangle{
color = { 1, 1, 0, 0.5 },
filled = false,
width = 3,
left_top = area.left_top,
right_bottom = area.right_bottom,
surface = surface,
players = { player },
}
end
--- Remove a render object for a player
--- @param player LuaPlayer
--- @param key string
local function remove_render(player, key)
local render = renders[player.index][key]
if render and render.valid then render.destroy() end
renders[player.index][key] = nil
end
--- Toggles entity protection selection
Commands.new("protect-entity", { "exp-commands_protection.description-entity" })
:add_aliases{ "pe" }
:register(function(player)
if Selection.is_selecting(player, SelectionName_Entity) then
Selection.stop(player)
return Commands.status.success{ "exp-commands_protection.exit-entity" }
else
Selection.start(player, SelectionName_Entity)
return Commands.status.success{ "exp-commands_protection.enter-entity" }
end
end)
--- Toggles area protection selection
Commands.new("protect-area", { "exp-commands_protection.description-area" })
:add_aliases{ "pa" }
:register(function(player)
if Selection.is_selecting(player, SelectionName_Entity) then
Selection.stop(player)
return Commands.status.success{ "exp-commands_protection.exit-area" }
else
Selection.start(player, SelectionName_Entity)
return Commands.status.success{ "exp-commands_protection.enter-area" }
end
end)
--- When an area is selected to add protection to entities
Selection.on_selection(SelectionName_Entity, function(event)
--- @cast event EventData.on_player_selected_area
local player = game.players[event.player_index]
for _, entity in ipairs(event.entities) do
EntityProtection.add_entity(entity)
show_protected_entity(player, entity)
end
player.print({ "exp-commands_protection.protected-entities", #event.entities }, Commands.print_settings.default)
end)
--- When an area is selected to remove protection from entities
Selection.on_alt_selection(SelectionName_Entity, function(event)
--- @cast event EventData.on_player_alt_selected_area
local player = game.players[event.player_index]
for _, entity in ipairs(event.entities) do
EntityProtection.remove_entity(entity)
remove_render(player, get_entity_key(entity))
end
player.print({ "exp-commands_protection.unprotected-entities", #event.entities }, Commands.print_settings.default)
end)
--- When an area is selected to add protection to the area
Selection.on_selection(SelectionName_Area, function(event)
--- @cast event EventData.on_player_selected_area
local surface = event.surface
local area = expand_area(event.area)
local areas = EntityProtection.get_areas(event.surface)
local player = game.players[event.player_index]
for _, next_area in pairs(areas) do
if contains_area(next_area, area) then
return player.print({ "exp-commands_protection.already-protected" }, Commands.print_settings.error)
end
end
EntityProtection.add_area(surface, area)
show_protected_area(player, surface, area)
player.print({ "exp-commands_protection.protected-area" }, Commands.print_settings.default)
end)
--- When an area is selected to remove protection from the area
Selection.on_alt_selection(SelectionName_Area, function(event)
--- @cast event EventData.on_player_alt_selected_area
local surface = event.surface
local area = expand_area(event.area)
local areas = EntityProtection.get_areas(surface)
local player = game.players[event.player_index]
for _, next_area in pairs(areas) do
if contains_area(area, next_area) then
EntityProtection.remove_area(surface, next_area)
player.print({ "exp-commands_protection.unprotected-area" }, Commands.print_settings.default)
remove_render(player, get_area_key(next_area))
end
end
end)
--- When selection starts show all protected entities and protected areas
local function on_player_selection_start(event)
if event.selection ~= SelectionName_Entity and event.selection ~= SelectionName_Area then return end
local player = game.players[event.player_index]
local surface = player.surface -- Allow remote view
renders[player.index] = {}
-- Show protected entities
local entities = EntityProtection.get_entities(surface)
for _, entity in pairs(entities) do
show_protected_entity(player, entity)
end
-- Show always protected entities by name
if #EntityProtection.protected_entity_names > 0 then
for _, entity in pairs(surface.find_entities_filtered{ name = EntityProtection.protected_entity_names, force = player.force }) do
show_protected_entity(player, entity)
end
end
-- Show always protected entities by type
if #EntityProtection.protected_entity_types > 0 then
for _, entity in pairs(surface.find_entities_filtered{ type = EntityProtection.protected_entity_types, force = player.force }) do
show_protected_entity(player, entity)
end
end
-- Show protected areas
local areas = EntityProtection.get_areas(surface)
for _, area in pairs(areas) do
show_protected_area(player, surface, area)
end
end
--- When selection ends hide protected entities and protected areas
local function on_player_selection_end(event)
if event.selection ~= SelectionName_Entity and event.selection ~= SelectionName_Area then return end
for _, render in pairs(renders[event.player_index]) do
if render.valid then render.destroy() end
end
renders[event.player_index] = nil
end
--- When there is a repeat offence print it in chat
local function on_repeat_violation(event)
Roles.print_to_roles_higher("Regular", {
"exp-commands_protection.repeat-offence",
format_player_name(event.player_index),
event.entity.localised_name,
event.entity.position.x,
event.entity.position.y
})
end
return {
events = {
[Selection.events.on_player_selection_start] = on_player_selection_start,
[Selection.events.on_player_selection_end] = on_player_selection_end,
[EntityProtection.events.on_repeat_violation] = on_repeat_violation,
}
}

View File

@@ -0,0 +1,112 @@
--[[-- Commands - Protected Tags
Adds a command that creates chart tags which can only be edited by admins
]]
local Commands = require("modules/exp_commands")
local Storage = require("modules/exp_util/storage")
--- Storage variables
local active_players = {} --- @type table<number, boolean> Stores all players in in protected mode
local map_tags = {} --- @type table<number, boolean> Stores all protected map tags
Storage.register({
active_players = active_players,
map_tags = map_tags,
}, function(tbl)
active_players = tbl.active_players
map_tags = tbl.map_tags
end)
--- Toggle admin marker mode, can only be applied to yourself
local cmd_protected_tag =
Commands.new("protected-tag", { "exp-commands_protected-tags.description" })
:add_aliases{ "ptag" }
:add_flags{ "admin_only" }
:register(function(player)
if active_players[player.index] then
active_players[player.index] = nil
return Commands.status.success{ "exp-commands_protected-tags.exit" }
else
active_players[player.index] = true
return Commands.status.success{ "exp-commands_protected-tags.enter" }
end
end)
--- When a player leaves the game, remove them from the active list
--- @param event EventData.on_player_left_game
local function on_player_left_game(event)
active_players[event.player_index] = nil
end
--- Add a chart tag as protected if the player is in protected mode
--- @param event EventData.on_chart_tag_added
local function on_chart_tag_added(event)
if not event.player_index then return end
if not active_players[event.player_index] then return end
local tag = event.tag
local player = game.players[event.player_index]
map_tags[tag.force.name .. tag.tag_number] = true
player.print{ "exp-commands_protected-tags.create" }
end
--- Stop a tag from being edited or removed
--- @param event EventData.on_chart_tag_modified | EventData.on_chart_tag_removed
local function on_chart_tag_removed_or_modified(event)
local tag = event.tag
if not event.player_index then return end
if not map_tags[tag.force.name .. tag.tag_number] then return end
local player = game.players[event.player_index]
-- Check if the player is in protected mode, and inform them that it was protected
if active_players[event.player_index] then
player.print{ "exp-commands_protected-tags.edit" }
return
end
-- Check how the changes need to be reverted
if event.name == defines.events.on_chart_tag_modified then
-- Tag was modified, revert the changes
tag.text = event.old_text
tag.icon = event.old_icon
tag.surface = event.old_surface
tag.position = event.old_position
if event.old_player_index then
tag.last_user = game.players[event.old_player_index]
else
tag.last_user = nil
end
else
-- Tag was removed, recreate the tag
local new_tag =
tag.force.add_chart_tag(tag.surface, {
last_user = tag.last_user,
position = tag.position,
icon = tag.icon,
text = tag.text,
})
--- @cast new_tag -nil
map_tags[tag.force.name .. tag.tag_number] = nil
map_tags[new_tag.force.name .. new_tag.tag_number] = true
end
if Commands.player_has_permission(player, cmd_protected_tag) then
-- Player is not in protected mode, but has access to the command
player.print({ "exp-commands_protected-tags.revert-has-access", cmd_protected_tag.name }, Commands.print_settings.error)
else
--- Player does not have access to protected mode
player.print({ "exp-commands_protected-tags.revert-no-access" }, Commands.print_settings.error)
end
end
local e = defines.events
return {
events = {
[e.on_chart_tag_added] = on_chart_tag_added,
[e.on_player_left_game] = on_player_left_game,
[e.on_chart_tag_modified] = on_chart_tag_removed_or_modified,
[e.on_chart_tag_removed] = on_chart_tag_removed_or_modified,
}
}

View File

@@ -0,0 +1,72 @@
--[[-- Commands - Rainbow
Adds a command that prints your message in rainbow font
]]
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
local format_text = Commands.format_rich_text_color
--- Wraps one component into the next
--- @param c1 number
--- @param c2 number
--- @return number, number
local function step_component(c1, c2)
if c1 < 0 then
return 0, c2 + c1
elseif c1 > 1 then
return 1, c2 - c1 + 1
else
return c1, c2
end
end
--- Wraps all components of a colour ensuring it remains valid
--- @param color Color
--- @return Color
local function step_color(color)
color.r, color.g = step_component(color.r, color.g)
color.g, color.b = step_component(color.g, color.b)
color.b, color.r = step_component(color.b, color.r)
color.r = step_component(color.r, 0)
return color
end
--- Get the next colour in the rainbow by the given step
--- @param color Color
--- @param step number
--- @return Color
local function next_color(color, step)
step = step or 0.1
local new_color = { r = 0, g = 0, b = 0 }
if color.b == 0 and color.r ~= 0 then
new_color.r = color.r - step
new_color.g = color.g + step
elseif color.r == 0 and color.g ~= 0 then
new_color.g = color.g - step
new_color.b = color.b + step
elseif color.g == 0 and color.b ~= 0 then
new_color.b = color.b - step
new_color.r = color.r + step
end
return step_color(new_color)
end
--- Sends an rainbow message in the chat
Commands.new("rainbow", { "exp-commands_rainbow" })
:argument("message", { "exp-commands_rainbow.arg-message" }, Commands.types.string)
:enable_auto_concatenation()
:register(function(player, message)
local color_step = 3 / message:len()
if color_step > 1 then color_step = 1 end
local current_color = { r = 1, g = 0, b = 0 }
game.print{
"exp-commands_rainbow.response",
format_player_name(player),
message:gsub("%S", function(letter)
local rtn = format_text(letter, current_color)
current_color = next_color(current_color, color_step)
return rtn
end)
}
end)

View File

@@ -0,0 +1,54 @@
--[[-- Commands - Ratio
Adds a command to calculate the number of machines needed to fulfil a desired production
]]
local Commands = require("modules/exp_commands")
Commands.new("ratio", { "exp-command_ratio.description" })
:optional("items-per-second", { "exp-command_ratio.arg-items-per-second" }, Commands.types.number)
:register(function(player, items_per_second)
--- @cast items_per_second number?
local machine = player.selected
if not machine then
return Commands.status.error{ "exp-command_ratio.not-selecting" }
end
if machine.type ~= "assembling-machine" and machine.type ~= "furnace" then
return Commands.status.error{ "exp-command_ratio.not-selecting" }
end
local recipe = machine.get_recipe()
if not recipe then
return Commands.status.error{ "exp-command_ratio.not-selecting" }
end
local products = recipe.products
local ingredients = recipe.ingredients
local crafts_per_second = machine.crafting_speed * machine.productivity_bonus / recipe.energy
local amount_of_machines = 1
if items_per_second then
amount_of_machines = math.ceil(products[1].amount * crafts_per_second)
end
for _, ingredient in ipairs(ingredients) do
Commands.print{
ingredient.type == "item" and "exp-command_ratio.item-out" or "exp-command_ratio.fluid-out",
math.round(ingredient.amount * crafts_per_second, 3),
ingredient.name
}
end
for i, product in ipairs(products) do
Commands.print{
product.type == "item" and "exp-command_ratio.item-out" or "exp-command_ratio.fluid-out",
math.round(product.amount * crafts_per_second, 3),
product.name
}
end
if amount_of_machines ~= 1 then
Commands.print{ "exp-command_ratio.machine-count", amount_of_machines }
end
end)

View File

@@ -0,0 +1,60 @@
--[[-- Commands - Repair
Adds a command that allows an admin to repair and revive a large area
]]
local Commands = require("modules/exp_commands")
local config = require("modules.exp_legacy.config.repair") --- @dep config.repair
local huge = math.huge
--- Repairs entities on your force around you
Commands.new("repair", { "exp-commands_repair.description" })
:argument("range", { "exp-commands_repair.arg-range" }, Commands.types.integer_range(1, config.max_range))
:register(function(player, range)
--- @cast range number
local force = player.force
local surface = player.surface -- Allow remote view
local position = player.position -- Allow remote view
local response = { "" } --- @type LocalisedString
if config.allow_ghost_revive then
local revive_count = 0
local entities = surface.find_entities_filtered{
type = "entity-ghost",
position = position,
radius = range,
force = force,
}
for _, entity in ipairs(entities) do
-- TODO test for ghost not being a blueprint, https://forums.factorio.com/viewtopic.php?f=28&t=119736
if not config.disallow[entity.ghost_name] and (config.allow_blueprint_repair or true) then
revive_count = revive_count + 1
entity.silent_revive()
end
end
response[#response + 1] = { "exp-commands_repair.response-revive", revive_count }
end
if config.allow_heal_entities then
local healed_count = 0
local entities = surface.find_entities_filtered{
position = position,
radius = range,
force = force,
}
for _, entity in ipairs(entities) do
if entity.health and entity.get_health_ratio() ~= 1 then
healed_count = healed_count + 1
entity.health = huge
end
end
response[#response + 1] = { "exp-commands_repair.response-heal", healed_count }
end
return Commands.status.success(response)
end)

View File

@@ -0,0 +1,107 @@
--[[-- Commands - Reports
Adds a commands that allow players to report other players
]]
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
local parse_input = Commands.parse_input
local Roles = require("modules.exp_legacy.expcore.roles")
local player_has_flag = Roles.player_has_flag
local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports
--- @type Commands.InputParser
local function reportable_player(input, player)
local success, status, result = parse_input(input, player, Commands.types.player)
if not success then return status, result end
--- @cast result LuaPlayer
if player_has_flag(input, "report-immune") then
return Commands.status.invalid_input{ "exp-commands_reports.player-immune" }
elseif player == input then
return Commands.status.invalid_input{ "exp-commands_reports.self-report" }
else
return Commands.status.success(result)
end
end
--- Reports a player and notifies admins
Commands.new("create-report", { "exp-commands_reports.description-create" })
:argument("player", { "exp-commands_reports.arg-player-create" }, reportable_player)
:argument("reason", { "exp-commands_reports.arg-reason" }, Commands.types.string)
:enable_auto_concatenation()
:add_aliases{ "report" }
:register(function(player, other_player, reason)
--- @cast other_player LuaPlayer
--- @cast reason string
local player_name = format_player_name(player)
local other_player_name = format_player_name(other_player)
if Reports.report_player(other_player, player.name, reason) then
local user_message = { "exp-commands_reports.response", other_player_name, reason }
local admin_message = { "exp-commands_reports.response-admin", other_player_name, player_name, reason }
for _, player in ipairs(game.connected_players) do
if player.admin then
player.print(admin_message)
else
player.print(user_message)
end
end
else
return Commands.status.invalid_input{ "exp-commands_reports.already-reported" }
end
end)
--- Gets a list of all reports that a player has on them. If no player then lists all players and the number of reports on them.
Commands.new("get-reports", { "exp-commands_reports.description-get" })
:optional("player", { "exp-commands_reports.arg-player-get" }, Commands.types.player)
:add_aliases{ "reports" }
:add_flags{ "admin_only" }
:register(function(player, other_player)
--- @cast other_player LuaPlayer?
if other_player then
local reports = Reports.get_reports(other_player)
local other_player_name = format_player_name(other_player)
Commands.print{ "exp-commands_reports.player-title", other_player_name, #reports }
for by_player_name, reason in pairs(reports) do
local by_player_name_formatted = format_player_name(by_player_name)
Commands.print{ "exp-commands_reports.list-element", by_player_name_formatted, reason }
end
else
local reports = Reports.user_reports
Commands.print{ "exp-commands_reports.reports-title" }
for player_name in pairs(reports) do
local player_name_formatted = format_player_name(player_name)
local report_count = Reports.count_reports(player_name)
Commands.print{ "exp-commands_reports.list-element", player_name_formatted, report_count }
end
end
end)
--- Clears all reports from a player or just the report from one player.
Commands.new("clear-reports", { "exp-commands_reports.description-clear" })
:argument("player", { "exp-commands_reports.arg-player-clear" }, Commands.types.player)
:optional("from-player", { "exp-commands_reports.arg-from-player" }, Commands.types.player)
:add_flags{ "admin_only" }
:register(function(player, other_player, from_player)
--- @cast other_player LuaPlayer
--- @cast from_player LuaPlayer?
local player_name = format_player_name(player)
local other_player_name = format_player_name(other_player)
if from_player then
if not Reports.remove_report(other_player, from_player.name, player.name) then
local from_player_name = format_player_name(other_player)
return Commands.status.invalid_input{ "exp-commands_reports.not-reported-by", from_player_name }
else
game.print{ "exp-commands_reports.removed", other_player_name, player_name }
return Commands.status.success()
end
else
if not Reports.remove_all(other_player, player.name) then
return Commands.status.invalid_input{ "exp-commands_reports.not-reported" }
else
game.print{ "exp-commands_reports.removed-all", other_player_name, player_name }
return Commands.status.success()
end
end
end)

View File

@@ -0,0 +1,71 @@
--[[-- Commands - Research
Adds a command to enable automatic research queueing
]]
local Storage = require("modules/exp_util/storage")
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
local config = require("modules.exp_legacy.config.research") --- @dep config.research
local research = {
res_queue_enable = false
}
Storage.register(research, function(tbl)
research = tbl
end)
--- @param force LuaForce
--- @param silent boolean True when no message should be printed
local function res_queue(force, silent)
local res_q = force.research_queue
local res = force.technologies["mining-productivity-4"]
if #res_q < config.queue_amount then
for i = 1, config.queue_amount - #res_q do
force.add_research(res)
if not silent then
game.print{ "exp-commands_research.queue", res.name, res.level + i }
end
end
end
end
--- Sets the auto research state
Commands.new("set-auto-research", { "exp-commands_research.description" })
:optional("state", { "exp-commands_research.arg-state" }, Commands.types.boolean)
:add_aliases{ "auto-research" }
:register(function(player, state)
--- @cast state boolean?
if state == nil then
research.res_queue_enable = not research.res_queue_enable
else
research.res_queue_enable = state
end
if research.res_queue_enable then
res_queue(player.force --[[@as LuaForce]], true)
end
local player_name = format_player_name(player)
game.print{ "exp-commands_research.auto-research", player_name, research.res_queue_enable }
end)
--- @param event EventData.on_research_finished
local function on_research_finished(event)
if not research.res_queue_enable then return end
local force = event.research.force
if force.rockets_launched > 0 and force.technologies["mining-productivity-4"].level > 4 then
res_queue(force, event.by_script)
end
end
local e = defines.events
return {
events = {
[e.on_research_finished] = on_research_finished,
}
}

View File

@@ -0,0 +1,63 @@
--[[-- Commands - Roles
Adds a commands that allow interaction with the role system
]]
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
local format_text = Commands.format_rich_text_color_locale
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
local get_roles_ordered = Roles.get_roles_ordered
local get_player_roles = Roles.get_player_roles
--- Assigns a role to a player
Commands.new("assign-role", { "exp-commands_roles.description-assign" })
:argument("player", { "exp-commands_roles.arg-player-assign" }, Commands.types.lower_role_player)
:argument("role", { "exp-commands_roles.arg-role-assign" }, Commands.types.lower_role)
:add_aliases{ "assign" }
:add_flags{ "admin_only" }
:register(function(player, other_player, role)
--- @cast other_player LuaPlayer
--- @cast role any -- TODO
Roles.assign_player(other_player, role, player.name)
end)
--- Unassigns a role to a player
Commands.new("unassign-role", { "exp-commands_roles.description-unassign" })
:argument("player", { "exp-commands_roles.arg-player-unassign" }, Commands.types.lower_role_player)
:argument("role", { "exp-commands_roles.arg-role-unassign" }, Commands.types.lower_role)
:add_aliases{ "unassign" }
:add_flags{ "admin_only" }
:register(function(player, other_player, role)
--- @cast other_player LuaPlayer
--- @cast role any -- TODO
Roles.unassign_player(other_player, role, player.name)
end)
--- Lists all roles in they correct order
Commands.new("get-role", { "exp-commands_roles.description-get" })
:optional("player", { "exp-commands_roles.arg-player-get" }, Commands.types.player)
:add_aliases{ "roles" }
:add_flags{ "admin_only" }
:register(function(player, other_player)
--- @cast other_player LuaPlayer?
local roles = get_roles_ordered()
local roles_formatted = { "" } --- @type LocalisedString
local response = { "exp-commands_roles.list-roles", roles_formatted }
if other_player then
roles = get_player_roles(other_player)
response[1] = "exp-commands_roles.list-player"
response[3] = format_player_name(other_player)
end
for index, role in ipairs(roles) do
local role_name = format_text(role.name, role.custom_color or Commands.color.white)
roles_formatted[index + 1] = { "exp-commands_roles.list-element", role_name }
end
local last = #roles_formatted
--- @diagnostic disable-next-line nil-check
roles_formatted[last] = roles_formatted[last][2]
return Commands.status.success(response)
end)

View File

@@ -0,0 +1,181 @@
--[[-- Commands - Inventory Search
Adds commands that will search all players inventories for an item
]]
local ExpUtil = require("modules/exp_util")
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
local format_number = require("util").format_number
--- A player who is of a lower role than the executing player
--- @type Commands.InputParser
local function parse_item(input, player)
-- First Case - internal name is given
-- Second Case - rich text is given
local item_name = input:lower():gsub(" ", "-")
local item = prototypes.item[item_name] or prototypes.item[input:match("%[item=([0-9a-z-]+)%]")]
if item then
return Commands.status.success(item)
end
-- No item found, we do not attempt to search all prototypes as this will be expensive
return Commands.status.invalid_input{ "exp-commands_search.invalid-item", item_name }
end
--- @class SearchResult: { player: LuaPlayer, count: number, online_time: number }
--- Search all players for this item
--- @param players LuaPlayer[] Players to search
--- @param item LuaItemPrototype Item to find
--- @return SearchResult[]
local function search_players(players, item)
local found = {} --- @type SearchResult[]
local head = 1
-- Check the item count of all players
for _, player in pairs(players) do
local item_count = player.get_item_count(item.name)
if item_count > 0 then
-- Add the player to the array as they have the item
found[head] = { player = player, count = item_count, online_time = player.online_time }
head = head + 1
end
end
return found
end
--- @alias SortFunction fun(result: SearchResult): number
--- Custom sort function which only retains 5 greatest values
--- @param results SearchResult[] Players to sort
--- @param func SortFunction Function to calculate value, higher better
--- @return SearchResult[] # Top 5 results
local function sort_results(results, func)
local sorted = {}
local values = {}
local threshold = 0
-- Loop over all provided players
for index, result in ipairs(results) do
local value = func(result)
-- Check if the item will make the top 5 elements
if index <= 5 or value > threshold then
local inserted = false
values[result] = value
-- Find where in the top 5 to insert the element
for next_index, next_result in ipairs(sorted) do
if value > values[next_result] then
table.insert(sorted, next_index, result)
inserted = true
break
end
end
-- Update the threshold, clean up the tables, and insert if needed
if sorted[6] then
threshold = values[sorted[5]]
values[sorted[6]] = nil
sorted[6] = nil
elseif not inserted then
-- index <= 5 so insert at the end
sorted[#sorted + 1] = result
threshold = value
end
end
end
return sorted
end
local display_players_time_format = ExpUtil.format_time_factory_locale{ format = "short", hours = true, minutes = true }
--- Display to the player the top players which were found
--- @param results SearchResult[]
--- @param item LuaItemPrototype
--- @return LocalisedString
local function format_response(results, item)
if #results == 0 then
return { "exp-commands_search.no-results", item.name }
end
local response = { "", { "exp-commands_search.title", item.name } } --- @type LocalisedString
for index, data in ipairs(results) do
response[index + 2] = {
"exp-commands_search.result",
index,
format_player_name(data.player),
format_number(data.count, false),
display_players_time_format(data.online_time),
}
end
return response
end
--- Return the the amount of an item a player has divided by their playtime
local function combined_sort(data)
return data.count / data.online_time
end
--- Get a list of players sorted by quantity held and play time
Commands.new("search", { "exp-commands_search.description-search" })
:argument("item", { "exp-commands_search.arg-item" }, parse_item)
:enable_auto_concatenation()
:add_aliases{ "s" }
:register(function(player, item)
--- @cast item LuaItemPrototype
local results = search_players(game.players, item)
local sorted = sort_results(results, combined_sort)
return Commands.status.success(format_response(sorted, item))
end)
--- Get a list of online players sorted by quantity held and play time
Commands.new("search-online", { "exp-commands_search.description-online" })
:argument("item", { "exp-commands_search.arg-item" }, parse_item)
:enable_auto_concatenation()
:add_aliases{ "so" }
:register(function(player, item)
--- @cast item LuaItemPrototype
local results = search_players(game.connected_players, item)
local sorted = sort_results(results, combined_sort)
return Commands.status.success(format_response(sorted, item))
end)
--- Return the amount of an item a player has
--- @type SortFunction
local function sort_by_count(data)
return data.count
end
--- Get a list of players sorted by the quantity of an item in their inventory
Commands.new("search-amount", { "exp-commands_search.description-amount" })
:argument("item", { "exp-commands_search.arg-item" }, parse_item)
:enable_auto_concatenation()
:add_aliases{ "sa" } -- cant use /sc
:register(function(player, item)
--- @cast item LuaItemPrototype
local results = search_players(game.players, item)
local sorted = sort_results(results, sort_by_count)
return Commands.status.success(format_response(sorted, item))
end)
--- Return the index of the player, higher means they joined more recently
local function sort_by_recent(data)
return data.player.index
end
--- Get a list of players who have the given item, sorted by how recently they joined
Commands.new("search-recent", { "exp-commands_search.description-recent" })
:argument("item", { "exp-commands_search.arg-item" }, parse_item)
:enable_auto_concatenation()
:add_aliases{ "sr" } -- cant use /sc
:register(function(player, item)
--- @cast item LuaItemPrototype
local results = search_players(game.players, item)
local sorted = sort_results(results, sort_by_recent)
return Commands.status.success(format_response(sorted, item))
end)

View File

@@ -0,0 +1,29 @@
--[[-- Commands - Spectate
Adds commands relating to spectate and follow
]]
local Commands = require("modules/exp_commands")
local Spectate = require("modules.exp_legacy.modules.control.spectate") --- @dep modules.control.spectate
--- Toggles spectator mode for the caller
Commands.new("spectate", { "exp-commands_spectate.description-spectate" })
:register(function(player)
if Spectate.is_spectating(player) then
Spectate.stop_spectate(player)
else
Spectate.start_spectate(player)
end
end)
--- Enters follow mode for the caller, following the given player.
Commands.new("follow", { "exp-commands_spectate.description-follow" })
:argument("player", { "exp-command_spectate.arg-player" }, Commands.types.player_online)
:add_aliases{ "f" }
:register(function(player, other_player)
--- @cast other_player LuaPlayer
if player == other_player then
return Commands.status.invalid_input{ "exp-command_spectate.follow-self" }
else
Spectate.start_follow(player, other_player)
end
end)

View File

@@ -0,0 +1,89 @@
--[[-- Commands - Clear Item On Ground
Adds a command that clear item on ground so blueprint can deploy safely
]]
local ExpUtil = require("modules/exp_util")
local move_items = ExpUtil.move_items_to_surface
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
--- @param surface LuaSurface
--- @return LuaItemStack[]
local function get_ground_items(surface)
local items = {} --- @type LuaItemStack[]
local entities = surface.find_entities_filtered{ name = "item-on-ground" }
for index, entity in ipairs(entities) do
items[index] = entity.stack
end
return items
end
--- Clear all items on the ground, optional to select a single surface
Commands.new("clear-ground-items", { "exp-commands_surface.description-items" })
:optional("surface", { "exp-commands_surface.arg-surface" }, Commands.types.surface)
:register(function(player, surface)
--- @cast surface LuaSurface?
local player_name = format_player_name(player)
if surface then
move_items{
surface = surface,
items = get_ground_items(surface),
allow_creation = true,
name = "iron-chest",
}
game.print{ "exp-commands_surface.items-surface", player_name, surface.localised_name }
else
for _, surface in pairs(game.surfaces) do
move_items{
surface = surface,
items = get_ground_items(surface),
allow_creation = true,
name = "iron-chest",
}
end
game.print{ "exp-commands_surface.items-all", player_name }
end
end)
--- Clear all blueprints, optional to select a single surface
Commands.new("clear-blueprints", { "exp-commands_surface.description-blueprints" })
:optional("surface", { "exp-commands_surface.arg-surface" }, Commands.types.surface)
:register(function(player, surface)
--- @cast surface LuaSurface?
local player_name = format_player_name(player)
if surface then
local entities = surface.find_entities_filtered{ type = "entity-ghost" }
for _, entity in ipairs(entities) do
entity.destroy()
end
game.print{ "exp-commands_surface.blueprint-surface", player_name, surface.localised_name }
else
for _, surface in pairs(game.surfaces) do
local entities = surface.find_entities_filtered{ type = "entity-ghost" }
for _, entity in ipairs(entities) do
entity.destroy()
end
end
game.print{ "exp-commands_surface.blueprint-all", player_name }
end
end)
--- Clear all blueprints in a radius around you
Commands.new("clear-blueprints-radius", { "exp-commands_surface.description-radius" })
:argument("radius", { "exp-commands_surface.arg-radius" }, Commands.types.number_range(1, 1000))
:register(function(player, radius)
--- @cast radius number
local player_name = format_player_name(player)
local entities = player.surface.find_entities_filtered{
type = "entity-ghost",
position = player.position,
radius = radius,
}
for _, entity in ipairs(entities) do
entity.destroy()
end
game.print{ "exp-commands_surface.blueprint-radius", player_name, radius, player.surface.localised_name }
end)

View File

@@ -0,0 +1,84 @@
--[[-- Commands - Teleport
Adds a command that allows players to teleport to other players and spawn
]]
local ExpUtil = require("modules/exp_util")
local teleport_player = ExpUtil.teleport_player
local Commands = require("modules/exp_commands")
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
local player_allowed = Roles.player_allowed
--- Teleports a player to another player.
Commands.new("teleport", { "exp-commands_teleport.description-teleport" })
:argument("player", { "exp-commands_teleport.arg-player-teleport" }, Commands.types.player_alive)
:optional("target", { "exp-commands_teleport.arg-player-to" }, Commands.types.player_alive)
:add_aliases{ "tp" }
:add_flags{ "admin_only" }
:register(function(player, other_player, target_player)
--- @cast other_player LuaPlayer
--- @cast target_player LuaPlayer?
if target_player == nil then
-- When no player is given, then instead behave like /goto
if not teleport_player(player, other_player.physical_surface, other_player.physical_position) then
return Commands.status.error{ "exp-commands_teleport.unavailable" }
end
elseif other_player == target_player then
return Commands.status.invalid_input{ "exp-commands_teleport.same-player" }
elseif not teleport_player(other_player, target_player.physical_surface, target_player.physical_position) then
return Commands.status.error{ "exp-commands_teleport.unavailable" }
end
end)
--- Teleports a player to you.
Commands.new("bring", { "exp-commands_teleport.description-bring" })
:argument("player", { "exp-commands_teleport.arg-player-from" }, Commands.types.player_alive)
:add_flags{ "admin_only" }
:register(function(player, other_player)
--- @cast other_player LuaPlayer
if player == other_player then
return Commands.status.invalid_input{ "exp-commands_teleport.same-player" }
elseif not teleport_player(other_player, player.physical_surface, player.physical_position) then
return Commands.status.error{ "exp-commands_teleport.unavailable" }
end
end)
--- Teleports you to a player.
Commands.new("goto", { "exp-commands_teleport.description-goto" })
:argument("player", { "exp-commands_teleport.arg-player-to" }, Commands.types.player_alive)
:add_flags{ "admin_only" }
:register(function(player, other_player)
--- @cast other_player LuaPlayer
if player == other_player then
return Commands.status.invalid_input{ "exp-commands_teleport.same-player" }
elseif not teleport_player(player, other_player.physical_surface, other_player.physical_position) then
return Commands.status.error{ "exp-commands_teleport.unavailable" }
end
end)
--- Teleport to spawn
Commands.new("spawn", { "exp-commands_teleport.description-spawn" })
:optional("player", { "exp-commands_teleport.arg-player-spawn" }, Commands.types.player_alive)
:defaults{
player = function(player)
if player.character and player.character.health > 0 then
return player
end
end,
}
:register(function(player, other_player)
if not other_player then
return Commands.status.error{ "exp-commands_teleport.unavailable" }
elseif other_player == player then
if not teleport_player(player, game.surfaces.nauvis, { 0, 0 }, "dismount") then
return Commands.status.error{ "exp-commands_teleport.unavailable" }
end
elseif player_allowed(player, "command/spawn/always") then
if not teleport_player(other_player, game.surfaces.nauvis, { 0, 0 }, "dismount") then
return Commands.status.error{ "exp-commands_teleport.unavailable" }
end
else
return Commands.status.unauthorised()
end
end)

View File

@@ -0,0 +1,29 @@
--[[-- Commands - Set Automatic Train
Adds a command that set all train back to automatic
]]
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
local format_number = require("util").format_number
--- Set all trains to automatic
Commands.new("set-trains-to-automatic", { "exp-commands_trains.description" })
:optional("surface", { "exp-commands_trains.arg-surface" }, Commands.types.surface)
:optional("force", { "exp-commands_trains.arg-force" }, Commands.types.force)
:register(function(player, surface, force)
--- @cast surface LuaSurface?
--- @cast force LuaForce?
local trains = game.train_manager.get_trains{
has_passenger = false,
is_manual = true,
surface = surface,
force = force,
}
for _, train in ipairs(trains) do
train.manual_mode = false
end
game.print{ "exp-commands_trains.response", format_player_name(player), format_number(#trains, false) }
end)

View File

@@ -0,0 +1,18 @@
--[[-- Commands - VLayer
Adds a virtual layer to store power to save space.
]]
local Commands = require("modules/exp_commands")
local vlayer = require("modules.exp_legacy.modules.control.vlayer")
--- Print all vlayer information
Commands.new("vlayer-info", { "exp-commands_vlayer.description" })
:register(function(player)
local index = 3
local response = { "", "exp-commands_vlayer.title" } --- @type LocalisedString
for title, value in pairs(vlayer.get_circuits()) do
response[index] = { "exp-commands_vlayer.result", title, value }
index = index + 1
end
return Commands.status.success(response)
end)

View File

@@ -0,0 +1,96 @@
--[[-- Commands - Warnings
Adds a commands that allow admins to warn other players
]]
local Commands = require("modules/exp_commands")
local format_player_name = Commands.format_player_name_locale
local Warnings = require("modules.exp_legacy.modules.control.warnings") --- @dep modules.control.warnings
local config = require("modules.exp_legacy.config.warnings") --- @dep config.warnings
--- Gives a warning to a player; may lead to automatic script action.
Commands.new("create-warning", { "exp-commands_warnings.description-create" })
:argument("player", { "exp-commands_warnings.arg-player-create" }, Commands.types.lower_role_player)
:argument("reason", { "exp-commands_warnings.arg-reason" }, Commands.types.string)
:enable_auto_concatenation()
:add_aliases{ "warn" }
:add_flags{ "admin_only" }
:register(function(player, other_player, reason)
--- @cast other_player LuaPlayer
--- @cast reason string
Warnings.add_warning(other_player, player.name, reason)
local player_name = format_player_name(player)
local other_player_name = format_player_name(other_player)
game.print{ "exp-commands_warnings.create", other_player_name, player_name, reason }
end)
--- Gets a list of all warnings that a player has on them. If no player then lists all players and the number of warnings on them.
Commands.new("get-warnings", { "exp-commands_warnings.description-get" })
:optional("player", { "exp-commands_warnings.arg-player-get" }, Commands.types.player)
:add_aliases{ "warnings" }
:add_flags{ "admin_only" }
:register(function(player, other_player)
--- @cast other_player LuaPlayer?
if other_player then
local warnings = Warnings.get_warnings(player)
local script_warnings = Warnings.get_script_warnings(player)
local other_player_name = format_player_name(other_player)
Commands.print{ "exp-commands_warnings.player-title", other_player_name, #warnings, #script_warnings, config.temp_warning_limit }
for _, warning in pairs(warnings) do
local by_player_name_formatted = format_player_name(warning.by_player_name)
Commands.print{ "exp-commands_warnings.list-element-player", by_player_name_formatted, warning.reason }
end
else
local warnings = Warnings.user_warnings:get_all()
local script_warnings = Warnings.user_script_warnings
Commands.print{ "exp-commands_warnings.warnings-title" }
for player_name, player_warnings in pairs(warnings) do
local player_name_formatted = format_player_name(player_name)
local script_warning_count = script_warnings[player_name] and #script_warnings[player_name] or 0
Commands.print{ "exp-commands_warnings.list-element", player_name_formatted, #player_warnings, script_warning_count, config.temp_warning_limit }
end
for player_name, player_warnings in pairs(script_warnings) do
if not warnings[player_name] then
local player_name_formatted = format_player_name(player_name)
Commands.print{ "exp-commands_warnings.list-element", player_name_formatted, 0, #player_warnings, config.temp_warning_limit }
end
end
end
end)
--- Clears all warnings from a player
Commands.new("clear-warnings", { "exp-commands_warnings.description-clear" })
:argument("player", { "exp-commands_warnings.arg-player-clear" }, Commands.types.player)
:add_flags{ "admin_only" }
:register(function(player, other_player)
--- @cast other_player LuaPlayer
Warnings.clear_warnings(other_player, player.name)
Warnings.clear_script_warnings(other_player)
local player_name = format_player_name(player)
local other_player_name = format_player_name(other_player)
game.print{ "exp-commands_warnings.cleared", other_player_name, player_name }
end)
--- Clears all script warnings from a player
Commands.new("clear-script-warnings", { "exp-commands_warnings.description-clear-script" })
:argument("player", { "exp-commands_warnings.arg-player-clear" }, Commands.types.player)
:add_flags{ "admin_only" }
:register(function(player, other_player)
--- @cast other_player LuaPlayer
Warnings.clear_script_warnings(other_player)
local player_name = format_player_name(player)
local other_player_name = format_player_name(other_player)
game.print{ "exp-commands_warnings.cleared-script", other_player_name, player_name }
end)
--- Clears the last warning that was given to a player
Commands.new("clear-last-warnings", { "exp-commands_warnings.description-clear-last" })
:argument("player", { "exp-commands_warnings.arg-player-clear" }, Commands.types.player)
:add_flags{ "admin_only" }
:register(function(player, other_player)
--- @cast other_player LuaPlayer
Warnings.remove_warning(other_player, player.name)
local player_name = format_player_name(player)
local other_player_name = format_player_name(other_player)
game.print{ "exp-commands_warnings.cleared-last", other_player_name, player_name }
end)

View File

@@ -0,0 +1,69 @@
--[[-- Commands - Waterfill
Adds a command that places shallow water
]]
local AABB = require("modules/exp_util/aabb")
local Commands = require("modules/exp_commands")
local Selection = require("modules.exp_legacy.modules.control.selection") --- @dep modules.control.selection
local SelectionName = "ExpCommand_Waterfill"
--- Toggle player selection mode for artillery
Commands.new("waterfill", { "exp-commands_waterfill.description" })
:register(function(player)
if Selection.is_selecting(player, SelectionName) then
Selection.stop(player)
return Commands.status.success{ "exp-commands_waterfill.exit" }
elseif player.get_item_count("cliff-explosives") == 0 then
return Commands.status.error{ "exp-commands_waterfill.requires-explosives" }
else
Selection.start(player, SelectionName)
return Commands.status.success{ "exp-commands_waterfill.enter" }
end
end)
--- When an area is selected to be converted to water
Selection.on_selection(SelectionName, function(event)
--- @cast event EventData.on_player_selected_area
local area = AABB.expand(event.area)
local player = game.players[event.player_index]
local surface = event.surface
if surface.planet and surface.planet ~= game.planets.nauvis then
player.print({ "exp-cods_waterfill.nauvis-only" }, Commands.print_settings.error)
return
end
local area_size = (area.right_bottom.x - area.left_top.x) * (area.right_bottom.y - area.left_top.y)
if area_size > 1000 then
player.print({ "exp-cods_waterfill.area-too-large", 1000, area_size }, Commands.print_settings.error)
return
end
local item_count = player.get_item_count("cliff-explosives")
if item_count < area_size then
player.print({ "exp-cods_waterfill.too-few-explosives", area_size, item_count }, Commands.print_settings.error)
return
end
local tile_count = 0
local tiles_to_make = {}
for x = area.left_top.x, area.right_bottom.x do
for y = area.left_top.y, area.right_bottom.y do
tile_count = tile_count + 1
tiles_to_make[tile_count] = {
name = "water-mud",
position = { x, y },
}
end
end
surface.set_tiles(tiles_to_make, true, "abort_on_collision", true, false, player, 0)
local remaining_tiles = surface.count_tiles_filtered{ area = area, name = "water-mud" }
player.remove_item{ name = "cliff-explosives", count = tile_count - remaining_tiles }
if remaining_tiles > 0 then
player.print({ "exp-cods_waterfill.part-complete", tile_count, remaining_tiles }, Commands.print_settings.default)
else
player.print({ "exp-cods_waterfill.complete", tile_count }, Commands.print_settings.default)
end
end)

View File

@@ -1,9 +1,43 @@
local event_handler = require("event_handler")
--- @type fun(lib: { on_init: fun(), on_load: fun(), events: { [defines.events]: fun(event: EventData) } })
local add = event_handler.add_lib
--- Command Extensions
require("modules.exp_scenario/commands/types")
require("modules.exp_scenario/commands/authorities")
require("modules.exp_scenario/commands/_authorities")
require("modules.exp_scenario/commands/_rcon")
require("modules.exp_scenario/commands/_types")
--- Commands with events
add(require("modules/exp_scenario/commands/protected_entities"))
add(require("modules/exp_scenario/commands/protected_tags"))
add(require("modules/exp_scenario/commands/research"))
--- Commands
require("modules/exp_scenario/commands/admin_chat")
require("modules/exp_scenario/commands/artillery")
require("modules/exp_scenario/commands/bot_queues")
require("modules/exp_scenario/commands/cheat")
require("modules/exp_scenario/commands/clear_inventory")
require("modules/exp_scenario/commands/connect")
require("modules/exp_scenario/commands/debug")
require("modules/exp_scenario/commands/enemy")
require("modules/exp_scenario/commands/home")
require("modules/exp_scenario/commands/jail")
require("modules/exp_scenario/commands/kill")
require("modules/exp_scenario/commands/lawnmower")
require("modules/exp_scenario/commands/locate")
require("modules/exp_scenario/commands/me")
require("modules/exp_scenario/commands/rainbow")
require("modules/exp_scenario/commands/ratio")
require("modules/exp_scenario/commands/repair")
require("modules/exp_scenario/commands/reports")
require("modules/exp_scenario/commands/roles")
require("modules/exp_scenario/commands/search")
require("modules/exp_scenario/commands/spectate")
require("modules/exp_scenario/commands/surface")
require("modules/exp_scenario/commands/teleport")
require("modules/exp_scenario/commands/trains")
require("modules/exp_scenario/commands/vlayer")
require("modules/exp_scenario/commands/warnings")
require("modules/exp_scenario/commands/waterfill")

View File

@@ -1,6 +1,282 @@
[exp-commands-authorities_role]
deny=Unauthorized, Access is denied due to missing permissions
deny=Unauthorized, Access is denied due to missing permissions.
[exp-commands-parse_role]
lower-role=Role is higher than your highest.
lower-role-player=Player has a higher role.
[exp-commands_admin-chat]
description=Sends a message in chat that only admins can see.
arg-message=The message to send.
format=[AC] __1__: __2__
[exp-commands_artillery]
description=Automaticly select enemy target with artillery.
invalid-area=The selected area is not valid.
enter=Entered artillery selection mode.
exit=Existed artillery selection mode.
[exp-commands_bot-queue]
description-get=Get / Set the construction bot queue limits.
arg-amount=Multiple of default value to set the queues to.
get=Bot queue is __1__ successful attempts and __2__ failed attempts.
set=__1__ set the bot queue to __2__ successful attempts and __3__ failed attempts.
[exp-commands_cheat]
description-cheat-mode=Set cheat mode for your player, or another player.
description-always-day=Set always day for your current surface, or another surface.
description-friendly-fire=Set friendly fire for your force, or another force.
description-research-all=Research all technology for your force, or another force.
description-clear-pollution=Clear pollution from your current surface, or another surface.
description-pollution-enabled=Set polution enabled state for this game.
description=game-speed=Set or get the current game speed.
arg-state=State to set, default is to toggle the current value.
arg-player=Player to toggle cheat mode for.
arg-force-friendly-fire=Force to research all technology for.
arg-force-research=Force to research all technology for.
arg-surface=Surface to toggle always day for.
arg-amount=Amount to set, returns the current value if not given.
cheat-mode=Cheat mode is now __1__
always-day=__1__ has toggled always day on __2__ surface to __3__.
friendly-fire=__1__ set friendly fire for __2__ to __3__.
research-all=__1__ has enabled all technology for __2__ force.
clear-pollution=__1__ has cleared pollution from __2__.
pollution-enabled=__1__ has set the polution enabled state to __2__.
game-speed-set=__1__ has set the game speed to __2__.
game-speed-get=The current game speed is __1__.
[exp-commands_clear-inventory]
description=Clears a players inventory, all items will be moved to the spawn point.
arg-player=Player to clear the inventory of.
[exp-commands_connect]
description=Connect to another server.
description-player=Connect a player to a different server.
description-all=Connect all players to another server.
arg-player=Player to connect to another server.
arg-server=Server name or address to connect to.
arg-is-address=True when the input should be read as an address.
too-many-matching=Multiple server were found with the given name: __1__
wrong-version=Servers were found but are on a different version: __1__
same-server=You are already connected to the server: __1__
offline=You cannot connect as the server is currently offline: __1__
none-matching=No servers were found with that name, if you used an address please append true to the end of your command.
[expcom-debug]
description=Opens the debug gui.
[exp-commands_enemy]
description-kill=Kill all enemy units.
description-remove=Remove all enemy spawners.
arg-surface=Surface to remove spawners from.
[exp-commands_home]
description-home=Teleports you to your home location.
description-return=Teleports you to previous location.
description-get=Returns your current home location.
description-set=Sets your home location to your current position.
no-home=You have no home set on __1__.
no-return=You can't return when /home has not been used on __1__.
home-get=Your home point on __1__ is at x: __2__ y: __3__
home-set=Your home point on __1__ has been set to x: __2__ y: __3__
return-set=Your return point on __1__ has been set to x: __1__ y: __2__
[exp-commands_jail]
description=Puts a player into jail and removes all other roles.
arg-player=Player to jail.
arg-reason=Reason to jail the player.
jailed=__1__ was jailed by __2__. Reason: __3__
already-jailed=__1__ is already jailed.
[exp-commands_unjail]
description=Puts a player into jail and removes all other roles.
arg-player=Player to unjail.
unjailed=__1__ was unjailed by __2__.
not-jailed=__1__ is not currently jailed.
[exp-commands_kill]
description=Kills yourself or another player.
arg-player=Player to kill.
already-dead=You are already dead.
lower-role=You must have a higher role than the target.
[exp-commands_lawnmower]
description=Clean up biter corpse, decoratives and nuclear hole.
arg-range=Range to clean up.
[exp-commands_locate]
description=Opens remote view at the location of the player's last location.
arg-player=Player to locate.
arg-remote=If true opens at the location of the player's remote view.
response=Last location of __1__ was [gps=__2__,__3__]
[exp-commands_me]
description=Sends an action message in the chat.
arg-action=Action you want to perform.
response=* __1__ __2__ *
[expcom-protection]
description-entity=Toggles entity protection selection, hold shift to remove protection
description-area=Toggles area protection selection, hold shift to remove protection
enter-entity-selection=Entered entity selection, select entites to protect, hold shift to remove protection.
enter-area-selection=Entered area selection, select areas to protect, hold shift to remove protection.
exit-entity=Exited entity protection selection.
exit-area=Exited area protect selection.
protected-entities=__1__ entities have been protected.
unprotected-entities=__1__ entities have been unprotected.
already-protected=This area is already protected.
protected-area=This area is now protected.
unprotected-area=This area is now unprotected.
repeat-offence=__1__ has removed __2__ at [gps=__3__,__4__]
[exp-commands_protected-tags]
description=Toggles protected tag mode, edit and create protected map tags.
exit=You have left protected tag mode, any new tags will not be protected.
enter=You have entered protected tag mode, any new tags will be protected.
create=You have placed a protected tag.
edit=You have edited a protected tag.
revert-has-access=This tag is protected, use /__1__ to modify or remove.
revert-no-access=This tag is protected, you can not modify or remove it.
[exp-commands_rainbow]
description=Sends an rainbow message in the chat
arg-message=Message to send in chat.
response=__1__: __2__
[exp-commands_ratio]
description=This command will give the input and output ratios of the selected machine. Use the parameter for calculating the machines needed for that amount of items per second.
arg-items-per-second=Target items per second, defaults to output of a single machine.
not-selecting=Please select an entity with a recipe.
item-in=You need __1__ per second of [item=__2__].
fluid-in=You need __1__ per second of [fluid=__2__].
item-out=This will result in: __1__ [item=__2__] per second.
fluid-out=This will result in: __1__ [fluid=__2__] per second.
machine-count=And you will need __1__ machines (with the same speed as this one) for this.
[exp-commands_repair]
description=Repairs entities on your force around you.
arg-range=Range to repair entities within.
# Intentional space left on the two lines below so they can be joined together.
response-revive=__1__ entities were revived.
response-heal=__1__ entities were healed.
[exp-commands_reports]
description-create=Reports a player and notifies moderators
description-get=Gets a list of all reports that a player has on them. If no player then lists all players and the number of reports on them.
description-clear=Clears all reports from a player or just the report from one player.
arg-player-create=Player you want to report.
arg-player-get=Player to get the reports of.
arg-player-clear=Player to clear the reports of.
arg-reason=Reason you want to report this player.
arg-from-player=Only remove the report from this player.
player-immune=This player can not be reported.
self-report=You cannot report yourself.
response=__1__ was reported for __2__.
response-admin=__1__ was reported by __2__ for __3__.
already-reported=You can only report a player once, you can ask a moderator to clear this report.
not-reported=The player had no reports on them.
not-reported-by=The player had no reports on them from __1__.
reports-title=The following players have reports against them:
player-title=__1__ has __2__ __plural_for_parameter__2__{1=report|rest=reports}__ against them:
list-element=__1__: __2__
removed-all=__1__ has has all of their reports removed by __2__.
removed=__1__ has a report removed by __2__.
[exp-commands_research]
description-ares=Sets research to be automatically queued.
arg-state=State to set, default is to toggle.
auto-research=__1__ set auto research to __2__
queue=[color=255, 255, 255] Research added to queue - [technology=__1__] - __2__[/color]
[exp-commands_roles]
description-assign-role=Assigns a role to a player.
description-unassign-role=Unassigns a role from a player.
description-get=Get all roles that a player has, if no player provided it lists all roles.
arg-player-assign=Player to assign the role to.
arg-player-unassign=Player to unassign the role from.
arg-player-get=Player to get the roles of.
arg-role-assign=Role to assign to the player.
arg-role-unassign=Role to unasign from the player.
list-roles=All roles: __1__
list-player=__2__ has: __1__
list-element=__1__,
[exp-commands_search]
description-search=Display players sorted by the quantity of an item held and playtime.
description-online=Display online players sorted by the quantity of an item held and playtime.
description-amount=Display players sorted by the quantity of an item held.
description-recent=Display players who hold an item sorted by join time.
invalid-item=No item was found with internal name __1__; try using rich text selection.
no-results=No players have [item=__1__]
title=Players found with [item=__1__]:
result=\n__1__) __2__ has __3__ items. (__4__)
[exp-commands_spectate]
description-spectate=Toggles spectator mode.
description-follow=Start following a player in spectator.
arg-player=Player to start following.
follow-self=You can not follow yourself.
[exp-commands_surface]
description-items=Clear all items on the ground.
description-blueprints=Clear all blueprints.
description-radius=Clear all blueprints in an radius around you.
arg-surface=Surface to clear on, default all.
arg-radis=Radius to clear.
items-surface=__1__ cleared all items on the ground of __2__.
items-all=__1__ cleared all items on the ground for all surfaces.
blueprints-surface=__1__ cleared all blueprints on __2__.
blueprints-all=__1__ cleared all blueprints for all surfaces.
blueprints-radius=__1__ cleared all blueprints in a __2__ radius around them on __3__.
[exp-commands_trains]
description=Set All Trains to Automatic, does not effect trains with passengers.
arg-force=Force to set the trains for, default all.
arg-surface=Surface to set the trains for, default all.
response=__1__ set __2__ trains into automatic mode.
[exp-commands_teleport]
description-teleport=Teleports a player to another player.
description-bring=Teleports a player to you.
description-goto=Teleports you to a player.
description-spawn=Teleport to spawn
arg-player-teleport=Player to teleport, if target is not given then you are teleported to this player.
arg-player-from=Player to teleported.
arg-player-to=Player who is the target.
unavailable=They was a problem teleporting you, likely no position found, please try again later.
same-player=Player can not be teleported to themselves.
[exp-commands_vlayer]
description=Print all vlayer information.
title=VLayer Information:
result=__1__: __2__
[exp-commands_warnings]
description-create=Gives a warning to a player; may lead to automatic script action.
description-get=Gets the number of warnings a player has. If no player then lists all players and the number of warnings they have.
description-clear=Clears all warnings (and script warnings) from a player.
description-clear-script=Clears all script warnings from a player.
description-clear-last=Clears the last warning from a player.
arg-player-create=Player to give the warning to.
arg-player-get=Player to get the warning of, if not given all players are returned.
arg-player=clear=Player to clear the warnings of.
arg-reason=Reason the user is receiving a warning.
create=__1__ received a warning from __2__ for __3__.
player-title=__1__ has __2__ warnings and __3__/__4__ script warnings.
list-element-player=__1__: __2__
warnings-title=The following players have warnings aginst them (and script warnings):
list-element=__1__: __2__ (__3__/__4__)
cleared=__1__ had all their warnings cleared by __2__.
cleared-script=__1__ had all their script warnings cleared by __2__.
cleared-last=__1__ had their last warning cleared by __2__.
[exp-commands_waterfill]
description=Replace tiles with shallow water.
requires-explosives=__ITEM__cliff-explosives__ are required to create water.
enter=Entered waterfill selection mode, select the area to fill with water.
exit=Exited water fill seclection mode.
nauvis-only=Can only waterfill on Nauvis, this may change in the future.
area-too-large=Selected area is too large, must be less than __1__ tiles, selected __2__.
too-few-explosives=Requires __1__ __ITEM__cliff-explosives__ you have __2__.
part-complete=__1__ tiles were filled with water, but entities are blocking __2__ tiles.
complete=__1__ tiles were filled with water.