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

@@ -8,44 +8,6 @@ return {
"modules.factorio-control", -- base factorio free play scenario "modules.factorio-control", -- base factorio free play scenario
"expcore.player_data", -- must be loaded first to register event handlers "expcore.player_data", -- must be loaded first to register event handlers
--- Game Commands
"modules.commands.debug",
"modules.commands.me",
"modules.commands.kill",
"modules.commands.admin-chat",
"modules.commands.admin-markers",
"modules.commands.teleport",
"modules.commands.cheat-mode",
"modules.commands.ratio",
"modules.commands.interface",
"modules.commands.help",
"modules.commands.roles",
"modules.commands.rainbow",
"modules.commands.clear-inventory",
"modules.commands.jail",
"modules.commands.repair",
"modules.commands.reports",
"modules.commands.spawn",
"modules.commands.warnings",
"modules.commands.find",
"modules.commands.home",
"modules.commands.connect",
"modules.commands.last-location",
"modules.commands.protection",
"modules.commands.spectate",
"modules.commands.search",
"modules.commands.bot-queue",
"modules.commands.speed",
"modules.commands.pollution",
"modules.commands.train",
"modules.commands.friendly-fire",
"modules.commands.research",
"modules.commands.vlayer",
"modules.commands.enemy",
"modules.commands.waterfill",
"modules.commands.artillery",
"modules.commands.surface-clearing",
--- Addons --- Addons
"modules.addons.chat-popups", "modules.addons.chat-popups",
"modules.addons.damage-popups", "modules.addons.damage-popups",
@@ -104,9 +66,6 @@ return {
"modules.gui.toolbar", -- must be loaded last to register toolbar handlers "modules.gui.toolbar", -- must be loaded last to register toolbar handlers
--- Config Files --- Config Files
"config.expcore.command_auth_admin", -- commands tagged with admin_only are blocked for non admins
"config.expcore.command_auth_roles", -- commands must be allowed via the role config
"config.expcore.command_runtime_disable", -- allows commands to be enabled and disabled during runtime
"config.expcore.permission_groups", -- loads some predefined permission groups "config.expcore.permission_groups", -- loads some predefined permission groups
"config.expcore.roles", -- loads some predefined roles "config.expcore.roles", -- loads some predefined roles
} }

View File

@@ -80,8 +80,8 @@ return {
local options = { "?", ".", "!", "!!!" } local options = { "?", ".", "!", "!!!" }
return { "chat-bot.hodor", table.get_random(options) } return { "chat-bot.hodor", table.get_random(options) }
end, end,
["evolution"] = function(_player, _is_command) ["evolution"] = function(player, _is_command)
return { "chat-bot.current-evolution", string.format("%.2f", game.forces["enemy"].evolution_factor) } return { "chat-bot.current-evolution", string.format("%.2f", game.forces["enemy"].get_evolution_factor(player.surface)) }
end, end,
["makepopcorn"] = function(player, _is_command) ["makepopcorn"] = function(player, _is_command)
local timeout = math.floor(180 * (math.random() + 0.5)) local timeout = math.floor(180 * (math.random() + 0.5))

View File

@@ -1,19 +0,0 @@
--- This is a very simple config file which adds a admin only auth function;
-- not much to change here its more so it can be enabled and disabled from ./config/file_loader.lua;
-- either way you can change the requirements to be "admin" if you wanted to
-- @config Commands-Auth-Admin
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
-- luacheck:ignore 212/command
Commands.add_authenticator(function(player, command, tags, reject)
if tags.admin_only then
if player.admin then
return true
else
return reject{ "command-auth.admin-only" }
end
else
return true
end
end)

View File

@@ -1,14 +0,0 @@
--- This will make commands only work if the role has been allowed it in the role config
-- @config Commands-Auth-Roles
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
-- luacheck:ignore 212/tags
Commands.add_authenticator(function(player, command, tags, reject)
if Roles.player_allowed(player, "command/" .. command) then
return true
else
return reject()
end
end)

View File

@@ -1,15 +0,0 @@
--- This will make commands only work when a valid color from the presets has been selected
-- @config Commands-Color-Parse
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Colours = require("modules/exp_util/include/color")
Commands.add_parse("color", function(input, _, reject)
if not input then return end
local color = Colours[input]
if not color then
return reject{ "expcore-commands.reject-color" }
else
return input
end
end)

View File

@@ -1,143 +0,0 @@
--[[-- This file contains some common command param parse functions;
this file is less of a config and more of a requirement but you may wish to change how some behave;
as such you need to be confident with lua but you edit this config file;
use Commands.add_parse('name',function(input, player, reject) end) to add a parse;
see ./expcore/commands.lua for more details
@config Commands-Parse
@usage Adds Parses:
boolean
string-options - options: array
string-max-length - max_length: number
number
integer
number-range - range_min: number, range_max: number
integer-range - range_min: number, range_max: number
player
player-online
player-alive
force
surface
]]
local ExpUtil = require("modules/exp_util")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
-- luacheck:ignore 212/player
Commands.add_parse("boolean", function(input, player)
if not input then return end -- nil check
input = input:lower()
if input == "yes"
or input == "y"
or input == "true"
or input == "1" then
return true
else
return false
end
end)
Commands.add_parse("string-options", function(input, player, reject, options)
if not input then return end -- nil check
local option = ExpUtil.auto_complete(options, input)
return option or reject{ "expcore-commands.reject-string-options", table.concat(options, ", ") }
end)
Commands.add_parse("string-max-length", function(input, player, reject, max_length)
if not input then return end -- nil check
local length = input:len()
if length > max_length then
return reject{ "expcore-commands.reject-string-max-length", max_length }
else
return input
end
end)
Commands.add_parse("number", function(input, player, reject)
if not input then return end -- nil check
local number = tonumber(input)
if not number then
return reject{ "expcore-commands.reject-number" }
else
return number
end
end)
Commands.add_parse("integer", function(input, player, reject)
if not input then return end -- nil check
local number = tonumber(input)
if not number then
return reject{ "expcore-commands.reject-number" }
else
return math.floor(number)
end
end)
Commands.add_parse("number-range", function(input, player, reject, range_min, range_max)
local number = Commands.parse("number", input, player, reject)
if not number then return end -- nil check
if number < range_min or number > range_max then
return reject{ "expcore-commands.reject-number-range", range_min, range_max }
else
return number
end
end)
Commands.add_parse("integer-range", function(input, player, reject, range_min, range_max)
local number = Commands.parse("integer", input, player, reject)
if not number then return end -- nil check
if number < range_min or number > range_max then
return reject{ "expcore-commands.reject-number-range", range_min, range_max }
else
return number
end
end)
Commands.add_parse("player", function(input, player, reject)
if not input then return end -- nil check
local input_player = game.players[input]
if not input_player then
return reject{ "expcore-commands.reject-player", input }
else
return input_player
end
end)
Commands.add_parse("player-online", function(input, player, reject)
local input_player = Commands.parse("player", input, player, reject)
if not input_player then return end -- nil check
if not input_player.connected then
return reject{ "expcore-commands.reject-player-online" }
else
return input_player
end
end)
Commands.add_parse("player-alive", function(input, player, reject)
local input_player = Commands.parse("player-online", input, player, reject)
if not input_player then return end -- nil check
if not input_player.character or not input_player.character.health or input_player.character.health <= 0 then
return reject{ "expcore-commands.reject-player-alive" }
else
return input_player
end
end)
Commands.add_parse("force", function(input, player, reject)
if not input then return end -- nil check
local force = game.forces[input]
if not force then
return reject{ "expcore-commands.reject-force" }
else
return force
end
end)
Commands.add_parse("surface", function(input, player, reject)
if not input then return end
local surface = game.surfaces[input]
if not surface then
return reject{ "expcore-commands.reject-surface" }
else
return surface
end
end)

View File

@@ -1,56 +0,0 @@
--[[-- Adds some parse functions that can be used with the role system
@config Commands-Parse-Roles
@usage Adds Parses:
role
player-role
player-role-online
player-role-alive
]]
local ExpUtil = require("modules/exp_util")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
local auto_complete = ExpUtil.auto_complete --- @dep expcore.common
require("modules.exp_legacy.config.expcore.command_general_parse")
-- luacheck:ignore 212/player
Commands.add_parse("role", function(input, player, reject)
if not input then return end
local roles = Roles.config.order
local rev_roles = {}
for i = #roles, 1, -1 do
table.insert(rev_roles, roles[i])
end
local role = auto_complete(rev_roles, input)
role = Roles.get_role_by_name(role)
if not role then
return reject{ "expcore-role.reject-role" }
else
return role
end
end)
Commands.add_parse("player-role", function(input, player, reject)
local input_player = Commands.parse("player", input, player, reject)
if not input_player then return end -- nil check
local player_highest = Roles.get_player_highest_role(player)
local input_player_highest = Roles.get_player_highest_role(input_player)
if player_highest.index < input_player_highest.index then
return input_player
else
return reject{ "expcore-roles.reject-player-role" }
end
end)
Commands.add_parse("player-role-online", function(input, player, reject)
local input_player = Commands.parse("player-role", input, player, reject)
if not input_player then return end -- nil check
return Commands.parse("player-online", input_player.name, player, reject)
end)
Commands.add_parse("player-role-alive", function(input, player, reject)
local input_player = Commands.parse("player-role", input, player, reject)
if not input_player then return end -- nil check
return Commands.parse("player-alive", input_player.name, player, reject)
end)

View File

@@ -1,32 +0,0 @@
--- This config for command auth allows commands to be globally enabled and disabled during runtime;
-- this config adds Commands.disable and Commands.enable to enable and disable commands for all users
-- @config Commands-Auth-Runtime-Disable
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Storage = require("modules/exp_util/storage")
local disabled_commands = {}
Storage.register(disabled_commands, function(tbl)
disabled_commands = tbl
end)
--- Stops a command from be used by any one
-- @tparam string command_name the name of the command to disable
function Commands.disable(command_name)
disabled_commands[command_name] = true
end
--- Allows a command to be used again after disable was used
-- @tparam string command_name the name of the command to enable
function Commands.enable(command_name)
disabled_commands[command_name] = nil
end
-- luacheck:ignore 212/player 212/tags
Commands.add_authenticator(function(player, command, tags, reject)
if disabled_commands[command] then
return reject{ "command-auth.command-disabled" }
else
return true
end
end)

View File

@@ -1,895 +0,0 @@
--[[-- Core Module - Commands
- Factorio command making module that makes commands with better parse and more modularity
@core Commands
@alias Commands
@usage--- Full code example, see below for explanation
Commands.new_command('repeat-name', 'Will repeat you name a number of times in chat.')
:add_param('repeat-count', 'number-range-int', 1, 5) -- required int in range 1 to 5 inclusive
:add_param('smiley', true, function(input, player, reject) -- optional boolean default false
if not input then return end
input = input:lower()
if input == 'true' or input == 'yes' then return true end
return false
end)
:set_defaults{ smiley = false }
:set_flag('admin_only') -- command is admin only
:add_alias('name', 'rname') -- allow alias: name and rname
:register(function(player, repeat_count, smiley, raw)
game.print(player.name..' used a command with input: '..raw)
local msg = ') '..player.name
if smiley then
msg = ':'..msg
end
for 1 = 1, repeat_count do
Command.print(1..msg)
end
end)
@usage--- Example Command Explanation:
-- Making commands basics, the commands can be set up with any number of params and flags that you want,
-- you can add aliases for the commands and set default values for optional params and of course register your command callback.
-- In our example we will have a command that will repeat the users name in chat X amount of times and only allow admins to use it.
-- First we create the new command, note this will not register the command to the game this is done at the end.
-- We will call the command "repeat-name" and set the help message as follows:
Commands.new_command('repeat-name', 'Will repeat you name a number of times in chat.')
-- Now for our first param, we have named it "repeat-count" and it will be a required value, between 1 and 5 inclusive:
-- By using "number-range-int" we are saying to use this parser to convert our input text, common ones exist in config.expcore.command_general_parse
:add_param('repeat-count', 'number-range-int', 1, 5)
-- Our second param needs a custom parser, meaning it isnt defined with add_parser, this is an option for when it is unlikely for
-- any other command to use the same input type. In the example it is a boolean type and we are just showing it here as part of the example.
-- As for the param its self it will be called "smiley" and will be optional with a default value of false:
:add_param('smiley', true, function(input, player, reject)
-- Since it is optional the input can be nil, in which case we just return
if not input then return end
-- If it is not nil then we check for a truthy value
if input == 'true' or input == 'yes' then return true end
-- Note that because we did not return nil or reject then false will be passed to command callback, see example parse
return false
end)
-- Once all params are defined you can add some default values for your optional params, the default value will be used only
-- when no value is given as input, if an invalid value is given then the command will fail and the default will not be used, the
-- default can also be a function which is passed the player as an argument and should return a value to be the default.
-- Here we set the default for "smiley" to false:
:set_defaults{smiley=false}
-- Another example of defaults if we have: item, amount[opt], player[opt]
:set_defaults{
amount = 50, -- More than one value can be set at a time
player = function(player) return player end -- Default is the player using the command
}
-- Now the params are set up we can alter how the command works, we can set auth flags, add aliases, or enable "auto concat":
:set_flag('admin_only') -- In our case we want "admin_only" to be set to true so only admins can use the command
:add_alias('name', 'rname') -- We also add two aliases here: "name" and "rname" which point to this command
-- :enable_auto_concat() -- We do not use this in our case but this can also be used to enable the "auto concat" feature
-- And finally we want to register a callback to this command, the callback is what defines what the command does, can be as complex as you
-- want it to be, or as simple as our example; the command receives two params plus all param you have defined:
-- 1) the player who used the command
-- 2) in our case repeat_count which will be a number
-- 3) in our case smiley which will be a boolean
-- 4) the raw input; this param is always last as is always present as a catch all
:register(function(player, repeat_count, smiley, raw)
-- This is to show the value for raw as this is an example command, the log file will also show this
game.print(player.name..' used a command with input: '..raw)
local msg = ') '..player.name
if smiley then
msg = ':'..msg
end
for 1 = 1, repeat_count do
-- this print function will return ANY value to the user in a desync safe manor, this includes if the command was used through rcon
Command.print(1..msg)
end
-- See below for what can be used here
end)
-- Values that can be returned from register callback
Commands.print(any, colour[opt]) -- This will return any value value to the user including if it is ran through rcon console
Commands.error(message[opt]) -- This returns a warning to the user, aka an error that does not prevent execution of the command
return Commands.error(message[opt]) -- This returns an error to the user, and will halt the command execution, ie no success message is returned
Commands.success(message[opt]) -- Used to return a success message however don't use this method, see below
return Commands.success(message[opt]) -- Will return the success message to the user and your given message, halts execution
return <any> -- If any value is returned then it will be returned to the player via a Commands.success call
@usage--- Example Authenticator:
-- The command system is best used when you can control who uses commands;
-- to do this you need to define an authenticator which is ran every time a command is run;
-- in this example I will show a simple one that requires certain commands to require the user to be a game admin.
-- For our admin only example we will set a flag to true when we want it to be admin only;
-- when we define the command will will use :set_flag('admin_only');
-- then inside the authenticator we will test if the flag is present using: if flags.admin_only then
-- When the authenticator is called by the command handler it will be passed 4 arguments:
-- 1) player - the player who used the command
-- 2) command - the name of the command that is being used
-- 3) flags - the flags which have been set for this command, flags are set with :set_flag(name, value)
-- 4) reject - the reject function which is the preferred method to prevent execution of the command
-- No return is required to allow the command to execute but it is best practice to return true;
-- we do this in two cases in our authenticator:
-- 1) when the "admin_only" flag is not set, which we take assume that any one can use it
-- 2) when the "admin_only" flag is set, and the player is admin
-- When want to prevent execution of the command we must reject it, listed is how that can be done:
-- 1) return false -- this is the most basic rejection and should only be used while testing
-- 2) return reject -- returning the reject function is as a fail safe in case you forget to call it, same as returning false
-- 3) reject() -- this will block execution while allowing further code to be ran in your authenticator
-- 4) reject('This command is for admins only!') -- using reject as a function allows a error message to be returned
-- 5) return reject() -- using return on either case above is best practice as you should execute all your code before rejecting
-- Example Code:
Commands.add_authenticator(function(player, command, flags, reject)
-- Check if the command is admin only
if flags.admin_only then
-- Return true if player is admin, or reject and return error message
return player.admin or reject('This command is for admins only!')
else
-- Return true if command was not admin only
return true
end
end)
@usage--- Example Parser:
-- Before you make a command it is important to understand the most powerful feature of this command handler;
-- when you define a command you are able to type the params and have then be parsed and validated before your command is executed;
-- This module should be paired with a general command parse but you may want to create your own.
-- For our example we will create a parse to accept only integer numbers in a given range:
-- 1) we will give it the name "number-range-int" this is the "type" that the input is expected to be
-- 2) when we define the type we will also define the min and max of the range so we can use the function more than once
:add_param('repeat_count', 'number-range-int', 5, 10) -- "repeat_count" is a required "number-range-int" in a range 5 to 10 inclusive
-- The command parse will be passed 3 arguments plus any other which you define, in our case:
-- 1) input - the input that has been given by the user for this param, the role of this function is to transform this value
-- nb: the input is a string but can be nil if the param is marked as optional
-- 2) player - the player who is using the command, this is always present
-- 3) reject - the reject function to throw an error to the user, this is always present
-- 4) range_min - the range min, this is user defined and has the value given when the param is defined
-- 5) range_max - the range max, this is user defined and has the value given when the param is defined
-- When returning from the param parse you have a few options with how to do this:
-- 1) you return the new value for the param (any non nil value) this value is then passed to the command callback
-- 2) not returning will cause a generic invalid error and the command is rejected, not recommenced
-- 3) return reject -- this is just a failsafe in case the function is not called, same as no return
-- 4) return reject() -- will give a shorter error message as you pass a nil custom error
-- 5) return reject('Number entered is not in range: '..range_min..', '..range_max) -- returns a custom error to the user
-- nb: if you do not return reject after you call it then you will still be returning nil so there will be a duplicate error message
-- It should be noted that if you want to expand on an existing parse you can use Commands.parse(type, input, player, reject)
-- this function will either return a new value for the input or nil, if it is nil you should return nil to prevent duplicate
-- error messages to the user:
input = Commands.parse('number-int', input, player, reject)
if not input then return end -- nil check
-- Example Code:
Commands.add_parse('number-range-int', function(input, player, reject, range_min, range_max)
local rtn = tonumber(input) and math.floor(tonumber(input)) or nil -- converts input to number
if not rtn or rtn < range_min or rtn > range_max then
-- the input is either not a number or is outside the range
return reject('Number entered is not in range: '..range_min..', '..range_max)
else
-- returns the input as a number value rather than a string, thus the param is now the correct type
return rtn
end
end)
]]
local ExpUtil = require("modules/exp_util")
local write_json = ExpUtil.write_json --- @dep expcore.common
local trace = debug.traceback
local Commands = {
--- Constant values used by the command system
defines = {
error = "CommandError",
unauthorized = "CommandErrorUnauthorized",
success = "CommandSuccess",
},
--- An array of all custom commands that are registered
commands = {},
--- When true any authenticator error will result in authorization failure, more secure
authorization_failure_on_error = false,
--- An array of all custom authenticators that are registered
authenticators = {},
--- Used to store default functions which are common parse function such as player or number in range
parsers = {},
--- The command prototype which stores all command defining functions
_prototype = {},
}
local Colours = ExpUtil.color
--- This is copied in so that _C.player_return can be removed
--- Returns a value to the player, different to success as this does not signal the end of your command
function Commands.print(value, colour, player)
colour = type(colour) == "table" and colour or Colours[colour] ~= Colours.white and Colours[colour] or Colours.white
player = player or game.player
local output = ExpUtil.format_any(value)
if player then
player = type(player) == "userdata" and player or game.get_player(player)
if not player then error("Invalid Player given to Commands.print", 2) end
player.print(output, {
color = colour,
sound_path = "utility/scenario_message",
})
else
rcon.print(output)
end
end
--- Authentication.
-- Functions that control who can use commands
-- @section auth
--[[-- Adds an authorization function, function used to check if a player if allowed to use a command
@tparam function authenticator The function you want to register as an authenticator
@treturn number The index it was inserted at, used to remove the authenticator
@usage-- If the admin_only flag is set, then make sure the player is an admin
local admin_authenticator =
Commands.add_authenticator(function(player, command, flags, reject)
if flags.admin_only and not player.admin then
return reject('This command is for admins only!')
else
return true
end
end)
]]
function Commands.add_authenticator(authenticator)
local next_index = #Commands.authenticators + 1
Commands.authenticators[next_index] = authenticator
return next_index
end
--[[-- Removes an authorization function, can use the index or the function value
@tparam function|number authenticator The authenticator to remove, either the index return from add_authenticator or the function used
@treturn boolean If the authenticator was found and removed successfully
@usage-- Removing the admin authenticator, can not be done during runtime
Commands.remove_authenticator(admin_authenticator)
]]
function Commands.remove_authenticator(authenticator)
if type(authenticator) == "number" then
-- If a number is passed then it is assumed to be the index
if Commands.authenticators[authenticator] then
Commands.authenticators[authenticator] = nil
return true
end
else
-- will search the array and remove the key
for index, value in pairs(Commands.authenticators) do
if value == authenticator then
Commands.authenticators[index] = nil
return true
end
end
end
return false
end
--[[-- Mostly used internally, calls all authenticators, returns if the player is authorized
@tparam LuaPlayer player The player who is using the command, passed to authenticators
@tparam string command_name The name of the command being used, passed to authenticators
@treturn[1] boolean true Player is authorized
@treturn[1] string commands Define value for success
@treturn[2] boolean false Player is unauthorized
@treturn[2] string|locale_string The reason given by the failed authenticator
@usage-- Test if a player can use "repeat-name"
local authorized, status = Commands.authorize(game.player, 'repeat-name')
]]
function Commands.authorize(player, command_name)
local command_data = Commands.commands[command_name]
if not command_data then return false end
if not player then return true end
-- This is the reject function given to authenticators
local failure_message
local function reject(message)
failure_message = message or { "expcore-commands.unauthorized" }
return Commands.defines.unauthorized
end
-- This is the internal error function used when an authenticator errors
local function authenticator_error(err)
log("[ERROR] Authorization failed: " .. trace(err))
if Commands.authorization_failure_on_error then
return reject("Internal Error")
end
end
-- Loops over each authenticator, if any return false then then command will not be ran
for _, authenticator in pairs(Commands.authenticators) do
-- player: LuaPlayer, command: string, flags: table, reject: function(error_message: string)
local _, rtn = xpcall(authenticator, authenticator_error, player, command_name, command_data.flags, reject)
if rtn == false or rtn == Commands.defines.unauthorized or rtn == reject or failure_message ~= nil then
if failure_message == nil then failure_message = { "expcore-commands.unauthorized" } end
return false, failure_message
end
end
return true, Commands.defines.success
end
--- Parse.
-- Functions that help with parsing
-- @section parse
--[[-- Adds a parse function which can be called by name (used in add_param)
nb: this is not required as you can use the callback directly this just allows it to be called by name
@tparam string name The name of the parse, should describe a type of input such as number or player, must be unique
@tparam function parser The function that is ran to parse the input string
@treturn boolean Was the parse added, will be false if the name is already used
@usage-- Adding a parse to validate integers in a given range
Commands.add_parse('number-range-int', function(input, player, reject, range_min, range_max)
local rtn = tonumber(input) and math.floor(tonumber(input)) or nil -- converts input to number
if not rtn or rtn < range_min or rtn > range_max then
-- The input is either not a number or is outside the range
return reject('Number entered is not in range: '..range_min..', '..range_max)
else
-- Returns the input as a number rather than a string, thus the param is now the correct type
return rtn
end
end)
]]
function Commands.add_parse(name, parser)
if Commands.parsers[name] then return false end
Commands.parsers[name] = parser
return true
end
--[[-- Removes a parse function, see add_parse for adding them, cant be done during runtime
@tparam string name The name of the parse to remove
@usage-- Removing a parse
Commands.remove_parse('number-range-int')
]]
function Commands.remove_parse(name)
Commands.parsers[name] = nil
end
--[[-- Intended to be used within other parse functions, runs a parse and returns success and new value
@tparam string name The name of the parse to call, must be a registered parser
@tparam string input The input to pass to the parse, must be a string but not necessarily the original input
@tparam LuaPlayer player The player that is using the command, pass directly from your arguments
@tparam function reject The reject function, pass directly from your arguments
@treturn any The new value for the input, if nil is return then either there was an error or the input was nil
@usage-- Parsing an int after first checking it is a number
Commands.add_parse('number', function(input, player, reject)
local number = tonumber(input)
if number then return number end
return reject('Input must be a number value')
end)
Commands.add_parse('number-int', function(input, player, reject)
local number = Commands.parse('number', input, player, reject)
if not number then return end
return math.floor(number)
end)
]]
function Commands.parse(name, input, player, reject, ...)
if not Commands.parsers[name] then return end
local success, rtn = pcall(Commands.parsers[name], input, player, reject, ...)
if not success then
error(rtn, 2)
return
end
if not rtn or rtn == Commands.defines.error then return end
return rtn
end
--- Getters.
-- Functions that get commands
-- @section getters
--[[-- Gets all commands that a player is allowed to use, game commands are not included
@tparam[opt] LuaPlayer player The player that you want to get commands of, nil will return all commands
@treturn table All commands that that player is allowed to use, or all commands
@usage-- Get the commands you are allowed to use
local commands = Commands.get(game.player)
@usage-- Get all commands that are registered
local commands = Commands.get()
]]
function Commands.get(player)
if not player then return Commands.commands end
local allowed = {}
for name, command_data in pairs(Commands.commands) do
if Commands.authorize(player, name) then
allowed[name] = command_data
end
end
return allowed
end
--[[-- Searches command names and help messages to find possible commands, game commands are included
@tparam string keyword The word which you are trying to find in your search
@tparam[opt] LuaPlayer player The player to get allowed commands of, if nil all commands are searched
@treturn table All commands that contain the key word, and allowed by the player if a player was given
@usage-- Get all commands which "repeat"
local commands = Commands.search('repeat')
@usage-- Get all commands which "repeat" and you are allowed to use
local commands = Commands.search('repeat', game.player)
]]
function Commands.search(keyword, player)
local custom_commands = Commands.get(player)
local matches = {}
keyword = keyword:lower()
-- Loops over custom commands
for name, command_data in pairs(custom_commands) do
-- combines name help and aliases into one message to be searched
local search = string.format("%s %s %s %s", name, command_data.help, command_data.searchable_description, table.concat(command_data.aliases, " "))
if search:lower():match(keyword) then
matches[name] = command_data
end
end
-- Loops over the names of game commands
for name, description in pairs(commands.game_commands) do
if name:lower():match(keyword) then
-- because game commands lack some stuff that the custom ones have they are formatted
matches[name] = {
name = name,
help = description,
description = "",
aliases = {},
}
end
end
return matches
end
--- Creation.
-- Functions that create a new command
-- @section creation
--[[-- Creates a new command object to added details to, this does not register the command to the game api
@tparam string name The name of the command to be created
@tparam string help The help message for the command
@treturn table This will be used with other functions to define the new command
@usage-- Define a new command
Commands.new_command('repeat-name', 'Will repeat you name a number of times in chat.')
]]
function Commands.new_command(name, help, descr)
local command = setmetatable({
name = name,
help = help,
searchable_description = descr or "",
callback = function() Commands.internal_error(false, name, "No callback registered") end,
auto_concat = false,
min_param_count = 0,
max_param_count = 0,
flags = {}, -- stores flags that can be used by auth
aliases = {}, -- stores aliases to this command
params = {}, -- [param_name] = {optional: boolean, default: any, parse: function, parse_args: table}
}, {
__index = Commands._prototype,
})
Commands.commands[name] = command
return command
end
--[[-- Adds a new param to the command this will be displayed in the help and used to parse the input
@tparam string name The name of the new param that is being added to the command
@tparam[opt=false] boolean optional Is this param optional, these must be added after all required params
@tparam[opt] ?string|function parse This function will take the input and return a new value, if not given no parse is done
@tparam[opt] any ... Extra args you want to pass to the parse function; for example if the parse is general use
@treturn table Pass through to allow more functions to be called
@usage-- Adding a required param which has a parser pre-defined
command:add_param('repeat-count', 'number-range-int', 1, 5)
@usage-- Adding an optional param which has a custom parse, see Commands.add_parse for details
command:add_param('smiley', true, function(input, player, reject)
if not input then return end
return input:lower() == 'true' or input:lower() == 'yes' or false
end)
]]
function Commands._prototype:add_param(name, optional, parse, ...)
local parse_args = { ... }
if type(optional) ~= "boolean" then
parse_args = { parse, ... }
parse = optional
optional = false
end
self.params[name] = {
optional = optional,
parse = parse or function(string) return string end,
parse_args = parse_args,
}
self.max_param_count = self.max_param_count + 1
if not optional then
self.min_param_count = self.min_param_count + 1
end
return self
end
--[[-- Add default values to params, only as an effect if the param is optional, if default value is a function it is called with the acting player
@tparam table defaults A table which is keyed by the name of the param and the value is the default value for that param
@treturn table Pass through to allow more functions to be called
@usage-- Adding default values
command:set_defaults{
smiley = false,
-- not in example just used to show arguments given
player_name = function(player)
return player.name
end
}
]]
function Commands._prototype:set_defaults(defaults)
for name, value in pairs(defaults) do
if self.params[name] then
self.params[name].default = value
end
end
return self
end
--[[-- Adds a flag to the command which is passed via the flags param to the authenticators, can be used to assign command roles or usage type
@tparam string name The name of the flag to be added, set to true if no value is given
@tparam[opt=true] any value The value for the flag, can be anything that the authenticators are expecting
@treturn table Pass through to allow more functions to be called
@usage-- Setting a custom flag
command:set_flag('admin_only', true)
@usage-- When value is true it does not need to be given
command:set_flag('admin_only')
]]
function Commands._prototype:set_flag(name, value)
self.flags[name] = value or true
return self
end
--[[-- Adds an alias, or multiple, that will be registered to this command, eg /teleport can be used as /tp
@tparam string ... Any amount of aliases that you want this command to be callable with
@treturn table Pass through to allow more functions to be called
@usage-- Added multiple aliases to a command
command:add_alias('name', 'rname')
]]
function Commands._prototype:add_alias(...)
local start_index = #self.aliases
for index, alias in ipairs{ ... } do
self.aliases[start_index + index] = alias
end
return self
end
--[[-- Enables auto concatenation for this command, all params after the last are added to the last param, useful for reasons or other long text input
nb: this will disable max param checking as they will be concatenated onto the end of that last param
@treturn table Pass through to allow more functions to be called
@usage-- Enable auto concat for a command
command:enable_auto_concat()
]]
function Commands._prototype:enable_auto_concat()
self.auto_concat = true
return self
end
--[[-- Adds the callback to the command and registers: aliases, params and help message with the base game api
nb: this must be the last function ran on the command and must be done for the command to work
@tparam function callback The callback for the command, will receive the player running command, and any params added with add_param
@usage-- Registering your command to the base game api
command:register(function(player, repeat_count, smiley, raw)
local msg = ') '..player.name
if smiley then msg = ':'..msg end
for 1 = 1, repeat_count do
Command.print(1..msg)
end
end)
]]
function Commands._prototype:register(callback)
self.callback = callback
-- Generates a description to be used
local description = ""
for param_name, param_details in pairs(self.params) do
if param_details.optional then
description = string.format("%s [%s]", description, param_name)
else
description = string.format("%s <%s>", description, param_name)
end
end
self.description = description
-- Last resort error handler for commands
local function command_error(err)
Commands.internal_error(false, self.name, trace(err))
end
-- Callback that the game will call
local function command_callback(event)
event.name = self.name
xpcall(Commands.run_command, command_error, event)
end
-- Registers the command under its own name
local help = { "expcore-commands.command-help", description, self.help }
commands.add_command(self.name, help, command_callback)
-- Adds any aliases that it has
for _, alias in pairs(self.aliases) do
if not commands.commands[alias] and not commands.game_commands[alias] then
commands.add_command(alias, help, command_callback)
end
end
end
--- Status.
-- Functions that indicate status
-- @section status
--[[-- Sends a value to the player, followed by a command complete message, returning a value will trigger this automatically
@tparam[opt] any value The value to return to the player, if nil then only the success message is returned
@treturn Commands.defines.success Return this to the command handler to prevent two success messages
@usage-- Print a custom success message
return Commands.success('Your message has been printed')
@usage-- Returning the value has the same result
return 'Your message has been printed'
]]
function Commands.success(value)
if value ~= nil then Commands.print(value) end
Commands.print({ "expcore-commands.command-ran" }, "cyan")
return Commands.defines.success
end
--[[-- Sends a value to the player, different to success as this does not signal the end of your command
@function print
@tparam any value The value that you want to return to the player
@tparam table colour The colour of the message that the player sees
@usage-- Output a message to the player
Commands.print('Your command is in progress')
]]
--[[-- Sends an error message to the player and when returned will stop execution of the command
nb: this is for non fatal errors meaning there is no log of this event, use during register callback
@tparam[opt=''] string error_message An optional error message that can be sent to the user
@tparam[opt=utility/wire_pickup] string play_sound The sound to play for the error
@treturn Commands.defines.error Return this to command handler to terminate execution
@usage-- Send an error message to the player, and stops further code running
return Commands.error('The player you selected is offline')
]]
function Commands.error(error_message, play_sound)
error_message = error_message or ""
Commands.print({ "expcore-commands.command-fail", error_message }, "orange_red")
if play_sound ~= false then
play_sound = play_sound or "utility/wire_pickup"
if game.player then game.player.play_sound{ path = play_sound } end
end
return Commands.defines.error
end
--[[-- Sends an error to the player and logs the error, used internally please avoid direct use
nb: use error(error_message) within your callback to trigger do not trigger directly as code execution may still continue
@tparam boolean success The success value returned from pcall, or just false to trigger error
@tparam string command_name The name of the command this is used within the log
@tparam string error_message The error returned by pcall or some other error, this is logged and not returned to player
@treturn boolean The opposite of success so true means to cancel execution, used internally
@usage-- Used in the command system to log handler errors
local success, err = pcall(command_data.callback, player, table.unpack(params))
if Commands.internal_error(success, command_data.name, err) then
return command_log(player, command_data, 'Internal Error: Command Callback Fail', raw_params, command_event.parameter, err)
end
]]
function Commands.internal_error(success, command_name, error_message)
if not success then
Commands.error("Internal Error, Please contact an admin", "utility/cannot_build")
log{ "expcore-commands.command-error-log-format", command_name, error_message }
end
return not success
end
--- Logs command usage to file
local function command_log(player, command, comment, params, raw, details)
local player_name = player and player.name or "<Server>"
write_json("log/commands.log", {
player_name = player_name,
command_name = command.name,
comment = comment,
details = details,
params = params,
raw = raw,
})
end
--- Main event function that is ran for all commands, used internally please avoid direct use
-- @tparam table command_event Passed directly from the add_command function
-- @usage Commands.run_command(event)
function Commands.run_command(command_event)
local command_data = Commands.commands[command_event.name]
-- Player can be nil when it is the server
local player
if command_event.player_index and command_event.player_index > 0 then
player = game.players[command_event.player_index]
end
-- Check if the player is allowed to use the command
local authorized, auth_fail = Commands.authorize(player, command_data.name)
if not authorized then
command_log(player, command_data, "Failed Auth", {}, command_event.parameter)
Commands.error(auth_fail, "utility/cannot_build")
return
end
-- Check for parameter being nil
if command_data.min_param_count > 0 and not command_event.parameter then
command_log(player, command_data, "No Params Given", {}, command_event.parameter)
Commands.error{ "expcore-commands.invalid-inputs", command_data.name, command_data.description }
return
end
-- Extract quoted arguments
local raw_input = command_event.parameter or ""
local quote_params = {}
local input_string = raw_input:gsub('"[^"]-"', function(word)
local no_spaces = word:gsub("%s", "%%s")
quote_params[no_spaces] = word:sub(2, -2)
return " " .. no_spaces .. " "
end)
-- Extract unquoted arguments
local raw_params = {}
local last_index = 0
local param_number = 0
for word in input_string:gmatch("%S+") do
param_number = param_number + 1
if param_number > command_data.max_param_count then
-- there are too many params given to the command
if not command_data.auto_concat then
-- error as they should not be more
command_log(player, command_data, "Invalid Input: Too Many Params", raw_params, raw_input)
Commands.error{ "expcore-commands.invalid-inputs", command_data.name, command_data.description }
return
else
-- concat to the last param
if quote_params[word] then
raw_params[last_index] = raw_params[last_index] .. ' "' .. quote_params[word] .. '"'
else
raw_params[last_index] = raw_params[last_index] .. " " .. word
end
end
else
-- new param that needs to be added
if quote_params[word] then
last_index = last_index + 1
raw_params[last_index] = quote_params[word]
else
last_index = last_index + 1
raw_params[last_index] = word
end
end
end
-- Check the param count
local param_count = #raw_params
if param_count < command_data.min_param_count then
command_log(player, command_data, "Invalid Input: Not Enough Params", raw_params, raw_input)
Commands.error{ "expcore-commands.invalid-inputs", command_data.name, command_data.description }
return
end
-- Parse the arguments
local index = 1
local params = {}
for param_name, param_data in pairs(command_data.params) do
local parse_callback = param_data.parse
-- If its a string this get it from the parser table
if type(parse_callback) == "string" then
parse_callback = Commands.parsers[parse_callback]
end
-- If its not a function throw and error
if type(parse_callback) ~= "function" then
Commands.internal_error(false, command_data.name, "Invalid param parse " .. tostring(param_data.parse))
command_log(player, command_data, "Internal Error: Invalid Param Parse", params, raw_input, tostring(param_data.parse))
return
end
-- This is the reject function given to parse callbacks
local function reject(error_message)
error_message = error_message or ""
command_log(player, command_data, "Invalid Param Given", raw_params, input_string)
return Commands.error{ "expcore-commands.invalid-param", param_name, error_message }
end
-- input: string, player: LuaPlayer, reject: function, ... extra args
local success, param_parsed = pcall(parse_callback, raw_params[index], player, reject, table.unpack(param_data.parse_args))
if Commands.internal_error(success, command_data.name, param_parsed) then
return command_log(player, command_data, "Internal Error: Param Parse Fail", params, raw_input, param_parsed)
end
if param_data.optional == true and raw_params[index] == nil then
-- If the param is optional and nil then it is set to default
param_parsed = param_data.default
if type(param_parsed) == "function" then
success, param_parsed = pcall(param_parsed, player)
if Commands.internal_error(success, command_data.name, param_parsed) then
return command_log(player, command_data, "Internal Error: Default Value Fail", params, raw_input, param_parsed)
end
end
elseif param_parsed == nil or param_parsed == Commands.defines.error or param_parsed == reject then
-- No value was returned or error was returned, if nil then give generic error
if param_parsed ~= Commands.defines.error then
command_log(player, command_data, "Invalid Param Given", raw_params, raw_input, param_name)
Commands.error{ "expcore-commands.command-error-param-format", param_name, "please make sure it is the correct type" }
end
return
end
-- Add the param to the table to be passed to the command callback
params[index] = param_parsed
index = index + 1
end
-- Run the command
-- player: LuaPlayer, ... command params, raw: string
params[command_data.max_param_count + 1] = raw_input
local success, rtn = pcall(command_data.callback, player, table.unpack(params))
if Commands.internal_error(success, command_data.name, rtn) then
return command_log(player, command_data, "Internal Error: Command Callback Fail", raw_params, command_event.parameter, rtn)
end
-- Give output to the player
if rtn == Commands.defines.error or rtn == Commands.error then
return command_log(player, command_data, "Custom Error", raw_params, raw_input)
elseif rtn ~= Commands.defines.success and rtn ~= Commands.success then
Commands.success(rtn)
end
command_log(player, command_data, "Success", raw_params, raw_input)
end
return Commands

View File

@@ -195,7 +195,7 @@ Gui.toggle_top_flow(game.player, true)
]] ]]
function Gui.toggle_top_flow(player, state) function Gui.toggle_top_flow(player, state)
-- Get the top flow, we need the parent as we want to toggle the outer frame -- Get the top flow, we need the parent as we want to toggle the outer frame
local top_flow = Gui.get_top_flow(player).parent local top_flow = Gui.get_top_flow(player).parent --- @cast top_flow -nil
if state == nil then state = not top_flow.visible end if state == nil then state = not top_flow.visible end
-- Get the show button for the top flow -- Get the show button for the top flow

View File

@@ -44,8 +44,7 @@ end)
local Async = require("modules/exp_util/async") local Async = require("modules/exp_util/async")
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
local Datastore = require("modules.exp_legacy.expcore.datastore") --- @dep expcore.datastore local Datastore = require("modules.exp_legacy.expcore.datastore") --- @dep expcore.datastore
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands local Commands = require("modules/exp_commands")
require("modules.exp_legacy.config.expcore.command_general_parse") --- @dep config.expcore.command_general_parse
local table_to_json = helpers.table_to_json local table_to_json = helpers.table_to_json
local write_file = helpers.write_file local write_file = helpers.write_file
@@ -67,23 +66,20 @@ DataSavingPreference:set_metadata{
} }
--- Sets your data saving preference --- Sets your data saving preference
-- @command set-data-preference Commands.new("data-preference", { "expcore-data.description-preference" })
Commands.new_command("set-preference", "Allows you to set your data saving preference") :optional("option", { "expcore-data.arg-option" }, Commands.types.enum(PreferenceEnum))
:add_param("option", false, "string-options", PreferenceEnum)
:register(function(player, option) :register(function(player, option)
DataSavingPreference:set(player, option) --- @cast option "All" | "Statistics" | "Settings" | "Required" | nil
return { "expcore-data.set-preference", option } if option then
end) DataSavingPreference:set(player, option)
return Commands.status.success{ "expcore-data.set-preference", option }
--- Gets your data saving preference else
-- @command data-preference return Commands.status.success{ "expcore-data.get-preference", DataSavingPreference:get(player) }
Commands.new_command("preference", "Shows you what your current data saving preference is") end
:register(function(player)
return { "expcore-data.get-preference", DataSavingPreference:get(player) }
end) end)
--- Gets your data and writes it to a file --- Gets your data and writes it to a file
Commands.new_command("save-data", "Writes all your player data to a file on your computer") Commands.new("save-data", { "expcore-data.description-data" })
:register(function(player) :register(function(player)
player.print{ "expcore-data.get-data" } player.print{ "expcore-data.get-data" }
write_file("expgaming_player_data.json", table_to_json(PlayerData:get(player, {})), false, player.index) write_file("expgaming_player_data.json", table_to_json(PlayerData:get(player, {})), false, player.index)

View File

@@ -311,6 +311,15 @@ function Roles.get_role_from_any(any)
end end
end end
--- Returns all roles in order of index
function Roles.get_roles_ordered()
local rtn = {}
for index, role_name in ipairs(Roles.config.order) do
rtn[index] = Roles.config.roles[role_name]
end
return rtn
end
--[[-- Gets all the roles of the given player, this will always contain the default role --[[-- Gets all the roles of the given player, this will always contain the default role
@tparam LuaPlayer player the player to get the roles of @tparam LuaPlayer player the player to get the roles of
@treturn table a table where the values are the roles which the player has @treturn table a table where the values are the roles which the player has

View File

@@ -1,245 +0,0 @@
[expcom-admin-chat]
description=Sends a message in chat that only admins can see.
format=[Admin Chat] __1__: __2__
[expcom-admin-marker]
description=Toggles admin marker mode, new markers can only be edited by admins
exit=You have left admin marker mode, all new markers will not be protected.
enter=You have entered admin marker mode, all new markers will be protected.
place=You have placed an admin marker.
edit=You have edited an admin marker.
revert=You cannot edit admin markers.
[expcom-artillery]
description=Artillery Target Remote
[expcom-bonus]
description=Changes the amount of bonus you receive
set=Your bonus has been set to __1__.
perm=You dont have enough permission to set more than __1__.
[expcom-bot-queue]
description-get=Get bot queue
description-set=Set bot queue
result=__1__ set the bot queue to __2__ successful attempts and __3__ failed attempts
[expcom-cheat]
description-cheat=Toggles cheat mode for your player, or another player.
description-res=Set all research for your force.
description-day=Toggles always day in surface.
res=__1__ has enabled all technologies
day=__1__ set always day to __2__
[expcom-chelp]
description=Searches for a keyword in all commands you are allowed to use.
title=Help results for "__1__":
footer=[__1__ results found: page __2__ of __3__]
format=/__1__ __2__ - __3__ __4__
alias=Alias: __1__
out-of-range=__1__ is an invalid page number.
[expcom-clr-inv]
description=Clears a players inventory
[expcom-connect]
description=Connect to another server
description-player=Send a player to a different server
description-all=Connect all players to another server
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 pannel for viewing tables.
[expcom-enemy]
description-kill=Kill all biters only
description-remove=Remove biters and prevent generation
[expcom-ff]
description=Toggle friendly fire
ff=__1__ set friendly fire to __2__
[expcom-find]
description=Find a player on your map.
[expcom-home]
description-home=Teleports you to your home location
description-home-set=Sets your home location to your current position
description-home-get=Returns your current home location
description-return=Teleports you to previous location
no-home=You have no home set.
no-return=You can't return when home has not yet been used.
home-set=Your home point has been set to x: __1__ y: __2__
return-set=Your return point has been set to x: __1__ y: __2__
home-get=Your home point is at x: __1__ y: __2__
[expcom-interface]
description=Sends an invocation to be ran and returns the result.
[expcom-inv-search]
description-ia=Display players sorted by the quantity of an item held
description-ir=Display players who hold an item sorted by join time
description-i=Display players sorted by the quantity of an item held and playtime
description-io=Display online players sorted by the quantity of an item held and playtime
reject-item=No item was found with internal name __1__; try using rich text selection.
results-heading=Players found with [item=__1__]:
results-item=__1__) __2__ has __3__ items. (__4__)
results-none=No players have [item=__1__]
[expcom-jail]
description-jail=Puts a player into jail and removes all other roles.
description-unjail=Removes a player from jail.
give=__1__ was jailed by __2__. Reason: __3__
remove=__1__ was unjailed by __2__.
already-jailed=__1__ is already in jail.
not-jailed=__1__ is not currently in jail.
[expcom-join-message]
description-msg=Sets your custom join message
description-clr=Clear your join message
[expcom-kill]
description=Kills yourself or another player.
already-dead=You are already dead.
[expcom-lawnmower]
description=Clean up biter corpse, decoratives and nuclear hole
[expcom-lastlocation]
description=Sends you the last location of a player
response=Last location of __1__ was [gps=__2__,__3__]
[expcom-me]
description=Sends an action message in the chat
[expcom-personal-logistics]
description=Set Personal Logistic (-1 to cancel all) (Select spidertron to edit spidertron)
[expcom-pol]
description-clr=Clear pollution
description-off=Disable pollution
clr=__1__ cleared the pollution.
off=__1__ disabled the pollution.
[expcom-protection]
description-pe=Toggles entity protection selection, hold shift to remove protection
description-pa=Toggles area protection selection, hold shift to remove protection
entered-entity-selection=Entered entity selection, select entites to protect, hold shift to remove protection.
entered-area-selection=Entered area selection, select areas to protect, hold shift to remove protection.
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__]
[expcom-quickbar]
description=Saves your quickbar preset items to file
[expcom-rainbow]
description=Sends an rainbow message in the chat
[expcom-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.
notSelecting=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.
machines=And you will need __1__ machines (with the same speed as this one) for this.
[expcom-repair]
description=Repairs entities on your force around you
result=__1__ entites were revived and __2__ were healed to max health.
[expcom-report]
description-report=Reports a player and notifies moderators
description-get-reports=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-reports=Clears all reports from a player or just the report from one player.
player-immune=This player can not be reported.
self-report=You cannot report yourself.
non-admin=__1__ was reported for __2__.
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.
player-count-title=The following players have reports against them:
player-report-title=__1__ has the following reports against them:
list=__1__: __2__
removed=__1__ has one or more reports removed by __2__.
[expcom-res]
description-ares=Automatically queue up research
res=__1__ set auto research to __2__
msg=[color=255, 255, 255] Research completed at __1__ - [technology=__2__][/color]
inf=[color=255, 255, 255] Research completed at __1__ - [technology=__2__] - __3__[/color]
inf-q=[color=255, 255, 255] Research added to queue - [technology=__1__] - __2__[/color]
res-name=[technology=__1__] __2__
name=Name
target=Target
attempt=Attempt
difference=Diff
main-tooltip=Research GUI
[expcom-roles]
description-assign-role=Assigns a role to a player
description-unassign-role=Unassigns a role from a player
description-list-roles=Lists all roles in they correct order
higher-role=The role you tried to assign is higher than your highest.
list=All roles are: __1__
list-player=__1__ has: __2__
list-element=__1__, __2__
[expcom-server-ups]
no-ext=No external source was found, cannot display server ups.
[expcom-spawn]
description=Teleport to spawn
unavailable=They was a problem getting you to spawn, please try again later.
[expcom-spectate]
description-spectate=Toggles spectator mode
description-follow=Start following a player in spectator
follow-self=You can not follow yourself
[expcom-speed]
description=Set game speed
result=__1__ set the game speed to __2__
[expcom-surface-clearing]
description-ci=Clear Item On Ground
description-cb=Clear Blueprint
[expcom-tag]
description=Sets your player tag.
description-clear=Clears your tag. Or another player if you are admin.
[expcom-tp]
description-tp=Teleports a player to another player.
description-bring=Teleports a player to you.
description-goto=Teleports you to a player.
no-position-found=No position to teleport to was found, please try again later.
to-self=Player can not be teleported to themselves.
[expcom-train]
description=Set All Trains to Automatic
manual-result=__1__ put __2__ trains into automatic mode
[expcom-warnings]
description-give=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
received=__1__ received a warning from __2__ for __3__.
player=__1__ has __2__ warnings and __3__/__4__ script warnings.
player-detail=__1__ gave warning for: __2__
list-title=The following players have this many warnings (and this many script warnings):
list=__1__: __2__ (__3__/__4__)
cleared=__1__ had all their warnings cleared by __2__.
[expcom-waterfill]
description=Change tile to water
waterfill-distance=Too close to designated location
waterfill-cliff=Not enough cliff explosive to create water
entered-area-selection=Entered area selection, select areas to convert.

View File

@@ -1,3 +0,0 @@
[command-auth]
admin-only=This command is for (game) admins only!
command-disabled=This command has been disabled by management!

View File

@@ -1,6 +1,10 @@
[join-message] [join-message]
description-add=Sets / Gets your custom join message.
description-remove=Removes you custom join message.
arg-message=Your custom join message.
greet=[color=0,1,0] Welcome to explosive gaming community server! If you like the server join our discord: __1__ [/color] greet=[color=0,1,0] Welcome to explosive gaming community server! If you like the server join our discord: __1__ [/color]
message-set=Your join message has been updated. message-set=Your join message has been updated.
message-get=Your join message is: __1__
message-cleared=Your join message has been cleared. message-cleared=Your join message has been cleared.
[quickbar] [quickbar]

View File

@@ -1,29 +1,3 @@
time-symbol-days-short=__1__d
color-tag=[color=__1__]__2__[/color]
[time-format]
simple-format-tagged=__1__ __2__
simple-format-div=__1__:__2__
[expcore-commands]
unauthorized=Unauthorized, Access is denied due to invalid credentials
reject-string-options=Invalid Option, Must be one of: __1__
reject-string-max-length=Invalid Length, Max: __1__
reject-number=Invalid Number.
reject-number-range=Invalid Range, Min (inclusive): __1__, Max (inclusive): __2__
reject-player=Invalid Player Name, __1__ ,try using tab key to auto-complete the name
reject-player-online=Player is offline.
reject-player-alive=Player is dead.
reject-force=Invalid Force Name.
reject-surface=Invalid Surface Name.
reject-color=Invalid Color Name.
invalid-inputs=Invalid Input, /__1__ __2__
invalid-param=Invalid Param "__1__"; __2__
command-help=__1__ - __2__
command-ran=Command Complete
command-fail=Command failed to run: __1__
command-error-log-format=[ERROR] command/__1__ :: __2__
[expcore-roles] [expcore-roles]
error-log-format-flag=[ERROR] roleFlag/__1__ :: __2__ error-log-format-flag=[ERROR] roleFlag/__1__ :: __2__
error-log-format-assign=[ERROR] rolePromote/__1__ :: __2__ error-log-format-assign=[ERROR] rolePromote/__1__ :: __2__
@@ -39,6 +13,8 @@ button_tooltip=Shows/hides the toolbar.
left-button-tooltip=Hide all open windows. left-button-tooltip=Hide all open windows.
[expcore-data] [expcore-data]
description-preference=Allows you to set/get your data saving preference.
description-data=Writes all your player data to a file on your computer.
set-preference=You data saving preference has been set to __1__. Existing data will not be effected until you rejoin. set-preference=You data saving preference has been set to __1__. Existing data will not be effected until you rejoin.
get-preference=You data saving preference is __1__. Use /set-preference to change this. Use /save-data to get a local copy of your data. get-preference=You data saving preference is __1__. Use /set-preference to change this. Use /save-data to get a local copy of your data.
get-data=Your player data has been writen to file, location: factorio/script_output/expgaming_player_data.json get-data=Your player data has been writen to file, location: factorio/script_output/expgaming_player_data.json

View File

@@ -210,6 +210,11 @@ disabled=disabled
toggle-msg=Fast decon has been __1__ toggle-msg=Fast decon has been __1__
[bonus] [bonus]
description=Get / Set the amount of bonus you receive.
arg-amount=Amount to set your bonus to, 0 will disable bonus.
set=Your bonus has been set to __1__.
get=Your bonus is __1__.
perm=You dont have enough permission to set more than __1__.
main-tooltip=Bonus main-tooltip=Bonus
control-pts-a=Points available control-pts-a=Points available
control-pts-n=Points needed control-pts-n=Points needed
@@ -319,3 +324,17 @@ reset=Reset All
toggle=Toggle Favourites toggle=Toggle Favourites
move-up=Move Up move-up=Move Up
move-down=Move Down move-down=Move Down
[research]
msg=[color=255, 255, 255] Research completed at __1__ - [technology=__2__][/color]
inf=[color=255, 255, 255] Research completed at __1__ - [technology=__2__] - __3__[/color]
res-name=[technology=__1__] __2__
name=Name
target=Target
attempt=Attempt
difference=Diff
main-tooltip=Research GUI
[server-ups]
description=Toggle the server UPS display.
no-ext=No external source was found, cannot display server ups.

View File

@@ -1,60 +0,0 @@
--[[-- Addon Lawnmower
- Adds a command that clean up biter corpse and nuclear hole
@addon Lawnmower
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
local config = require("modules.exp_legacy.config.lawnmower") --- @dep config.lawnmower
require("modules.exp_legacy.config.expcore.command_general_parse")
Commands.new_command("lawnmower", "Clean up biter corpse, decoratives and nuclear hole")
:add_param("range", false, "integer-range", 1, 200)
:register(function(player, range)
local tile_to_do = {}
-- Intentionally left as player.position to allow use in remote view
player.surface.destroy_decoratives{ position = player.position, radius = range }
local entities = player.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 tiles = player.surface.find_tiles_filtered{ position = player.position, radius = range, name = { "nuclear-ground" } }
for _, tile in pairs(tiles) do
table.insert(tile_to_do, { name = "grass-1", position = tile.position })
end
player.surface.set_tiles(tile_to_do)
return Commands.success
end)
local function destroy_decoratives(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
if config.destroy_decoratives then
Event.add(defines.events.on_built_entity, function(event)
destroy_decoratives(event.created_entity)
end)
Event.add(defines.events.on_robot_built_entity, function(event)
destroy_decoratives(event.created_entity)
end)
Event.add(defines.events.script_raised_built, function(event)
destroy_decoratives(event.entity)
end)
Event.add(defines.events.script_raised_revive, function(event)
destroy_decoratives(event.entity)
end)
end

View File

@@ -1,28 +0,0 @@
--[[-- Commands Module - Admin Chat
- Adds a command that allows admins to talk in a private chat
@commands Admin-Chat
]]
local ExpUtil = require("modules/exp_util")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local format_player_name = ExpUtil.format_player_name_locale --- @dep expcore.common
require("modules.exp_legacy.config.expcore.command_general_parse")
--- Sends a message in chat that only admins can see
-- @command admin-chat
-- @tparam string message the message to send in the admin chat
Commands.new_command("admin-chat", { "expcom-admin-chat.description" }, "Sends a message in chat that only admins can see.")
:add_param("message", false)
:enable_auto_concat()
:set_flag("admin_only")
:add_alias("ac")
:register(function(player, message)
local player_name_colour = format_player_name(player)
for _, return_player in pairs(game.connected_players) do
if return_player.admin then
return_player.print{ "expcom-admin-chat.format", player_name_colour, message }
end
end
return Commands.success -- prevents command complete message from showing
end)

View File

@@ -1,88 +0,0 @@
--[[-- Commands Module - Admin Markers
- Adds a command that creates map markers which can only be edited by admins
@commands Admin-Markers
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Storage = require("modules/exp_util/storage")
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
local admins = {} -- Stores all players in admin marker mode
local markers = {} -- Stores all admin markers
--- Storage variables
Storage.register({
admins = admins,
markers = markers,
}, function(tbl)
admins = tbl.admins
markers = tbl.markers
end)
--- Toggle admin marker mode, can only be applied to yourself
-- @command admin-marker
Commands.new_command("admin-marker", { "expcom-admin-marker.description" }, "Toggles admin marker mode, new markers can only be edited by admins")
:set_flag("admin_only")
:add_alias("am", "admin-markers")
:register(function(player)
if admins[player.name] then
-- Exit admin mode
admins[player.name] = nil
return Commands.success{ "expcom-admin-marker.exit" }
else
-- Enter admin mode
admins[player.name] = true
return Commands.success{ "expcom-admin-marker.enter" }
end
end)
--- Listen for new map markers being added, add admin marker if done by player in admin mode
Event.add(defines.events.on_chart_tag_added, function(event)
if not event.player_index then return end
local player = game.players[event.player_index]
if not admins[player.name] then return end
local tag = event.tag
markers[tag.force.name .. tag.tag_number] = true
Commands.print({ "expcom-admin-marker.place" }, nil, player)
end)
--- Listen for players leaving the game, leave admin mode to avoid unexpected admin markers
Event.add(defines.events.on_player_left_game, function(event)
if not event.player_index then return end
local player = game.players[event.player_index]
admins[player.name] = nil
end)
--- Listen for tags being removed or edited, maintain tags edited by non admins
local function maintain_tag(event)
local tag = event.tag
if not event.player_index then return end
if not markers[tag.force.name .. tag.tag_number] then return end
local player = game.players[event.player_index]
if player.admin then
-- Player is admin, tell them it was an admin marker
Commands.print({ "expcom-admin-marker.edit" }, nil, player)
elseif event.name == defines.events.on_chart_tag_modified then
-- Tag was modified, revert the changes
tag.text = event.old_text
tag.last_user = event.old_player
if event.old_icon then tag.icon = event.old_icon end
player.play_sound{ path = "utility/wire_pickup" }
Commands.print({ "expcom-admin-marker.revert" }, nil, player)
else
-- Tag was removed, remake the tag
player.play_sound{ path = "utility/wire_pickup" }
Commands.print({ "expcom-admin-marker.revert" }, "orange_red", player)
local new_tag = tag.force.add_chart_tag(tag.surface, {
last_user = tag.last_user,
position = tag.position,
icon = tag.icon,
text = tag.text,
})
markers[tag.force.name .. tag.tag_number] = nil
markers[new_tag.force.name .. new_tag.tag_number] = true
end
end
Event.add(defines.events.on_chart_tag_modified, maintain_tag)
Event.add(defines.events.on_chart_tag_removed, maintain_tag)

View File

@@ -1,81 +0,0 @@
--[[-- Commands Module - Artillery
- Adds a command that help shot artillery
@commands Artillery
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
local Selection = require("modules.exp_legacy.modules.control.selection") --- @dep modules.control.selection
local SelectionArtyArea = "ArtyArea"
local function location_break(player, pos)
-- Intentionally left as player.surface to allow use in remote view
if player.force.is_chunk_charted(player.surface, { x = math.floor(pos.left_top.x / 32), y = math.floor(pos.left_top.y / 32) }) then
return true
elseif player.force.is_chunk_charted(player.surface, { x = math.floor(pos.left_top.x / 32), y = math.floor(pos.right_bottom.y / 32) }) then
return true
elseif player.force.is_chunk_charted(player.surface, { x = math.floor(pos.right_bottom.x / 32), y = math.floor(pos.left_top.y / 32) }) then
return true
elseif player.force.is_chunk_charted(player.surface, { x = math.floor(pos.right_bottom.x / 32), y = math.floor(pos.right_bottom.y / 32) }) then
return true
else
return false
end
end
--- align an aabb to the grid by expanding it
local function aabb_align_expand(aabb)
return {
left_top = { x = math.floor(aabb.left_top.x), y = math.floor(aabb.left_top.y) },
right_bottom = { x = math.ceil(aabb.right_bottom.x), y = math.ceil(aabb.right_bottom.y) },
}
end
--- when an area is selected to add protection to the area
Selection.on_selection(SelectionArtyArea, function(event)
local area = aabb_align_expand(event.area)
local player = game.players[event.player_index]
if player == nil then
return
end
if not (game.players[event.player_index].cheat_mode or location_break(player, event.area)) then
return Commands.error
end
local count = 0
local hit = {}
for _, e in pairs(player.surface.find_entities_filtered{ area = area, type = { "unit-spawner", "turret" }, force = "enemy" }) do
local skip = false
for _, pos in ipairs(hit) do
if math.sqrt(math.abs(e.position.x - pos.x) ^ 2 + math.abs(e.position.y - pos.y) ^ 2) < 6 then
skip = true
break
end
end
if not skip then
player.surface.create_entity{ name = "artillery-flare", position = e.position, force = player.force, life_time = 240, movement = { 0, 0 }, height = 0, vertical_speed = 0, frame_speed = 0 }
table.insert(hit, e.position)
count = count + 1
if count > 400 then
break
end
end
end
end)
Commands.new_command("artillery-target-remote", { "expcom-artillery.description" }, "Artillery Target Remote")
:register(function(player)
if Selection.is_selecting(player, SelectionArtyArea) then
Selection.stop(player)
else
Selection.start(player, SelectionArtyArea)
end
return Commands.success
end)

View File

@@ -1,25 +0,0 @@
--[[-- Commands Module - Bot queue
- Adds a command that allows changing bot queue
@commands Bot Queue
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
Commands.new_command("bot-queue-get", { "expcom-bot-queue.description-get" }, "Get bot queue")
:set_flag("admin_only")
:register(function(player)
local s = player.force.max_successful_attempts_per_tick_per_construction_queue
local f = player.force.max_failed_attempts_per_tick_per_construction_queue
return Commands.success{ "expcom-bot-queue.result", player.name, s, f }
end)
Commands.new_command("bot-queue-set", { "expcom-bot-queue.description-set" }, "Set bot queue")
:add_param("amount", "integer-range", 1, 20)
:set_flag("admin_only")
:register(function(player, amount)
player.force.max_successful_attempts_per_tick_per_construction_queue = 3 * amount
player.force.max_failed_attempts_per_tick_per_construction_queue = 1 * amount
game.print{ "expcom-bot-queue.result", player.name, 3 * amount, 1 * amount }
return Commands.success
end)

View File

@@ -1,46 +0,0 @@
--[[-- Commands Module - Cheat Mode
- Adds a command that allows players to enter cheat mode
@commands Cheat-Mode
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
--- Toggles cheat mode for your player, or another player.
-- @command toggle-cheat-mode
-- @tparam[opt=self] LuaPlayer player player to toggle chest mode of, can be nil for self
Commands.new_command("toggle-cheat-mode", { "expcom-cheat.description-cheat" }, "Toggles cheat mode for your player, or another player.")
:add_param("player", true, "player")
:set_defaults{ player = function(player)
return player -- default is the user using the command
end }
:set_flag("admin_only")
:register(function(_, player)
player.cheat_mode = not player.cheat_mode
return Commands.success
end)
Commands.new_command("research-all", { "expcom-cheat.description-res" }, "Set all research for your force.")
:set_flag("admin_only")
:add_param("force", true, "force")
:set_defaults{ force = function(player)
return player.force
end }
:register(function(player, force)
force.research_all_technologies()
game.print{ "expcom-cheat.res", player.name }
return Commands.success
end)
Commands.new_command("toggle-always-day", { "expcom-cheat.description-day" }, "Toggles always day in surface.")
:set_flag("admin_only")
:add_param("surface", true, "surface")
:set_defaults{ surface = function(player)
-- Intentionally left as player.surface to allow use in remote view
return player.surface
end }
:register(function(player, surface)
surface.always_day = not surface.always_day
game.print{ "expcom-cheat.day", player.name, surface.always_day }
return Commands.success
end)

View File

@@ -1,28 +0,0 @@
--[[-- Commands Module - Clear Inventory
- Adds a command that allows admins to clear people's inventorys
@commands Clear-Inventory
]]
local ExpUtil = require("modules/exp_util")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_role_parse")
--- Clears a players inventory
-- @command clear-inventory
-- @tparam LuaPlayer player the player to clear the inventory of
Commands.new_command("clear-inventory", { "expcom-clr-inv.description" }, "Clears a players inventory")
:add_param("player", false, "player-role")
:add_alias("clear-inv", "move-inventory", "move-inv")
:register(function(_, player)
local inventory = player.get_main_inventory()
if not inventory then
return Commands.error{ "expcore-commands.reject-player-alive" }
end
ExpUtil.transfer_inventory_to_surface{
inventory = inventory,
surface = game.planets.nauvis.surface,
name = "iron-chest",
allow_creation = true,
}
end)

View File

@@ -1,107 +0,0 @@
--[[-- Commands Module - Connect
- Adds a commands that allows you to request a player move to another server
@commands Connect
]]
local Async = require("modules/exp_util/async")
local External = require("modules.exp_legacy.expcore.external") --- @dep expcore.external
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_role_parse")
local concat = table.concat
local request_connection_async = Async.register(External.request_connection)
local function get_server_id(server)
local current_server = External.get_current_server()
local current_version = current_server.version
local servers = External.get_servers_filtered(server)
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, Commands.error{ "expcom-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, Commands.error{ "expcom-connect.same-server", server_details.name }
elseif status == "Offline" then
return false, Commands.error{ "expcom-connect.offline", server_details.name }
end
return true, server_id
elseif server_count_before > 0 then
return false, Commands.error{ "expcom-connect.wrong-version", concat(server_names_before, ", ") }
else
return false, Commands.error{ "expcom-connect.none-matching" }
end
end
--- Connect to a different server
-- @command connect
-- @tparam string server The address or name of the server to connect to
-- @tparam[opt=false] boolean is_address If an address was given for the server param
Commands.new_command("connect", { "expcom-connect.description" }, "Connect to another server")
:add_param("server")
:add_param("is_address", true, "boolean")
:add_alias("join", "server")
:register(function(player, server, is_address)
local server_id = server
if not is_address and External.valid() then
local success, new_server_id = get_server_id(server)
if not success then return new_server_id end
server_id = new_server_id
end
request_connection_async(player, server_id, true)
end)
--- Connect a player to a different server
-- @command connect-player
-- @tparam string address The address or name of the server to connect to
-- @tparam LuaPlayer player The player to connect to a different server
-- @tparam[opt=false] boolean is_address If an address was given for the server param
Commands.new_command("connect-player", { "expcom-connect.description-player" }, "Send a player to a different server")
:add_param("player", "player-role")
:add_param("server")
:add_param("is_address", true, "boolean")
:register(function(_, player, server, is_address)
local server_id = server
if not is_address and External.valid() then
local success, new_server_id = get_server_id(server)
if not success then return new_server_id end
server_id = new_server_id
end
External.request_connection(player, server_id)
end)
--- Connect all players to a different server
-- @command connect-all
-- @tparam string address The address or name of the server to connect to
-- @tparam[opt=false] boolean is_address If an address was given for the server param
Commands.new_command("connect-all", { "expcom-connect.description-all" }, "Connect all players to another server")
:add_param("server")
:add_param("is_address", true, "boolean")
:register(function(_, server, is_address)
local server_id = server
if not is_address and External.valid() then
local success, new_server_id = get_server_id(server)
if not success then return new_server_id end
server_id = new_server_id
end
for _, player in pairs(game.connected_players) do
External.request_connection(player, server_id)
end
end)

View File

@@ -1,14 +0,0 @@
--[[-- Commands Module - Debug
- Adds a command that opens the debug frame
@commands Debug
]]
local DebugView = require("modules.exp_legacy.modules.gui.debug.main_view") --- @dep modules.gui.debug.main_view
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
--- Opens the debug pannel for viewing tables.
-- @command debug
Commands.new_command("debug", { "expcom-debug.description" }, "Opens the debug pannel for viewing tables.")
:register(function(player)
DebugView.open_dubug(player)
end)

View File

@@ -1,30 +0,0 @@
--[[-- Commands Module - Enemy
- Adds a command of handling enemy
@commands Enemy
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
Commands.new_command("kill-biters", { "expcom-enemy.description-kill" }, "Kill all biters only")
:set_flag("admin_only")
:register(function(_, _)
game.forces["enemy"].kill_all_units()
return Commands.success
end)
Commands.new_command("remove-biters", { "expcom-enemy.description-remove" }, "Remove biters and prevent generation")
:set_flag("admin_only")
:add_param("surface", true, "surface")
:set_defaults{ surface = function(player)
-- Intentionally left as player.surface to allow use in remote view
return player.surface
end }
:register(function(_, 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"
return Commands.success
end)

View File

@@ -1,19 +0,0 @@
--[[-- Commands Module - Find
- Adds a command that zooms in on the given player
@commands Find
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
--- Find a player on your map.
-- @command find-on-map
-- @tparam LuaPlayer the player to find on the map
Commands.new_command("find-on-map", { "expcom-find.description" }, "Find a player on your map.")
:add_param("player", false, "player-online")
:add_alias("find", "zoom-to")
:register(function(player, action_player)
local position = action_player.physical_position
player.zoom_to_world(position, 1.75)
return Commands.success -- prevents command complete message from showing
end)

View File

@@ -1,19 +0,0 @@
--[[-- Commands Module - Toggle Friendly Fire
- Adds a command that toggle all friendly fire
@commands Toggle Friendly Fire
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
-- For Modded Server Use
Commands.new_command("toggle-friendly-fire", { "expcom-ff.description" }, "Toggle friendly fire")
:add_param("force", true, "force")
:set_defaults{ force = function(player)
return player.force
end }
:register(function(player, force)
force.friendly_fire = not force.friendly_fire
game.print{ "expcom-ff.ff", player.name, force.friendly_fire }
return Commands.success
end)

View File

@@ -1,95 +0,0 @@
--[[-- Commands Module - Help
- Adds a better help command that allows searching of descriotions and names
@commands Help
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Storage = require("modules/exp_util/storage")
require("modules.exp_legacy.config.expcore.command_general_parse")
local results_per_page = 5
local search_cache = {}
Storage.register(search_cache, function(tbl)
search_cache = tbl
end)
--- Searches for a keyword in all commands you are allowed to use.
-- @command chelp
-- @tparam string keyword the keyword that will be looked for
-- @tparam number page the page of help to view, must be in range of pages
Commands.new_command("search-help", { "expcom-chelp.description" }, "Searches for a keyword in all commands you are allowed to use.")
:add_alias("chelp", "shelp", "commands")
:add_param("keyword", true)
:add_param("page", true, "integer")
:set_defaults{ keyword = "", page = 1 }
:register(function(player, keyword, page)
local player_index = player and player.index or 0
-- if keyword is a number then treat it as page number
if tonumber(keyword) then
--- @diagnostic disable-next-line: param-type-mismatch
page = math.floor(tonumber(keyword))
keyword = ""
end
-- gets a value for pages, might have result in cache
local pages
local found = 0
if search_cache[player_index] and search_cache[player_index].keyword == keyword:lower() then
pages = search_cache[player_index].pages
found = search_cache[player_index].found
else
pages = { {} }
local current_page = 1
local page_count = 0
local commands = Commands.search(keyword, player)
-- loops other all commands returned by search, includes game commands
for _, command_data in pairs(commands) do
-- if the number of results if greater than the number already added then it moves onto a new page
if page_count >= results_per_page then
page_count = 0
current_page = current_page + 1
table.insert(pages, {})
end
-- adds the new command to the page
page_count = page_count + 1
found = found + 1
local alias_format = #command_data.aliases > 0 and { "expcom-chelp.alias", table.concat(command_data.aliases, ", ") } or ""
table.insert(pages[current_page], {
"expcom-chelp.format",
command_data.name,
command_data.description,
command_data.help,
alias_format,
})
end
-- adds the result to the cache
search_cache[player_index] = {
keyword = keyword:lower(),
pages = pages,
found = found,
}
end
-- print the requested page
keyword = keyword == "" and "<all>" or keyword
Commands.print({ "expcom-chelp.title", keyword }, "cyan")
if pages[page] then
for _, command in pairs(pages[page]) do
Commands.print(command)
end
Commands.print({ "expcom-chelp.footer", found, page, #pages }, "cyan")
else
Commands.print({ "expcom-chelp.footer", found, page, #pages }, "cyan")
return Commands.error{ "expcom-chelp.out-of-range", page }
end
-- blocks command complete message
return Commands.success
end)
-- way to access global
return search_cache

View File

@@ -1,83 +0,0 @@
--[[-- Commands Module - Home
- Adds a command that allows setting and teleporting to your home position
@commands Home
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Storage = require("modules/exp_util/storage")
require("modules.exp_legacy.config.expcore.command_general_parse")
local homes = {}
Storage.register(homes, function(tbl)
homes = tbl
end)
local function teleport(player, position)
local surface = player.physical_surface
local pos = surface.find_non_colliding_position("character", position, 32, 1)
if not position then return false end
if player.driving then player.driving = false end -- kicks a player out a vehicle if in one
player.teleport(pos, surface)
return true
end
local function floor_pos(position)
return {
x = math.floor(position.x),
y = math.floor(position.y),
}
end
--- Teleports you to your home location
-- @command home
Commands.new_command("home", { "expcom-home.description-home" }, "Teleports you to your home location")
:register(function(player)
local home = homes[player.index]
if not home or not home[1] then
return Commands.error{ "expcom-home.no-home" }
end
local rtn = floor_pos(player.physical_position)
teleport(player, home[1])
home[2] = rtn
Commands.print{ "expcom-home.return-set", rtn.x, rtn.y }
end)
--- Sets your home location to your current position
-- @command home-set
Commands.new_command("home-set", { "expcom-home.description-home-set" }, "Sets your home location to your current position")
:register(function(player)
local home = homes[player.index]
if not home then
home = {}
homes[player.index] = home
end
local pos = floor_pos(player.physical_position)
home[1] = pos
Commands.print{ "expcom-home.home-set", pos.x, pos.y }
end)
--- Returns your current home location
-- @command home-get
Commands.new_command("home-get", { "expcom-home.description-home-get" }, "Returns your current home location")
:register(function(player)
local home = homes[player.index]
if not home or not home[1] then
return Commands.error{ "expcom-home.no-home" }
end
local pos = home[1]
Commands.print{ "expcom-home.home-get", pos.x, pos.y }
end)
--- Teleports you to previous location
-- @command return
Commands.new_command("return", { "expcom-home.description-return" }, "Teleports you to previous location")
:register(function(player)
local home = homes[player.index]
if not home or not home[2] then
return Commands.error{ "expcom-home.no-return" }
end
local rtn = floor_pos(player.physical_position)
teleport(player, home[2])
home[2] = rtn
Commands.print{ "expcom-home.return-set", rtn.x, rtn.y }
end)

View File

@@ -1,117 +0,0 @@
--[[-- Commands Module - Interface
- Adds a command that acts as a direct link to the the active softmod, for debug use
@commands Interface
]]
local ExpUtil = require("modules/exp_util")
local Storage = require("modules/exp_util/storage")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
-- modules that are loaded into the interface env to be accessed
local interface_modules = {
["Commands"] = Commands,
["output"] = Commands.print,
["Group"] = "modules.exp_legacy.expcore.permission_groups",
["Roles"] = "modules.exp_legacy.expcore.roles",
["Gui"] = "modules.exp_legacy.expcore.gui",
["Datastore"] = "modules.exp_legacy.expcore.datastore",
["External"] = "modules.exp_legacy.expcore.external",
}
-- loads all the modules given in the above table
for key, value in pairs(interface_modules) do
if type(value) == "string" then
interface_modules[key] = ExpUtil.optional_require(value)
end
end
local interface_env = {} -- used as a persistent sandbox for interface commands
local interface_callbacks = {} -- saves callbacks which can load new values per use
Storage.register(interface_env, function(tbl)
interface_env = tbl
end)
--- Adds a static module that can be accessed with the interface
-- @tparam string name The name that the value is assigned to
-- @tparam any value The value that will be accessible in the interface env
-- callback param - player: LuaPlayer - the player who used the command
local function add_interface_module(name, value)
interface_modules[name] = value
end
--- Adds a dynamic value that is calculated when the interface is used
-- @tparam string name The name that the value is assigned to
-- @tparam function callback The function that will be called to get the value
local function add_interface_callback(name, callback)
if type(callback) == "function" then
interface_callbacks[name] = callback
end
end
--- Internal, this is a meta function for __index when self[key] is nil
local function get_index(_, key)
if interface_env[key] then
return interface_env[key]
elseif interface_modules[key] then
return interface_modules[key]
elseif _G[key] then
return _G[key]
end
end
--- Sends an invocation to be ran and returns the result.
-- @command interface
-- @tparam string invocation the command that will be run
Commands.new_command("interface", { "expcom-interface.description" }, "Sends an invocation to be ran and returns the result.")
:add_param("invocation", false)
:enable_auto_concat()
:set_flag("admin_only")
:register(function(player, invocation)
-- If the invocation has no white space then prepend return to it
if not invocation:find("%s") and not invocation:find("return") then
invocation = "return " .. invocation
end
-- _env will be the new _ENV that the invocation will run inside of
local _env = setmetatable({}, {
__index = get_index,
__newindex = interface_env,
})
-- If the command is ran by a player then load the dynamic values
if player then
for name, callback in pairs(interface_callbacks) do
local _, rtn = pcall(callback, player)
rawset(_env, name, rtn)
end
end
-- Compile the invocation with the custom _env value
local invocation_func, compile_error = load(invocation, "interface", nil, _env)
if compile_error then return Commands.error(compile_error) end
--- @cast invocation_func -nil
-- Run the invocation
local success, rtn = pcall(invocation_func)
if not success then
local err = rtn:gsub("%.%.%..-/temp/currently%-playing", "")
return Commands.error(err)
end
return Commands.success(rtn)
end)
-- Adds some basic callbacks for the interface
add_interface_callback("player", function(player) return player end)
add_interface_callback("surface", function(player) return player.surface end)
add_interface_callback("force", function(player) return player.force end)
add_interface_callback("position", function(player) return player.position end)
add_interface_callback("entity", function(player) return player.selected end)
add_interface_callback("tile", function(player) return player.surface.get_tile(player.position) end)
-- Module Return
return {
add_interface_module = add_interface_module,
add_interface_callback = add_interface_callback,
interface_env = interface_env,
clean_stack_trace = function(str) return str:gsub("%.%.%..-/temp/currently%-playing", "") end,
}

View File

@@ -1,48 +0,0 @@
--[[-- Commands Module - Jail
- Adds a commands that allow admins to jail and unjail
@commands Jail
]]
local ExpUtil = require("modules/exp_util")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail
local format_player_name = ExpUtil.format_player_name_locale --- @dep expcore.common
require("modules.exp_legacy.config.expcore.command_role_parse")
--- Puts a player into jail and removes all other roles.
-- @command jail
-- @tparam LuaPlayer player the player that will be jailed
-- @tparam[opt] string reason the reason why the player is being jailed
Commands.new_command("jail", { "expcom-jail.description-jail" }, "Puts a player into jail and removes all other roles.")
:add_param("player", false, "player-role")
:add_param("reason", true)
:enable_auto_concat()
:register(function(player, action_player, reason)
reason = reason or "Non Given."
local action_player_name_color = format_player_name(action_player)
local by_player_name_color = format_player_name(player)
local player_name = player and player.name or "<server>"
if Jail.jail_player(action_player, player_name, reason) then
game.print{ "expcom-jail.give", action_player_name_color, by_player_name_color, reason }
else
return Commands.error{ "expcom-jail.already-jailed", action_player_name_color }
end
end)
--- Removes a player from jail.
-- @command unjail
-- @tparam LuaPlayer the player that will be unjailed
Commands.new_command("unjail", { "expcom-jail.description-unjail" }, "Removes a player from jail.")
:add_param("player", false, "player-role")
:add_alias("clear-jail", "remove-jail")
:enable_auto_concat()
:register(function(player, action_player)
local action_player_name_color = format_player_name(action_player)
local by_player_name_color = format_player_name(player)
local player_name = player and player.name or "<server>"
if Jail.unjail_player(action_player, player_name) then
game.print{ "expcom-jail.remove", action_player_name_color, by_player_name_color }
else
return Commands.error{ "expcom-jail.not-jailed", action_player_name_color }
end
end)

View File

@@ -1,34 +0,0 @@
--[[-- Commands Module - Kill
- Adds a command that allows players to kill them selfs and others
@commands Kill
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
require("modules.exp_legacy.config.expcore.command_general_parse")
require("modules.exp_legacy.config.expcore.command_role_parse")
--- Kills yourself or another player.
-- @command kill
-- @tparam[opt=self] LuaPlayer player the player to kill, must be alive to be valid
Commands.new_command("kill", { "expcom-kill.description" }, "Kills yourself or another player.")
:add_param("player", true, "player-role-alive")
:set_defaults{ player = function(player)
-- default is the player unless they are dead
if player.character and player.character.health > 0 then
return player
end
end }
:register(function(player, action_player)
if not action_player then
-- can only be nil if no player given and the user is dead
return Commands.error{ "expcom-kill.already-dead" }
end
if player == action_player then
action_player.character.die()
elseif Roles.player_allowed(player, "command/kill/always") then
action_player.character.die()
else
return Commands.error{ "expcore-commands.unauthorized" }
end
end)

View File

@@ -1,20 +0,0 @@
--[[-- Commands Module - Last location
- Adds a command that will return the last location of a player
@commands LastLocation
]]
local ExpUtil = require("modules/exp_util")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local format_player_name = ExpUtil.format_player_name_locale --- @dep expcore.common
require("modules.exp_legacy.config.expcore.command_general_parse")
--- Get the last location of a player.
-- @command last-location
-- @tparam LuaPlayer player the player that you want a location of
Commands.new_command("last-location", { "expcom-lastlocation.description" }, "Sends you the last location of a player")
:add_alias("location")
:add_param("player", false, "player")
:register(function(_, action_player)
local action_player_name_color = format_player_name(action_player)
return Commands.success{ "expcom-lastlocation.response", action_player_name_color, string.format("%.1f", action_player.physical_position.x), string.format("%.1f", action_player.physical_position.y) }
end)

View File

@@ -1,17 +0,0 @@
--[[-- Commands Module - Me
- Adds a command that adds * around your message in the chat
@commands Me
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
--- Sends an action message in the chat
-- @command me
-- @tparam string action the action that follows your name in chat
Commands.new_command("me", { "expcom-me.description" }, "Sends an action message in the chat")
:add_param("action", false)
:enable_auto_concat()
:register(function(player, action)
local player_name = player and player.name or "<Server>"
game.print(string.format("* %s %s *", player_name, action), player.chat_color)
end)

View File

@@ -1,35 +0,0 @@
--[[-- Commands Module - Pollution Handle
- Adds a command that allows modifying pollution
@commands Pollution Handle
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
Commands.new_command("pollution-clear", { "expcom-pol.description-clr" }, "Clear pollution")
:set_flag("admin_only")
:add_alias("pol-clr")
:add_param("surface", true, "surface")
:set_defaults{ surface = function(player)
-- Intentionally left as player.surface to allow use in remote view
return player.surface
end }
:register(function(player, surface)
surface.clear_pollution()
game.print{ "expcom-pol.clr", player.name }
return Commands.success
end)
Commands.new_command("pollution-off", { "expcom-pol.description-off" }, "Disable pollution")
:set_flag("admin_only")
:add_alias("pol-off")
:register(function(player)
game.map_settings.pollution.enabled = false
for _, v in pairs(game.surfaces) do
v.clear_pollution()
end
game.print{ "expcom-pol.off", player.name }
return Commands.success
end)

View File

@@ -1,83 +0,0 @@
local Commands = require("modules.exp_legacy.expcore.commands")
local function Modules(moduleInventory) -- returns the multiplier of the modules
local effect1 = moduleInventory.get_item_count("productivity-module") -- type 1
local effect2 = moduleInventory.get_item_count("productivity-module-2") -- type 2
local effect3 = moduleInventory.get_item_count("productivity-module-3") -- type 3
local multi = effect1 * 4 + effect2 * 6 + effect3 * 10
return multi / 100 + 1
end
local function AmountOfMachines(itemsPerSecond, output)
if (itemsPerSecond) then
return itemsPerSecond / output
end
end
Commands.new_command("ratio", { "expcom-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.")
:add_param("itemsPerSecond", true, "number")
:register(function(player, itemsPerSecond)
local machine = player.selected -- selected machine
if not machine then -- nil check
return Commands.error{ "expcom-ratio.notSelecting" }
end
if machine.type ~= "assembling-machine" and machine.type ~= "furnace" then
return Commands.error{ "expcom-ratio.notSelecting" }
end
local recipe = machine.get_recipe() -- recipe
if not recipe then -- nil check
return Commands.error{ "expcom-ratio.notSelecting" }
end
local items = recipe.ingredients -- items in that recipe
local products = recipe.products -- output items
local amountOfMachines
local moduleInventory = machine.get_module_inventory() -- the module Inventory of the machine
local multi = Modules(moduleInventory) -- function for the productively modals
if itemsPerSecond then
amountOfMachines = math.ceil(AmountOfMachines(itemsPerSecond, 1 / recipe.energy * machine.crafting_speed * products[1].amount * multi)) -- amount of machines
end
if not amountOfMachines then
amountOfMachines = 1 -- set to 1 to make it not nil
end
----------------------------items----------------------------
for i, item in ipairs(items) do
local sprite -- string to make the icon work either fluid ore item
if item.type == "item" then
sprite = "expcom-ratio.item-in"
else
sprite = "expcom-ratio.fluid-in"
end
local ips = item.amount / recipe.energy * machine.crafting_speed * amountOfMachines -- math on the items/fluids per second
Commands.print{ sprite, math.round(ips, 3), item.name } -- full string
end
----------------------------products----------------------------
for i, product in ipairs(products) do
local sprite -- string to make the icon work either fluid ore item
if product.type == "item" then
sprite = "expcom-ratio.item-out"
else
sprite = "expcom-ratio.fluid-out"
end
local output = 1 / recipe.energy * machine.crafting_speed * product.amount * multi -- math on the outputs per second
Commands.print{ sprite, math.round(output * amountOfMachines, 3), product.name } -- full string
end
if amountOfMachines ~= 1 then
Commands.print{ "expcom-ratio.machines", amountOfMachines }
end
end)

View File

@@ -1,54 +0,0 @@
--[[-- Commands Module - Repair
- Adds a command that allows an admin to repair and revive a large area
@commands Repair
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local config = require("modules.exp_legacy.config.repair") --- @dep config.repair
require("modules.exp_legacy.config.expcore.command_general_parse")
local max_time_to_live = 4294967295 -- unit32 max
--- Repairs entities on your force around you
-- @command repair
-- @tparam number range the range to repair stuff in, there is a max limit to this
Commands.new_command("repair", { "expcom-repair.description" }, "Repairs entities on your force around you")
:add_param("range", false, "integer-range", 1, config.max_range)
:register(function(player, range)
local revive_count = 0
local heal_count = 0
local range2 = range ^ 2
-- Intentionally left as player.surface to allow use in remote view
local surface = player.surface
-- Intentionally left as player.position to allow use in remote view
local center = player.position
local area = { { x = center.x - range, y = center.y - range }, { x = center.x + range, y = center.y + range } }
if config.allow_ghost_revive then
local ghosts = surface.find_entities_filtered{ area = area, type = "entity-ghost", force = player.force }
for _, ghost in pairs(ghosts) do
if ghost.valid then
local x = ghost.position.x - center.x
local y = ghost.position.y - center.y
if x ^ 2 + y ^ 2 <= range2 then
if config.allow_blueprint_repair or ghost.time_to_live ~= max_time_to_live then
revive_count = revive_count + 1
if not config.disallow[ghost.ghost_name] then ghost.revive() end
end
end
end
end
end
if config.allow_heal_entities then
local entities = surface.find_entities_filtered{ area = area, force = player.force }
for _, entity in pairs(entities) do
if entity.valid then
local x = entity.position.x - center.x
local y = entity.position.y - center.y
if entity.health and entity.get_health_ratio() ~= 1 and x ^ 2 + y ^ 2 <= range2 then
heal_count = heal_count + 1
entity.health = max_time_to_live
end
end
end
end
return Commands.success{ "expcom-repair.result", revive_count, heal_count }
end)

View File

@@ -1,99 +0,0 @@
--[[-- Commands Module - Reports
- Adds a commands that allow players to report other players
@commands Reports
]]
local ExpUtil = require("modules/exp_util")
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports
local format_player_name = ExpUtil.format_player_name_locale --- @dep expcore.common
require("modules.exp_legacy.config.expcore.command_general_parse")
--- Print a message to all players who match the value of admin
local function print_to_players(admin, message)
for _, player in ipairs(game.connected_players) do
if player.admin == admin then
player.print(message)
end
end
end
--- Reports a player and notifies moderators
-- @command report
-- @tparam LuaPlayer player the player to report, some players are immune
-- @tparam string reason the reason the player is being reported
Commands.new_command("report", { "expcom-report.description-report" }, "Reports a player and notifies moderators")
:add_param("player", false, function(input, player, reject)
input = Commands.parse("player", input, player, reject)
if not input then return end
if Roles.player_has_flag(input, "report-immune") then
return reject{ "expcom-report.player-immune" }
elseif player == input then
return reject{ "expcom-report.self-report" }
else
return input
end
end)
:add_param("reason", false)
:add_alias("report-player")
:enable_auto_concat()
:register(function(player, action_player, reason)
local action_player_name_color = format_player_name(action_player)
local by_player_name_color = format_player_name(player)
if Reports.report_player(action_player, player.name, reason) then
print_to_players(false, { "expcom-report.non-admin", action_player_name_color, reason })
print_to_players(true, { "expcom-report.admin", action_player_name_color, by_player_name_color, reason })
else
return Commands.error{ "expcom-report.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.
-- @command get-reports
-- @tparam LuaPlayer player the player to get the report for
Commands.new_command("get-reports", { "expcom-report.description-get-reports" },
"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.")
:add_param("player", true, "player")
:add_alias("reports", "list-reports")
:register(function(_, player)
if player then
local reports = Reports.get_reports(player)
local player_name_color = format_player_name(player)
Commands.print{ "expcom-report.player-report-title", player_name_color }
for player_name, reason in pairs(reports) do
local by_player_name_color = format_player_name(player_name)
Commands.print{ "expcom-report.list", by_player_name_color, reason }
end
else
local user_reports = Reports.user_reports
Commands.print{ "expcom-report.player-count-title" }
for player_name in pairs(user_reports) do
local player_name_color = format_player_name(player_name)
local report_count = Reports.count_reports(player_name)
Commands.print{ "expcom-report.list", player_name_color, report_count }
end
end
end)
--- Clears all reports from a player or just the report from one player.
-- @command clear-reports
-- @tparam LuaPlayer player the player to clear the report(s) from
-- @tparam[opt=all] LuaPlayer from-player remove only the report made by this player
Commands.new_command("clear-reports", { "expcom-report.description-clear-reports" }, "Clears all reports from a player or just the report from one player.")
:add_param("player", false, "player")
:add_param("from-player", true, "player")
:register(function(player, action_player, from_player)
if from_player then
if not Reports.remove_report(action_player, from_player.name, player.name) then
return Commands.error{ "expcom-report.not-reported" }
end
else
if not Reports.remove_all(action_player, player.name) then
return Commands.error{ "expcom-report.not-reported" }
end
end
local action_player_name_color = format_player_name(action_player)
local by_player_name_color = format_player_name(player)
game.print{ "expcom-report.removed", action_player_name_color, by_player_name_color }
end)

View File

@@ -1,45 +0,0 @@
local Storage = require("modules/exp_util/storage")
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local config = require("modules.exp_legacy.config.research") --- @dep config.research
local research = {}
Storage.register(research, function(tbl)
research = tbl
end)
local function res_queue(force, by_script)
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 (by_script) then
game.print{ "expcom-res.inf-q", res.name, res.level + i }
end
end
end
end
Commands.new_command("auto-research", { "expcom-res.description-ares" }, "Automatically queue up research")
:add_alias("ares")
:register(function(player)
research.res_queue_enable = not research.res_queue_enable
if research.res_queue_enable then
res_queue(player.force, true)
end
game.print{ "expcom-res.res", player.name, research.res_queue_enable }
return Commands.success
end)
Event.add(defines.events.on_research_finished, function(event)
if research.res_queue_enable then
if event.research.force.rockets_launched > 0 and event.research.force.technologies["mining-productivity-4"].level > 4 then
res_queue(event.research.force, event.by_script)
end
end
end)

View File

@@ -1,80 +0,0 @@
--[[-- Commands Module - Roles
- Adds a commands that allow interaction with the role system
@commands Roles
]]
local ExpUtil = require("modules/exp_util")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
local Colours = require("modules/exp_util/include/color")
local format_player_name, format_color = ExpUtil.format_player_name_locale, ExpUtil.format_rich_text_color
--- Assigns a role to a player
-- @command assign-role
-- @tparam LuaPlayer player the player to assign the role to
-- @tparam string role the name of the role to assign to the player, supports auto complete after enter
Commands.new_command("assign-role", { "expcom-roles.description-assign-role" }, "Assigns a role to a player")
:add_param("player", false, "player-role")
:add_param("role", false, "role")
:set_flag("admin-only")
:add_alias("rpromote", "assign", "role", "add-role")
:register(function(player, action_player, role)
local player_highest = Roles.get_player_highest_role(player)
if player_highest.index < role.index then
Roles.assign_player(action_player, role, player.name)
else
return Commands.error{ "expcom-roles.higher-role" }
end
end)
--- Unassigns a role from a player
-- @command unassign-role
-- @tparam LuaPlayer player the player to unassign the role from
-- @tparam string role the name of the role to unassign from the player, supports auto complete after enter
Commands.new_command("unassign-role", { "expcom-roles.description-unassign-role" }, "Unassigns a role from a player")
:add_param("player", false, "player-role")
:add_param("role", false, "role")
:set_flag("admin-only")
:add_alias("rdemote", "unassign", "rerole", "remove-role")
:register(function(player, action_player, role)
local player_highest = Roles.get_player_highest_role(player)
if player_highest.index < role.index then
Roles.unassign_player(action_player, role, player.name)
else
return Commands.error{ "expcom-roles.higher-role" }
end
end)
--- Lists all roles in they correct order
-- @command list-roles
-- @tparam[opt=all] LuaPlayer player list only the roles which this player has
Commands.new_command("list-roles", { "expcom-roles.description-list-roles" }, "Lists all roles in they correct order")
:add_param("player", true, "player")
:add_alias("lsroles", "roles")
:register(function(_, player)
local roles = Roles.config.order
local message = { "expcom-roles.list" }
if player then
roles = Roles.get_player_roles(player)
end
for index, role in pairs(roles) do
role = Roles.get_role_from_any(role)
local colour = role.custom_color or Colours.white
local role_name = format_color(role.name, colour)
if index == 1 then
message = { "expcom-roles.list", role_name }
if player then
local player_name_colour = format_player_name(player)
message = { "expcom-roles.list-player", player_name_colour, role_name }
end
else
message = { "expcom-roles.list-element", message, role_name }
end
end
return Commands.success(message)
end)

View File

@@ -1,170 +0,0 @@
--[[-- Commands Module - Inventory Search
- Adds commands that will search all players inventories for an item
@commands InventorySearch
]]
local ExpUtil = require("modules/exp_util")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local format_number = require("util").format_number --- @dep util
local format_player_name = ExpUtil.format_player_name_locale
require("modules.exp_legacy.config.expcore.command_general_parse")
--- Input parse for items by name
local function item_parse(input, _, reject)
if input == nil then return end
local lower_input = input:lower():gsub(" ", "-")
-- Simple Case - internal name is given
local item = prototypes.item[lower_input]
if item then return item end
-- Second Case - rich text is given
local item_name = input:match("%[item=([0-9a-z-]+)%]")
item = prototypes.item[item_name]
if item then return item end
-- No item found, we do not attempt to search all prototypes as this will be expensive
return reject{ "expcom-inv-search.reject-item", lower_input }
end
--- Search all players for this item
local function search_players(players, item)
local head = 1
local found = {}
-- 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
--- Custom sort function which only retains 5 greatest values
local function sort_players(players, func)
local sorted = {}
local values = {}
local threshold = nil
-- Loop over all provided players
for index, player in ipairs(players) do
local value = func(player)
-- Check if the item will make the top 5 elements
if index <= 5 or value > threshold then
local inserted = false
values[player] = value
-- Find where in the top 5 to insert the element
for next_index, next_player in ipairs(sorted) do
if value > values[next_player] then
table.insert(sorted, next_index, player)
inserted = true
break
end
end
-- Insert the element, this can only be called when index <= 5
if not inserted then
sorted[#sorted + 1] = player
end
-- Update the threshold
if sorted[6] then
threshold = values[sorted[5]]
values[sorted[6]] = nil
sorted[6] = nil
else
threshold = values[sorted[#sorted]]
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
local function display_players(player, players, item)
player.print{ "expcom-inv-search.results-heading", item.name }
for index, data in ipairs(players) do
local player_name_color = format_player_name(data.player)
local amount = format_number(data.count)
local time = display_players_time_format(data.online_time)
player.print{ "expcom-inv-search.results-item", index, player_name_color, amount, time }
end
end
--- Return the amount of an item a player has
local function amount_sort(data)
return data.count
end
--- Get a list of players sorted by the quantity of an item in their inventory
-- @command search-amount
-- @tparam LuaItemPrototype item The item to search for in players inventories
Commands.new_command("search-amount", { "expcom-inv-search.description-ia" }, "Display players sorted by the quantity of an item held")
:add_alias("ia")
:add_param("item", false, item_parse)
:enable_auto_concat()
:register(function(player, item)
local players = search_players(game.players, item)
if #players == 0 then return { "expcom-inv-search.results-none", item.name } end
local top_players = sort_players(players, amount_sort)
display_players(player, top_players, item)
end)
--- Return the index of the player, higher means they joined more recently
local function recent_sort(data)
return data.player.index
end
--- Get a list of players who have the given item, sorted by how recently they joined
-- @command search-recent
-- @tparam LuaItemPrototype item The item to search for in players inventories
Commands.new_command("search-recent", { "expcom-inv-search.description-ir" }, "Display players who hold an item sorted by join time")
:add_alias("ir")
:add_param("item", false, item_parse)
:enable_auto_concat()
:register(function(player, item)
local players = search_players(game.players, item)
if #players == 0 then return { "expcom-inv-search.results-none", item.name } end
local top_players = sort_players(players, recent_sort)
display_players(player, top_players, item)
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
-- @command search
-- @tparam LuaItemPrototype item The item to search for in players inventories
Commands.new_command("search", { "expcom-inv-search.description-i" }, "Display players sorted by the quantity of an item held and playtime")
:add_alias("i")
:add_param("item", false, item_parse)
:enable_auto_concat()
:register(function(player, item)
local players = search_players(game.players, item)
if #players == 0 then return { "expcom-inv-search.results-none", item.name } end
local top_players = sort_players(players, combined_sort)
display_players(player, top_players, item)
end)
--- Get a list of online players sorted by quantity held and play time
-- @command search-online
-- @tparam LuaItemPrototype item The item to search for in players inventories
Commands.new_command("search-online", { "expcom-inv-search.description-io" }, "Display online players sorted by the quantity of an item held and playtime")
:add_alias("io")
:add_param("item", false, item_parse)
:enable_auto_concat()
:register(function(player, item)
local players = search_players(game.connected_players, item)
if #players == 0 then return { "expcom-inv-search.results-none", item.name } end
local top_players = sort_players(players, combined_sort)
display_players(player, top_players, item)
end)

View File

@@ -1,66 +0,0 @@
--[[-- Commands Module - Spawn
- Adds a command that allows players to teleport to their spawn point
@commands Spawn
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
local function teleport(player)
local surface = player.surface
local spawn = player.force.get_spawn_position(surface)
local position = surface.find_non_colliding_position("character", spawn, 32, 1)
-- return false if no new position
if not position then
return false
end
if player.vehicle then
-- Teleport the entity
local entity = player.vehicle
local goto_position = surface.find_non_colliding_position(entity.name, position, 32, 1)
-- Surface teleport can only be done for players and cars at the moment. (with surface as an peramitor it gives this error)
if entity.type == "car" then
entity.teleport(goto_position, surface)
elseif surface.index == entity.surface.index then
-- Try teleport the entity
if not entity.teleport(goto_position) then
player.driving = false
player.teleport(position, surface)
end
end
else
-- Teleport the player
player.teleport(position, surface)
end
return true
end
--- Teleport to spawn
-- @command go-to-spawn
-- @tparam[opt=self] LuaPlayer player the player to teleport to their spawn point
Commands.new_command("go-to-spawn", { "expcom-spawn.description" }, "Teleport to spawn")
:add_param("player", true, "player-role-alive")
:set_defaults{
player = function(player)
if player.connected and player.character and player.character.health > 0 then
return player
end
end,
}
:add_alias("spawn", "tp-spawn")
:register(function(player, action_player)
if not action_player then
return Commands.error{ "expcom-spawn.unavailable" }
elseif action_player == player then
if not teleport(player) then
return Commands.error{ "expcom-spawn.unavailable" }
end
elseif Roles.player_allowed(player, "command/go-to-spawn/always") then
if not teleport(action_player) then
return Commands.error{ "expcom-spawn.unavailable" }
end
else
return Commands.error{ "expcore-commands.unauthorized" }
end
end)

View File

@@ -1,33 +0,0 @@
--[[-- Commands Module - Spectate
- Adds commands relating to spectate and follow
@commands Spectate
]]
local Spectate = require("modules.exp_legacy.modules.control.spectate") --- @dep modules.control.spectate
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
--- Toggles spectator mode for the caller
-- @command spectate
Commands.new_command("spectate", { "expcom-spectate.description-spectate" }, "Toggles spectator mode")
: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.
-- @command follow
-- @tparam LuaPlayer player The player that will be followed
Commands.new_command("follow", { "expcom-spectate.description-follow" }, "Start following a player in spectator")
:add_alias("f")
:add_param("player", false, "player-online")
:register(function(player, action_player)
if player == action_player then
return Commands.error{ "expcom-spectate.follow-self" }
else
Spectate.start_follow(player, action_player)
end
end)

View File

@@ -1,16 +0,0 @@
--[[-- Commands Module - Set game speed
- Adds a command that allows changing game speed
@commands Set game speed
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
Commands.new_command("game-speed", { "expcom-speed.description" }, "Set game speed")
:add_param("amount", "number-range", 0.2, 8)
:set_flag("admin_only")
:register(function(player, amount)
game.speed = math.round(amount, 3)
game.print{ "expcom-speed.result", player.name, string.format("%.3f", amount) }
return Commands.success
end)

View File

@@ -1,41 +0,0 @@
--[[-- Commands Module - Clear Item On Ground
- Adds a command that clear item on ground so blueprint can deploy safely
@commands Clear Item On Ground
]]
local ExpUtil = require("modules/exp_util")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
Commands.new_command("clear-item-on-ground", { "expcom-surface-clearing.description-ci" }, "Clear Item On Ground")
:add_param("range", false, "integer-range", 1, 1000)
:register(function(player, range)
local items = {} --- @type LuaItemStack[]
-- Intentionally left as player.position to allow use in remote view
local entities = player.surface.find_entities_filtered{ position = player.position, radius = range, name = "item-on-ground" }
for _, e in pairs(entities) do
if e.stack then
items[#items + 1] = e.stack
end
end
ExpUtil.move_items_to_surface{
items = items,
surface = player.surface,
allow_creation = true,
name = "iron-chest",
}
return Commands.success
end)
Commands.new_command("clear-blueprint", { "expcom-surface-clearing.description-cb" }, "Clear Blueprint")
:add_param("range", false, "integer-range", 1, 1000)
:register(function(player, range)
-- Intentionally left as player.position to allow use in remote view
for _, e in pairs(player.surface.find_entities_filtered{ position = player.position, radius = range, type = "entity-ghost" }) do
e.destroy()
end
return Commands.success
end)

View File

@@ -1,93 +0,0 @@
--[[-- Commands Module - Teleport
- Adds a command that allows players to teleport to other players
@commands Teleport
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
local function teleport(from_player, to_player)
local surface = to_player.physical_surface
local position = surface.find_non_colliding_position("character", to_player.physical_position, 32, 1)
-- return false if no new position
if not position then
return false
end
if from_player.vehicle then
-- Teleport the entity
local entity = from_player.vehicle
local goto_position = surface.find_non_colliding_position(entity.name, position, 32, 1)
-- Surface teleport can only be done for players and cars at the moment. (with surface as an peramitor it gives this error)
if entity.type == "car" then
entity.teleport(goto_position, surface)
elseif surface.index == entity.surface.index then
-- Try teleport the entity
if not entity.teleport(goto_position) then
from_player.driving = false
from_player.teleport(position, surface)
end
end
else
-- Teleport the player
from_player.teleport(position, surface)
end
return true
end
--- Teleports a player to another player.
-- @command teleport
-- @tparam LuaPlayer from_player the player that will be teleported, must be alive
-- @tparam LuaPlayer to_player the player to teleport to, must be online (if dead goes to where they died)
Commands.new_command("teleport", { "expcom-tp.description-tp" }, "Teleports a player to another player.")
:add_param("from_player", false, "player-alive")
:add_param("to_player", false, "player-online")
:add_alias("tp")
:set_flag("admin_only")
:register(function(_, from_player, to_player)
if from_player.index == to_player.index then
-- return if attempting to teleport to self
return Commands.error{ "expcom-tp.to-self" }
end
if not teleport(from_player, to_player) then
-- return if the teleport failed
return Commands.error{ "expcom-tp.no-position-found" }
end
end)
--- Teleports a player to you.
-- @command bring
-- @tparam LuaPlayer player the player that will be teleported, must be alive
Commands.new_command("bring", { "expcom-tp.description-bring" }, "Teleports a player to you.")
:add_param("player", false, "player-alive")
:set_flag("admin_only")
:register(function(player, from_player)
if from_player.index == player.index then
-- return if attempting to teleport to self
return Commands.error{ "expcom-tp.to-self" }
end
if not teleport(from_player, player) then
-- return if the teleport failed
return Commands.error{ "expcom-tp.no-position-found" }
end
from_player.print("Come here my friend")
end)
--- Teleports you to a player.
-- @command goto
-- @tparam LuaPlayer player the player to teleport to, must be online (if dead goes to where they died)
Commands.new_command("goto", { "expcom-tp.description-goto" }, "Teleports you to a player.")
:add_param("player", false, "player-online")
:add_alias("tp-me", "tpme")
:register(function(player, to_player)
if to_player.index == player.index then
-- return if attempting to teleport to self
return Commands.error{ "expcom-tp.to-self" }
end
if not teleport(player, to_player) then
-- return if the teleport failed
return Commands.error{ "expcom-tp.no-position-found" }
end
end)

View File

@@ -1,23 +0,0 @@
--[[-- Commands Module - Set Automatic Train
- Adds a command that set all train back to automatic
@commands Set Automatic Train
]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
local format_number = require("util").format_number
Commands.new_command("set-trains-to-automatic", { "expcom-train.description" }, "Set All Trains to Automatic")
:register(function(player)
local count = 0
for _, v in pairs(player.force.get_trains()) do
if v.manual_mode then
count = count + 1
v.manual_mode = false
end
end
game.print{ "expcom-train.manual-result", player.name, format_number(count) }
return Commands.success
end)

View File

@@ -1,15 +0,0 @@
--- Adds a virtual layer to store power to save space.
-- @commands Vlayer
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
local vlayer = require("modules.exp_legacy.modules.control.vlayer")
Commands.new_command("vlayer-info", { "vlayer.description-vi" }, "Vlayer Info")
:register(function(_)
local c = vlayer.get_circuits()
for k, v in pairs(c) do
Commands.print(v .. " : " .. k)
end
end)

View File

@@ -1,77 +0,0 @@
--[[-- Commands Module - Warnings
- Adds a commands that allow admins to warn other players
@commands Warnings
]]
local ExpUtil = require("modules/exp_util")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local Warnings = require("modules.exp_legacy.modules.control.warnings") --- @dep modules.control.warnings
local format_player_name = ExpUtil.format_player_name_locale
local config = require("modules.exp_legacy.config.warnings") --- @dep config.warnings
require("modules.exp_legacy.config.expcore.command_role_parse")
--- Gives a warning to a player; may lead to automatic script action.
-- @command give-warning
-- @tparam LuaPlayer player the player the will recive a warning
-- @tparam string reason the reason the player is being given a warning
Commands.new_command("give-warning", { "expcom-warnings.description-give" }, "Gives a warning to a player; may lead to automatic script action.")
:add_param("player", false, "player-role")
:add_param("reason", false)
:add_alias("warn")
:enable_auto_concat()
:register(function(player, action_player, reason)
Warnings.add_warning(action_player, player.name, reason)
local action_player_name_color = format_player_name(action_player)
local by_player_name_color = format_player_name(player)
game.print{ "expcom-warnings.received", action_player_name_color, by_player_name_color, reason }
end)
--- Gets the number of warnings a player has. If no player then lists all players and the number of warnings they have.
-- @command get-warnings
-- @tparam[opt=list] LuaPlayer player the player to get the warning for, if nil all players are listed
Commands.new_command("get-warnings", { "expcom-warnings.description-get" }, "Gets the number of warnings a player has. If no player then lists all players and the number of warnings they have.")
:add_param("player", true, "player")
:add_alias("warnings", "list-warnings")
:register(function(_, player)
if player then
local warnings = Warnings.get_warnings(player)
local script_warnings = Warnings.get_script_warnings(player)
local player_name_color = format_player_name(player)
Commands.print{ "expcom-warnings.player", player_name_color, #warnings, #script_warnings, config.temp_warning_limit }
for _, warning in ipairs(warnings) do
Commands.print{ "expcom-warnings.player-detail", format_player_name(warning.by_player_name), warning.reason }
end
else
local rtn = {}
local user_script_warnings = Warnings.user_script_warnings
for player_name, warnings in pairs(Warnings.user_warnings:get_all()) do
rtn[player_name] = { #warnings, 0 }
end
for player_name, warnings in pairs(user_script_warnings) do
if not rtn[player_name] then
rtn[player_name] = { 0, 0 }
end
rtn[player_name][2] = #warnings
end
Commands.print{ "expcom-warnings.list-title" }
for player_name, warnings in pairs(rtn) do
local player_name_color = format_player_name(player_name)
Commands.print{ "expcom-warnings.list", player_name_color, warnings[1], warnings[2], config.temp_warning_limit }
end
end
end)
--- Clears all warnings (and script warnings) from a player
-- @command clear-warnings
-- @tparam LuaPlayer player the player to clear the warnings from
Commands.new_command("clear-warnings", { "expcom-warnings.description-clear" }, "Clears all warnings (and script warnings) from a player")
:add_param("player", false, "player")
:register(function(player, action_player)
Warnings.clear_warnings(action_player, player.name)
Warnings.clear_script_warnings(action_player)
local action_player_name_color = format_player_name(action_player)
local by_player_name_color = format_player_name(player)
game.print{ "expcom-warnings.cleared", action_player_name_color, by_player_name_color }
end)

View File

@@ -1,80 +0,0 @@
--- Adds a waterfill
-- @commands Waterfill
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
require("modules.exp_legacy.config.expcore.command_general_parse")
local Selection = require("modules.exp_legacy.modules.control.selection") --- @dep modules.control.selection
local SelectionConvertArea = "ConvertArea"
--- Align an aabb to the grid by expanding it
local function aabb_align_expand(aabb)
return {
left_top = { x = math.floor(aabb.left_top.x), y = math.floor(aabb.left_top.y) },
right_bottom = { x = math.ceil(aabb.right_bottom.x), y = math.ceil(aabb.right_bottom.y) },
}
end
Commands.new_command("waterfill", { "expcom-waterfill.description" }, "Change tile to water")
:register(function(player)
local inv = player.get_main_inventory()
if (inv.get_item_count("cliff-explosives")) == 0 then
return player.print{ "expcom-waterfill.waterfill-cliff" }
end
if Selection.is_selecting(player, SelectionConvertArea) then
Selection.stop(player)
else
Selection.start(player, SelectionConvertArea)
return Commands.success{ "expcom-waterfill.entered-area-selection" }
end
return Commands.success
end)
--- When an area is selected to add protection to the area
Selection.on_selection(SelectionConvertArea, function(event)
local area = aabb_align_expand(event.area)
local player = game.players[event.player_index]
if not player then
return
end
local entities = event.surface.find_entities_filtered{ area = area, name = "steel-chest" }
if #entities == 0 then
player.print("No steel chest found")
return
end
local tiles_to_make = {}
local inv = player.get_main_inventory()
if not inv then
return
end
local clf_exp = inv.get_item_count("cliff-explosives")
for _, entity in pairs(entities) do
if clf_exp >= 1 then
if entity.get_inventory(defines.inventory.chest).is_empty() then
-- Intentionally left as player.position to allow use in report view
if (math.floor(player.position.x) ~= math.floor(entity.position.x)) or (math.floor(player.position.y) ~= math.floor(entity.position.y)) then
table.insert(tiles_to_make, { name = "water-mud", position = entity.position })
entity.destroy()
else
player.print{ "expcom-waterfill.waterfill-distance" }
end
end
clf_exp = clf_exp - 1
inv.remove{ name = "cliff-explosives", count = 1 }
else
break
end
end
event.surface.set_tiles(tiles_to_make)
end)

View File

@@ -123,8 +123,8 @@ function Selection.is_selecting(player, selection_name)
end end
--- Filter on_player_selected_area to this custom selection, appends the selection arguments --- Filter on_player_selected_area to this custom selection, appends the selection arguments
-- @tparam string selection_name The name of the selection to listen for -- @param string selection_name The name of the selection to listen for
-- @tparam function handler The event handler -- @param function handler The event handler
function Selection.on_selection(selection_name, handler) function Selection.on_selection(selection_name, handler)
Event.add(defines.events.on_player_selected_area, function(event) Event.add(defines.events.on_player_selected_area, function(event)
local selection = selections[event.player_index] local selection = selections[event.player_index]

View File

@@ -31,9 +31,11 @@ WrapData:set_serializer(function(raw_key) return raw_key.warp_id end)
local Warps = {} local Warps = {}
--- @class ExpScenario_Warps.force_warps: { spawn: string, [number]: string }
-- Storage lookup table for force name to task ids -- Storage lookup table for force name to task ids
local force_warps = { _uid = 1 } local force_warps = { _uid = 1 }
--- @cast force_warps table<string, { spawn: string, [number]: string }> --- @cast force_warps table<string, ExpScenario_Warps.force_warps>
Storage.register(force_warps, function(tbl) Storage.register(force_warps, function(tbl)
force_warps = tbl force_warps = tbl
end) end)
@@ -61,7 +63,7 @@ WrapData:on_update(function(warp_id, warp, old_warp)
local warp_ids = force_warps[force_name] local warp_ids = force_warps[force_name]
local spawn_id = warp_ids.spawn local spawn_id = warp_ids.spawn
local warp_names = {} local warp_names = {} --- @type table<string, string>
for _, next_warp_id in pairs(warp_ids) do for _, next_warp_id in pairs(warp_ids) do
local next_warp = WrapData:get(next_warp_id) local next_warp = WrapData:get(next_warp_id)
if next_warp_id ~= spawn_id then if next_warp_id ~= spawn_id then
@@ -71,6 +73,7 @@ WrapData:on_update(function(warp_id, warp, old_warp)
-- Sort the warp names in alphabetical order -- Sort the warp names in alphabetical order
local new_warp_ids = table.get_values(table.key_sort(warp_names)) local new_warp_ids = table.get_values(table.key_sort(warp_names))
--- @cast new_warp_ids ExpScenario_Warps.force_warps
table.insert(new_warp_ids, 1, spawn_id) table.insert(new_warp_ids, 1, spawn_id)
new_warp_ids.spawn = spawn_id new_warp_ids.spawn = spawn_id
force_warps[force_name] = new_warp_ids force_warps[force_name] = new_warp_ids

View File

@@ -6,8 +6,7 @@
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
local config = require("modules.exp_legacy.config.bonus") --- @dep config.bonuses local config = require("modules.exp_legacy.config.bonus") --- @dep config.bonuses
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands local Commands = require("modules/exp_commands")
require("modules.exp_legacy.config.expcore.command_general_parse")
-- Stores the bonus for the player -- Stores the bonus for the player
local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data
@@ -47,19 +46,16 @@ PlayerBonus:on_update(function(player_name, player_bonus)
end) end)
--- Changes the amount of bonus you receive --- Changes the amount of bonus you receive
-- @command bonus Commands.new("bonus", { "bonus.description" })
-- @tparam number amount range 0-10 the increase for your bonus :optional("amount", { "bonus.arg-amount" }, Commands.types.integer_range(0, 10))
Commands.new_command("bonus", "Changes the amount of bonus you receive")
:add_param("amount", "integer-range", 0, 10)
:register(function(player, amount) :register(function(player, amount)
if not Roles.player_allowed(player, "command/bonus") then --- @cast amount number?
Commands.print{ "expcom-bonus.perm", 1 } if amount then
return PlayerBonus:set(player, amount)
return Commands.status.success{ "bonus.set", amount }
else
return Commands.status.success{ "bonus.get", PlayerBonus:get(player) }
end end
PlayerBonus:set(player, amount)
Commands.print{ "expcom-bonus.set", amount }
end) end)
--- When a player respawns re-apply bonus --- When a player respawns re-apply bonus

View File

@@ -2,8 +2,7 @@
-- @data Greetings -- @data Greetings
local config = require("modules.exp_legacy.config.join_messages") --- @dep config.join_messages local config = require("modules.exp_legacy.config.join_messages") --- @dep config.join_messages
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands local Commands = require("modules/exp_commands")
require("modules.exp_legacy.config.expcore.command_general_parse")
--- Stores the join message that the player have --- Stores the join message that the player have
local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data
@@ -24,20 +23,23 @@ CustomMessages:on_load(function(player_name, player_message)
end) end)
--- Set your custom join message --- Set your custom join message
-- @command join-message Commands.new("set-join-message", { "join-message.description-add" })
-- @tparam string message The custom join message that will be used :optional("message", false, Commands.types.string_max_length(255))
Commands.new_command("join-message", "Sets your custom join message") :enable_auto_concatenation()
:add_param("message", false, "string-max-length", 255) :add_aliases{ "join-message" }
:enable_auto_concat()
:register(function(player, message) :register(function(player, message)
if not player then return end --- @cast message string?
CustomMessages:set(player, message) if message then
return { "join-message.message-set" } CustomMessages:set(player, message)
return Commands.status.success{ "join-message.message-set" }
else
return Commands.status.success{ "join-message.message-get", CustomMessages:get(player) }
end
end) end)
Commands.new_command("join-message-clear", "Clear your join message") --- Removes your custom join message
Commands.new("remove-join-message", { "join-message.description-remove" })
:register(function(player) :register(function(player)
if not player then return end
CustomMessages:remove(player) CustomMessages:remove(player)
return { "join-message.message-cleared" } return Commands.status.success{ "join-message.message-cleared" }
end) end)

View File

@@ -1,4 +1,4 @@
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands local Commands = require("modules/exp_commands")
local config = require("modules.exp_legacy.config.personal_logistic") --- @dep config.personal-logistic local config = require("modules.exp_legacy.config.personal_logistic") --- @dep config.personal-logistic
local function pl(type, target, amount) local function pl(type, target, amount)
@@ -66,21 +66,20 @@ local function pl(type, target, amount)
end end
end end
Commands.new_command("personal-logistic", "Set Personal Logistic (-1 to cancel all) (Select spidertron to edit spidertron)") Commands.new("personal-logistic", "Set Personal Logistic (-1 to cancel all) (Select spidertron to edit spidertron)")
:add_param("amount", "integer-range", -1, 10) :argument("amount", "", Commands.types.integer_range(-1, 10))
:add_alias("pl") :add_aliases{ "pl" }
:register(function(player, amount) :register(function(player, amount)
--- @cast amount number
if player.force.technologies["logistic-robotics"].researched then if player.force.technologies["logistic-robotics"].researched then
if player.selected ~= nil then if player.selected ~= nil then
if player.selected.name == "spidertron" then if player.selected.name == "spidertron" then
pl("s", player.selected, amount / 10) pl("s", player.selected, amount / 10)
return Commands.success
end end
else else
pl("p", player, amount / 10) pl("p", player, amount / 10)
return Commands.success
end end
else else
player.print("Personal Logistic not researched") return Commands.status.error("Personal Logistic not researched")
end end
end) end)

View File

@@ -3,7 +3,7 @@
@data Quickbar @data Quickbar
]] ]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands local Commands = require("modules/exp_commands")
local config = require("modules.exp_legacy.config.preset_player_quickbar") --- @dep config.preset_player_quickbar local config = require("modules.exp_legacy.config.preset_player_quickbar") --- @dep config.preset_player_quickbar
--- Stores the quickbar filters for a player --- Stores the quickbar filters for a player
@@ -32,7 +32,7 @@ PlayerFilters:on_load(function(player_name, filters)
end end
end) end)
local ignoredItems = { local ignored_items = {
["blueprint"] = true, ["blueprint"] = true,
["blueprint-book"] = true, ["blueprint-book"] = true,
["deconstruction-planner"] = true, ["deconstruction-planner"] = true,
@@ -41,9 +41,8 @@ local ignoredItems = {
} }
--- Saves your quickbar preset to the script-output folder --- Saves your quickbar preset to the script-output folder
-- @command save-quickbar Commands.new("save-quickbar", "Saves your Quickbar preset items to file")
Commands.new_command("save-quickbar", "Saves your Quickbar preset items to file") :add_aliases{ "save-toolbar" }
:add_alias("save-toolbar")
:register(function(player) :register(function(player)
local filters = {} local filters = {}
@@ -51,7 +50,7 @@ Commands.new_command("save-quickbar", "Saves your Quickbar preset items to file"
local slot = player.get_quick_bar_slot(i) local slot = player.get_quick_bar_slot(i)
-- Need to filter out blueprint and blueprint books because the slot is a LuaItemPrototype and does not contain a way to export blueprint data -- Need to filter out blueprint and blueprint books because the slot is a LuaItemPrototype and does not contain a way to export blueprint data
if slot ~= nil then if slot ~= nil then
local ignored = ignoredItems[slot.name] local ignored = ignored_items[slot.name]
if ignored ~= true then if ignored ~= true then
filters[i] = slot.name filters[i] = slot.name
end end
@@ -64,5 +63,5 @@ Commands.new_command("save-quickbar", "Saves your Quickbar preset items to file"
PlayerFilters:remove(player) PlayerFilters:remove(player)
end end
return { "quickbar.saved" } return Commands.status.success{ "quickbar.saved" }
end) end)

View File

@@ -3,11 +3,8 @@
@data Tag @data Tag
]] ]]
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands local Commands = require("modules/exp_commands")
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
require("modules.exp_legacy.config.expcore.command_general_parse")
require("modules.exp_legacy.config.expcore.command_role_parse")
require("modules.exp_legacy.config.expcore.command_color_parse")
--- Stores the tag for a player --- Stores the tag for a player
local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data
@@ -47,42 +44,39 @@ PlayerTagColors:on_update(function(player_name, player_tag_color)
end) end)
--- Sets your player tag. --- Sets your player tag.
-- @command tag Commands.new("tag", "Sets your player tag.")
-- @tparam string tag the tag that will be after the name, there is a max length :argument("tag", "", Commands.types.string_max_length(20))
Commands.new_command("tag", "Sets your player tag.") :enable_auto_concatenation()
:add_param("tag", false, "string-max-length", 20)
:enable_auto_concat()
:register(function(player, tag) :register(function(player, tag)
--- @cast tag string
PlayerTags:set(player, tag) PlayerTags:set(player, tag)
end) end)
--- Sets your player tag color. --- Sets your player tag color.
-- @command tag Commands.new("tag-color", "Sets your player tag color.")
-- @tparam string color name. :argument("color", "", Commands.types.color)
Commands.new_command("tag-color", "Sets your player tag color.") :enable_auto_concatenation()
:add_param("color", false, "color")
:enable_auto_concat()
:register(function(player, color) :register(function(player, color)
--- @cast color Color
PlayerTagColors:set(player, color) PlayerTagColors:set(player, color)
end) end)
--- Clears your tag. Or another player if you are admin. --- Clears your tag. Or another player if you are admin.
-- @command tag-clear Commands.new("tag-clear", "Clears your tag. Or another player if you are admin.")
-- @tparam[opt=self] LuaPlayer player the player to remove the tag from, nil will apply to self :optional("player", "", Commands.types.lower_role_player)
Commands.new_command("tag-clear", "Clears your tag. Or another player if you are admin.") :defaults{
:add_param("player", true, "player-role") player = function(player) return player end
:set_defaults{ player = function(player) }
return player -- default is the user using the command :register(function(player, other_player)
end } --- @cast other_player LuaPlayer
:register(function(player, action_player) if other_player == player then
if action_player.index == player.index then -- No player given so removes your tag
-- no player given so removes your tag PlayerTags:remove(other_player)
PlayerTags:remove(action_player)
elseif Roles.player_allowed(player, "command/clear-tag/always") then elseif Roles.player_allowed(player, "command/clear-tag/always") then
-- player given and user is admin so clears that player's tag -- Player given and user is admin so clears that player's tag
PlayerTags:remove(action_player) PlayerTags:remove(other_player)
else else
-- user is not admin and tried to clear another users tag -- User is not admin and tried to clear another users tag
return Commands.error{ "expcore-commands.unauthorized" } return Commands.status.unauthorised()
end end
end) end)

View File

@@ -42,6 +42,7 @@ end
Event.add(defines.events.on_player_created, function(event) Event.add(defines.events.on_player_created, function(event)
local player = game.players[event.player_index] local player = game.players[event.player_index]
--- @diagnostic disable-next-line param-type-mismatch
util.insert_safe(player, global.created_items) util.insert_safe(player, global.created_items)
local r = global.chart_distance or 200 local r = global.chart_distance or 200
@@ -65,6 +66,7 @@ end)
Event.add(defines.events.on_player_respawned, function(event) Event.add(defines.events.on_player_respawned, function(event)
local player = game.players[event.player_index] local player = game.players[event.player_index]
--- @diagnostic disable-next-line param-type-mismatch
util.insert_safe(player, global.respawn_items) util.insert_safe(player, global.respawn_items)
if use_silo_script then if use_silo_script then
silo_script.on_event(event) silo_script.on_event(event)

View File

@@ -1,4 +1,4 @@
local Commands = require("modules.exp_legacy.expcore.commands") local Commands = require("modules/exp_commands")
local config = require("modules.exp_legacy.config.graftorio") local config = require("modules.exp_legacy.config.graftorio")
local statics = require("modules.exp_legacy.modules.graftorio.statics") local statics = require("modules.exp_legacy.modules.graftorio.statics")
local general = require("modules.exp_legacy.modules.graftorio.general") local general = require("modules.exp_legacy.modules.graftorio.general")
@@ -10,8 +10,8 @@ if config.modules.forcestats then
forcestats = require("modules.exp_legacy.modules.graftorio.forcestats") forcestats = require("modules.exp_legacy.modules.graftorio.forcestats")
end end
Commands.new_command("collectdata", "Collect data for RCON usage") Commands.new("collectdata", "Collect data for RCON usage")
:add_param("location", true) :optional("location", "", Commands.types.string) -- Not sure what this is for, i didn't write this
:register(function() :register(function()
-- this must be first as it overwrites the stats -- this must be first as it overwrites the stats
-- also makes the .other table for all forces -- also makes the .other table for all forces
@@ -24,6 +24,5 @@ Commands.new_command("collectdata", "Collect data for RCON usage")
forcestats.collect_production() forcestats.collect_production()
forcestats.collect_loginet() forcestats.collect_loginet()
end end
rcon.print(table_to_json(general.data.output)) return Commands.status.success(table_to_json(general.data.output))
return Commands.success()
end) end)

View File

@@ -17,7 +17,7 @@ local main_frame_name = Gui.uid_name()
local close_name = Gui.uid_name() local close_name = Gui.uid_name()
local tab_name = Gui.uid_name() local tab_name = Gui.uid_name()
function Public.open_dubug(player) function Public.open_debug(player)
for i = 1, #pages do for i = 1, #pages do
local page = pages[i] local page = pages[i]
local callback = page.on_open_debug local callback = page.on_open_debug

View File

@@ -24,7 +24,8 @@ function Public.show(container)
local left_panel_style = left_panel.style local left_panel_style = left_panel.style
left_panel_style.width = 300 left_panel_style.width = 300
for token_id in pairs(Storage.registered) do --- @diagnostic disable-next-line invisible
for token_id in pairs(Storage._registered) do
local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = token_id } local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = token_id }
Gui.set_data(header, token_id) Gui.set_data(header, token_id)
end end

View File

@@ -60,9 +60,10 @@ local elem_filter = {
} }
local function clear_module(player, area, machine) local function clear_module(player, area, machine)
-- Intentionally left as player.surface to allow use in remote view local force = player.force
for _, entity in pairs(player.surface.find_entities_filtered{ area = area, name = machine, force = player.force }) do local surface = player.surface -- Allow remote view
for _, r in pairs(player.surface.find_entities_filtered{ position = entity.position, name = "item-request-proxy", force = player.force }) do for _, entity in pairs(surface.find_entities_filtered{ area = area, name = machine, force = force }) do
for _, r in pairs(surface.find_entities_filtered{ position = entity.position, name = "item-request-proxy", force = force }) do
if r then if r then
r.destroy{ raise_destroy = true } r.destroy{ raise_destroy = true }
end end
@@ -75,7 +76,7 @@ local function clear_module(player, area, machine)
if m_current_module_content then if m_current_module_content then
for k, m in pairs(m_current_module_content) do for k, m in pairs(m_current_module_content) do
player.surface.spill_item_stack(entity.bounding_box.left_top, { name = k, count = m }, true, player.force, false) surface.spill_item_stack(entity.bounding_box.left_top, { name = k, count = m }, true, force, false)
end end
end end

View File

@@ -129,8 +129,7 @@ end)
Event.on_nth_tick(60, function() Event.on_nth_tick(60, function()
for _, player in pairs(game.connected_players) do for _, player in pairs(game.connected_players) do
local frame = Gui.get_left_element(player, production_container) local frame = Gui.get_left_element(player, production_container)
-- Intentionally left as player.surface to allow use in remote view local stat = player.force.get_item_production_statistics(player.surface) -- Allow remote view
local stat = player.force.get_item_production_statistics(player.surface)
local precision_value = precision[frame.container["production_st"].disp.table["production_0_e"].selected_index] local precision_value = precision[frame.container["production_st"].disp.table["production_0_e"].selected_index]
local table = frame.container["production_st"].disp.table local table = frame.container["production_st"].disp.table

View File

@@ -107,12 +107,12 @@ local function research_notification(event)
end end
else else
if not (event.by_script) then if not (event.by_script) then
game.print{ "expcom-res.inf", research_time_format(game.tick), event.research.name, event.research.level - 1 } game.print{ "research.inf", research_time_format(game.tick), event.research.name, event.research.level - 1 }
end end
end end
else else
if not (event.by_script) then if not (event.by_script) then
game.print{ "expcom-res.msg", research_time_format(game.tick), event.research.name } game.print{ "research.msg", research_time_format(game.tick), event.research.name }
end end
if config.bonus_inventory.enabled then if config.bonus_inventory.enabled then
@@ -139,7 +139,7 @@ local function research_gui_update()
local res_i = res_n + i - 3 local res_i = res_n + i - 3
if res["disp"][res_i] then if res["disp"][res_i] then
res_disp[i]["name"] = { "expcom-res.res-name", res["disp"][res_i]["raw_name"], prototypes.technology[res["disp"][res_i]["raw_name"]].localised_name } res_disp[i]["name"] = { "research.res-name", res["disp"][res_i]["raw_name"], prototypes.technology[res["disp"][res_i]["raw_name"]].localised_name }
if research.time[res_i] == 0 then if research.time[res_i] == 0 then
res_disp[i]["target"] = res["disp"][res_i].target_disp res_disp[i]["target"] = res["disp"][res_i].target_disp
@@ -237,10 +237,10 @@ local research_data_set =
local res_disp = research_gui_update() local res_disp = research_gui_update()
research_data_group(disp, 0) research_data_group(disp, 0)
disp["research_0_name"].caption = { "expcom-res.name" } disp["research_0_name"].caption = { "research.name" }
disp["research_0_target"].caption = { "expcom-res.target" } disp["research_0_target"].caption = { "research.target" }
disp["research_0_attempt"].caption = { "expcom-res.attempt" } disp["research_0_attempt"].caption = { "research.attempt" }
disp["research_0_difference"].caption = { "expcom-res.difference" } disp["research_0_difference"].caption = { "research.difference" }
for i = 1, 8, 1 do for i = 1, 8, 1 do
research_data_group(disp, i) research_data_group(disp, i)
@@ -269,7 +269,7 @@ local research_container =
:static_name(Gui.unique_static_name) :static_name(Gui.unique_static_name)
:add_to_left_flow() :add_to_left_flow()
Gui.left_toolbar_button("item/space-science-pack", { "expcom-res.main-tooltip" }, research_container, function(player) Gui.left_toolbar_button("item/space-science-pack", { "research.main-tooltip" }, research_container, function(player)
return Roles.player_allowed(player, "gui/research") return Roles.player_allowed(player, "gui/research")
end) end)

View File

@@ -6,8 +6,8 @@
local Gui = require("modules.exp_legacy.expcore.gui") --- @dep expcore.gui local Gui = require("modules.exp_legacy.expcore.gui") --- @dep expcore.gui
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local External = require("modules.exp_legacy.expcore.external") --- @dep expcore.external local External = require("modules.exp_legacy.expcore.external") --- @dep expcore.external
local Commands = require("modules/exp_commands")
--- Stores the visible state of server ups --- Stores the visible state of server ups
local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data
@@ -34,19 +34,19 @@ local server_ups =
UsesServerUps:on_load(function(player_name, visible) UsesServerUps:on_load(function(player_name, visible)
local player = game.players[player_name] local player = game.players[player_name]
local label = player.gui.screen[server_ups.name] local label = player.gui.screen[server_ups.name]
--- @diagnostic disable-next-line undefined-field
if not External.valid() or not global.ext.var.server_ups then visible = false end if not External.valid() or not global.ext.var.server_ups then visible = false end
label.visible = visible label.visible = visible
end) end)
--- Toggles if the server ups is visbile --- Toggles if the server ups is visbile
-- @command server-ups Commands.new("server-ups", { "server-ups.description" })
Commands.new_command("server-ups", "Toggle the server UPS display") :add_aliases{ "sups", "ups" }
:add_alias("sups", "ups")
:register(function(player) :register(function(player)
local label = player.gui.screen[server_ups.name] local label = player.gui.screen[server_ups.name]
if not External.valid() then if not External.valid() then
label.visible = false label.visible = false
return Commands.error{ "expcom-server-ups.no-ext" } return Commands.status.error{ "server-ups.no-ext" }
end end
label.visible = not label.visible label.visible = not label.visible
UsesServerUps:set(player, label.visible) UsesServerUps:set(player, label.visible)

View File

@@ -25,9 +25,6 @@ export const plugin: lib.PluginDeclaration = {
instanceEntrypoint: "./dist/node/instance", instanceEntrypoint: "./dist/node/instance",
messages: [ messages: [
Messages.PluginExampleEvent,
Messages.PluginExampleRequest,
Messages.ExampleSubscribableUpdate,
], ],
webEntrypoint: "./web", webEntrypoint: "./web",

View File

@@ -1,15 +1,19 @@
--[[-- Command Authorities - Roles
Adds a permission authority for exp roles
]]
local Commands = require("modules/exp_commands") local Commands = require("modules/exp_commands")
local add, allow, deny = Commands.add_permission_authority, Commands.status.success, Commands.status.unauthorised local add, allow, deny = Commands.add_permission_authority, Commands.status.success, Commands.status.unauthorised
local Roles = require("modules/exp_legacy/expcore/roles") local Roles = require("modules/exp_legacy/expcore/roles")
local player_allowed = Roles.player_allowed
local authorities = {} local authorities = {}
--- If a command has the flag "character_only" then the command can only be used outside of remote view --- If a command has the flag "character_only" then the command can only be used outside of remote view
authorities.exp_permission = authorities.exp_permission =
add(function(player, command) 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" } return deny{ "exp-commands-authorities_role.deny" }
else else
return allow() 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 Roles = require("modules.exp_legacy.expcore.roles")
local highest_role = Roles.get_player_highest_role 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 --- A role defined by exp roles
--- @type Commands.InputParser types.role = add("role", Commands.types.key_of(Roles.config.roles))
types.role =
add("role", function(input, player)
local _, status, rtn = parse(input, player, key_of_roles)
return status, rtn
end)
--- A role which is lower than the players highest role --- A role which is lower than the players highest role
--- @type Commands.InputParser
types.lower_role = types.lower_role =
add("lower_role", function(input, player) add("lower_role", function(input, player)
local success, status, result = parse(input, player, types.role) local success, status, result = parse(input, player, types.role)
@@ -45,7 +38,6 @@ types.lower_role =
end) end)
--- A player who is of a lower role than the executing player --- A player who is of a lower role than the executing player
--- @type Commands.InputParser
types.lower_role_player = types.lower_role_player =
add("lower_role_player", function(input, player) add("lower_role_player", function(input, player)
local success, status, result = parse(input, player, Commands.types.player) local success, status, result = parse(input, player, Commands.types.player)
@@ -62,9 +54,8 @@ types.lower_role_player =
end) end)
--- A player who is of a lower role than the executing player --- A player who is of a lower role than the executing player
--- @type Commands.InputParser
types.lower_role_player_online = 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) local success, status, result = parse(input, player, Commands.types.player_online)
if not success then return status, result end if not success then return status, result end
--- @cast result LuaPlayer --- @cast result LuaPlayer
@@ -80,7 +71,7 @@ types.lower_role_player_online =
--- A player who is of a lower role than the executing player --- A player who is of a lower role than the executing player
types.lower_role_player_alive = 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) local success, status, result = parse(input, player, Commands.types.player_alive)
if not success then return status, result end if not success then return status, result end
--- @cast result LuaPlayer --- @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

@@ -1,63 +1,56 @@
--[[-- Commands Module - Protection --[[-- Commands - Protection
- Adds commands that can add and remove protection Adds commands that can add and remove protection
@commands Protection
]] ]]
local ExpUtil = require("modules/exp_util")
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
local Storage = require("modules/exp_util/storage") 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 Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands
local format_player_name = ExpUtil.format_player_name_locale --- @dep expcore.common
local EntityProtection = require("modules.exp_legacy.modules.control.protection") --- @dep modules.control.protection
local Selection = require("modules.exp_legacy.modules.control.selection") --- @dep modules.control.selection 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 SelectionProtectEntity = "ProtectEntity" local format_string = string.format
local SelectionProtectArea = "ProtectArea" local floor = math.floor
local renders = {} -- Stores all renders for a player 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({ Storage.register({
renders = renders, renders = renders,
}, function(tbl) }, function(tbl)
renders = tbl.renders renders = tbl.renders
end) end)
--- Test if a point is inside an aabb
local function aabb_point_enclosed(point, aabb)
return point.x >= aabb.left_top.x and point.y >= aabb.left_top.y
and point.x <= aabb.right_bottom.x and point.y <= aabb.right_bottom.y
end
--- Test if an aabb is inside another aabb
local function aabb_area_enclosed(aabb_one, aabb_two)
return aabb_point_enclosed(aabb_one.left_top, aabb_two)
and aabb_point_enclosed(aabb_one.right_bottom, aabb_two)
end
--- Align an aabb to the grid by expanding it
local function aabb_align_expand(aabb)
return {
left_top = { x = math.floor(aabb.left_top.x), y = math.floor(aabb.left_top.y) },
right_bottom = { x = math.ceil(aabb.right_bottom.x), y = math.ceil(aabb.right_bottom.y) },
}
end
--- Get the key used in protected_entities --- Get the key used in protected_entities
--- @param entity LuaEntity
--- @return string
local function get_entity_key(entity) local function get_entity_key(entity)
return string.format("%i,%i", math.floor(entity.position.x), math.floor(entity.position.y)) return format_string("%i,%i", floor(entity.position.x), floor(entity.position.y))
end end
--- Get the key used in protected_areas --- Get the key used in protected_areas
--- TODO expose this from EntityProtection
--- @param area BoundingBox
--- @return string
local function get_area_key(area) local function get_area_key(area)
return string.format("%i,%i", math.floor(area.left_top.x), math.floor(area.left_top.y)) return format_string("%i,%i", floor(area.left_top.x), floor(area.left_top.y))
end end
--- Show a protected entity to a player --- Show a protected entity to a player
--- @param player LuaPlayer
--- @param entity LuaEntity
local function show_protected_entity(player, entity) local function show_protected_entity(player, entity)
local key = get_entity_key(entity) local key = get_entity_key(entity)
if renders[player.index][key] then return end if renders[player.index][key] then return end
local rb = entity.selection_box.right_bottom local rb = entity.selection_box.right_bottom
local render_id = rendering.draw_sprite{ renders[player.index][key] = rendering.draw_sprite{
sprite = "utility/notification", sprite = "utility/notification",
target = entity, target = entity,
target_offset = { target_offset = {
@@ -69,14 +62,16 @@ local function show_protected_entity(player, entity)
surface = entity.surface, surface = entity.surface,
players = { player }, players = { player },
} }
renders[player.index][key] = render_id
end end
--- Show a protected area to a player --- 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 function show_protected_area(player, surface, area)
local key = get_area_key(area) local key = get_area_key(area)
if renders[player.index][key] then return end if renders[player.index][key] then return end
local render_id = rendering.draw_rectangle{ renders[player.index][key] = rendering.draw_rectangle{
color = { 1, 1, 0, 0.5 }, color = { 1, 1, 0, 0.5 },
filled = false, filled = false,
width = 3, width = 3,
@@ -85,101 +80,108 @@ local function show_protected_area(player, surface, area)
surface = surface, surface = surface,
players = { player }, players = { player },
} }
renders[player.index][key] = render_id
end end
--- Remove a render object for a player --- Remove a render object for a player
--- @param player LuaPlayer
--- @param key string
local function remove_render(player, key) local function remove_render(player, key)
local render = renders[player.index][key] --[[@as LuaRenderObject]] local render = renders[player.index][key]
if render and render.valid then render.destroy() end if render and render.valid then render.destroy() end
renders[player.index][key] = nil renders[player.index][key] = nil
end end
--- Toggles entity protection selection --- Toggles entity protection selection
-- @command protect-entity Commands.new("protect-entity", { "exp-commands_protection.description-entity" })
Commands.new_command("protect-entity", { "expcom-protection.description-pe" }, "Toggles entity protection selection, hold shift to remove protection") :add_aliases{ "pe" }
:add_alias("pe")
:register(function(player) :register(function(player)
if Selection.is_selecting(player, SelectionProtectEntity) then if Selection.is_selecting(player, SelectionName_Entity) then
Selection.stop(player) Selection.stop(player)
return Commands.status.success{ "exp-commands_protection.exit-entity" }
else else
Selection.start(player, SelectionProtectEntity) Selection.start(player, SelectionName_Entity)
return Commands.success{ "expcom-protection.entered-entity-selection" } return Commands.status.success{ "exp-commands_protection.enter-entity" }
end end
end) end)
--- Toggles area protection selection --- Toggles area protection selection
-- @command protect-area Commands.new("protect-area", { "exp-commands_protection.description-area" })
Commands.new_command("protect-area", { "expcom-protection.description-pa" }, "Toggles area protection selection, hold shift to remove protection") :add_aliases{ "pa" }
:add_alias("pa")
:register(function(player) :register(function(player)
if Selection.is_selecting(player, SelectionProtectArea) then if Selection.is_selecting(player, SelectionName_Entity) then
Selection.stop(player) Selection.stop(player)
return Commands.status.success{ "exp-commands_protection.exit-area" }
else else
Selection.start(player, SelectionProtectArea) Selection.start(player, SelectionName_Entity)
return Commands.success{ "expcom-protection.entered-area-selection" } return Commands.status.success{ "exp-commands_protection.enter-area" }
end end
end) end)
--- When an area is selected to add protection to entities --- When an area is selected to add protection to entities
Selection.on_selection(SelectionProtectEntity, function(event) Selection.on_selection(SelectionName_Entity, function(event)
--- @cast event EventData.on_player_selected_area
local player = game.players[event.player_index] local player = game.players[event.player_index]
for _, entity in ipairs(event.entities) do for _, entity in ipairs(event.entities) do
EntityProtection.add_entity(entity) EntityProtection.add_entity(entity)
show_protected_entity(player, entity) show_protected_entity(player, entity)
end end
player.print{ "expcom-protection.protected-entities", #event.entities } player.print({ "exp-commands_protection.protected-entities", #event.entities }, Commands.print_settings.default)
end) end)
--- When an area is selected to remove protection from entities --- When an area is selected to remove protection from entities
Selection.on_alt_selection(SelectionProtectEntity, function(event) Selection.on_alt_selection(SelectionName_Entity, function(event)
--- @cast event EventData.on_player_alt_selected_area
local player = game.players[event.player_index] local player = game.players[event.player_index]
for _, entity in ipairs(event.entities) do for _, entity in ipairs(event.entities) do
EntityProtection.remove_entity(entity) EntityProtection.remove_entity(entity)
remove_render(player, get_entity_key(entity)) remove_render(player, get_entity_key(entity))
end end
player.print{ "expcom-protection.unprotected-entities", #event.entities } player.print({ "exp-commands_protection.unprotected-entities", #event.entities }, Commands.print_settings.default)
end) end)
--- When an area is selected to add protection to the area --- When an area is selected to add protection to the area
Selection.on_selection(SelectionProtectArea, function(event) Selection.on_selection(SelectionName_Area, function(event)
local area = aabb_align_expand(event.area) --- @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 areas = EntityProtection.get_areas(event.surface)
local player = game.players[event.player_index] local player = game.players[event.player_index]
for _, next_area in pairs(areas) do for _, next_area in pairs(areas) do
if aabb_area_enclosed(area, next_area) then if contains_area(next_area, area) then
return player.print{ "expcom-protection.already-protected" } return player.print({ "exp-commands_protection.already-protected" }, Commands.print_settings.error)
end end
end end
EntityProtection.add_area(event.surface, area) EntityProtection.add_area(surface, area)
show_protected_area(player, event.surface, area) show_protected_area(player, surface, area)
player.print{ "expcom-protection.protected-area" } player.print({ "exp-commands_protection.protected-area" }, Commands.print_settings.default)
end) end)
--- When an area is selected to remove protection from the area --- When an area is selected to remove protection from the area
Selection.on_alt_selection(SelectionProtectArea, function(event) Selection.on_alt_selection(SelectionName_Area, function(event)
local area = aabb_align_expand(event.area) --- @cast event EventData.on_player_alt_selected_area
local areas = EntityProtection.get_areas(event.surface) local surface = event.surface
local area = expand_area(event.area)
local areas = EntityProtection.get_areas(surface)
local player = game.players[event.player_index] local player = game.players[event.player_index]
for _, next_area in pairs(areas) do for _, next_area in pairs(areas) do
if aabb_area_enclosed(next_area, area) then if contains_area(area, next_area) then
EntityProtection.remove_area(event.surface, next_area) EntityProtection.remove_area(surface, next_area)
player.print{ "expcom-protection.unprotected-area" } player.print({ "exp-commands_protection.unprotected-area" }, Commands.print_settings.default)
remove_render(player, get_area_key(next_area)) remove_render(player, get_area_key(next_area))
end end
end end
end) end)
--- When selection starts show all protected entities and protected areas --- When selection starts show all protected entities and protected areas
Event.add(Selection.events.on_player_selection_start, function(event) local function on_player_selection_start(event)
if event.selection ~= SelectionProtectEntity and event.selection ~= SelectionProtectArea then return end if event.selection ~= SelectionName_Entity and event.selection ~= SelectionName_Area then return end
local player = game.players[event.player_index] local player = game.players[event.player_index]
-- Intentionally left as player.surface to allow use in remote view local surface = player.surface -- Allow remote view
local surface = player.surface
renders[player.index] = {} renders[player.index] = {}
-- Show protected entities -- Show protected entities
local entities = EntityProtection.get_entities(surface) local entities = EntityProtection.get_entities(surface)
for _, entity in pairs(entities) do for _, entity in pairs(entities) do
@@ -192,31 +194,46 @@ Event.add(Selection.events.on_player_selection_start, function(event)
show_protected_entity(player, entity) show_protected_entity(player, entity)
end end
end end
-- Show always protected entities by type -- Show always protected entities by type
if #EntityProtection.protected_entity_types > 0 then if #EntityProtection.protected_entity_types > 0 then
for _, entity in pairs(surface.find_entities_filtered{ type = EntityProtection.protected_entity_types, force = player.force }) do for _, entity in pairs(surface.find_entities_filtered{ type = EntityProtection.protected_entity_types, force = player.force }) do
show_protected_entity(player, entity) show_protected_entity(player, entity)
end end
end end
-- Show protected areas -- Show protected areas
local areas = EntityProtection.get_areas(surface) local areas = EntityProtection.get_areas(surface)
for _, area in pairs(areas) do for _, area in pairs(areas) do
show_protected_area(player, surface, area) show_protected_area(player, surface, area)
end end
end) end
--- When selection ends hide protected entities and protected areas --- When selection ends hide protected entities and protected areas
Event.add(Selection.events.on_player_selection_end, function(event) local function on_player_selection_end(event)
if event.selection ~= SelectionProtectEntity and event.selection ~= SelectionProtectArea then return end if event.selection ~= SelectionName_Entity and event.selection ~= SelectionName_Area then return end
for _, render in pairs(renders[event.player_index]) do for _, render in pairs(renders[event.player_index]) do
if render.valid then render.destroy() end if render.valid then render.destroy() end
end end
renders[event.player_index] = nil renders[event.player_index] = nil
end) end
--- When there is a repeat offence print it in chat --- When there is a repeat offence print it in chat
Event.add(EntityProtection.events.on_repeat_violation, function(event) local function on_repeat_violation(event)
local player_name = format_player_name(event.player_index) Roles.print_to_roles_higher("Regular", {
Roles.print_to_roles_higher("Regular", { "expcom-protection.repeat-offence", player_name, event.entity.localised_name, event.entity.position.x, event.entity.position.y }) "exp-commands_protection.repeat-offence",
end) 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

@@ -1,12 +1,15 @@
--[[-- Commands Module - Rainbow --[[-- Commands - Rainbow
- Adds a command that prints your message in rainbow font Adds a command that prints your message in rainbow font
@commands Rainbow
]] ]]
local ExpUtil = require("modules/exp_util") local Commands = require("modules/exp_commands")
local Commands = require("modules.exp_legacy.expcore.commands") --- @dep expcore.commands local format_player_name = Commands.format_player_name_locale
local format_chat_colour = ExpUtil.format_rich_text_color --- @dep expcore.common 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) local function step_component(c1, c2)
if c1 < 0 then if c1 < 0 then
return 0, c2 + c1 return 0, c2 + c1
@@ -17,6 +20,9 @@ local function step_component(c1, c2)
end end
end end
--- Wraps all components of a colour ensuring it remains valid
--- @param color Color
--- @return Color
local function step_color(color) local function step_color(color)
color.r, color.g = step_component(color.r, color.g) color.r, color.g = step_component(color.r, color.g)
color.g, color.b = step_component(color.g, color.b) color.g, color.b = step_component(color.g, color.b)
@@ -25,6 +31,10 @@ local function step_color(color)
return color return color
end 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) local function next_color(color, step)
step = step or 0.1 step = step or 0.1
local new_color = { r = 0, g = 0, b = 0 } local new_color = { r = 0, g = 0, b = 0 }
@@ -42,22 +52,21 @@ local function next_color(color, step)
end end
--- Sends an rainbow message in the chat --- Sends an rainbow message in the chat
-- @command rainbow Commands.new("rainbow", { "exp-commands_rainbow" })
-- @tparam string message the message that will be printed in chat :argument("message", { "exp-commands_rainbow.arg-message" }, Commands.types.string)
Commands.new_command("rainbow", { "expcom-rainbow.description" }, "Sends an rainbow message in the chat") :enable_auto_concatenation()
:add_param("message", false)
:enable_auto_concat()
:register(function(player, message) :register(function(player, message)
local player_name = player and player.name or "<Server>"
local player_color = player and player.color or nil
local color_step = 3 / message:len() local color_step = 3 / message:len()
if color_step > 1 then color_step = 1 end if color_step > 1 then color_step = 1 end
local current_color = { r = 1, g = 0, b = 0 } local current_color = { r = 1, g = 0, b = 0 }
local output = format_chat_colour(player_name .. ": ", player_color)
output = output .. message:gsub("%S", function(letter) game.print{
local rtn = format_chat_colour(letter, current_color) "exp-commands_rainbow.response",
current_color = next_color(current_color, color_step) format_player_name(player),
return rtn message:gsub("%S", function(letter)
end) local rtn = format_text(letter, current_color)
game.print(output) current_color = next_color(current_color, color_step)
return rtn
end)
}
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)

Some files were not shown because too many files have changed in this diff Show More