mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-08-12 16:35:11 +09:00
Merge branch 'explosivegaming:main' into aperx
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json",
|
||||
"runtime": {
|
||||
"version": "Lua5.2",
|
||||
"requirePattern": [ "?", "?.lua" ]
|
||||
},
|
||||
"workspace": {
|
||||
"$comment-moduleMap": "Replaces the fmtk --clusterio-modules plugin, rewrites each file's own module path rather than the require string",
|
||||
"$comment-library": "clusterio is outside this repo, set CLUSTERIO to your checkout. The factorio typedefs come from .luarc.json, which the factoriomod-debug extension manages",
|
||||
"library": [ "$CLUSTERIO/packages/host" ],
|
||||
"ignoreDir": [ ".github", "web", "dist", "factorio" ],
|
||||
"ignoreGlobs": [ "**/node_modules/**", "**/dist/**", "**/campaigns/**" ],
|
||||
"moduleMap": [
|
||||
{ "pattern": "^([^.]+)\\.module\\.module_exports$", "replace": "modules.$1" },
|
||||
{ "pattern": "^([^.]+)\\.module\\.(.+)$", "replace": "modules.$1.$2" }
|
||||
]
|
||||
},
|
||||
"doc": {
|
||||
"privateName": [ "__*" ]
|
||||
},
|
||||
"$comment-disable": "Carried over from the luals config, which had these as editor only rather than checked in ci",
|
||||
"$comment-unnecessary-if": "Disabled by the config fmtk generates for itself, the api union types make it unreliable",
|
||||
"diagnostics": {
|
||||
"globals": [ "__DebugAdapter", "__Profiler" ],
|
||||
"disable": [
|
||||
"assign-type-mismatch",
|
||||
"param-type-mismatch",
|
||||
"preferred-local-alias",
|
||||
"unnecessary-assert",
|
||||
"unnecessary-if",
|
||||
"unused"
|
||||
]
|
||||
}
|
||||
}
|
||||
+53
-35
@@ -1,76 +1,94 @@
|
||||
name: FMTK Lint
|
||||
name: Lua Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
EMMYLUA_CHECK_VERSION: "0.24.0"
|
||||
CLUSTERIO: ${{ github.workspace }}/.clusterio
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout clusterio modules
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: clusterio/clusterio
|
||||
path: .clusterio
|
||||
sparse-checkout: packages/host/modules
|
||||
sparse-checkout-cone-mode: false
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
- name: Install FMTK
|
||||
- name: Generate Factorio typedefs
|
||||
run: |
|
||||
# Pinned: 2.1.4+ generates typedefs targeting EmmyLua that LuaLS misreads
|
||||
pnpm install factoriomod-debug@2.1.3
|
||||
pnpm exec fmtk luals-addon
|
||||
jq '.["workspace.library"] += ["${{ github.workspace }}/factorio/library"] | .["runtime.plugin"] = "${{ github.workspace }}/factorio/plugin.lua"' .luarc.json > temp.luarc.json
|
||||
jq -s '.[0] * .[1].settings' temp.luarc.json ${{ github.workspace }}/factorio/config.json > check.luarc.json
|
||||
- name: Install LuaLS
|
||||
pnpm install factoriomod-debug
|
||||
pnpm exec fmtk luals-addon "$RUNNER_TEMP"
|
||||
- name: Install emmylua_check
|
||||
run: |
|
||||
wget https://github.com/LuaLS/lua-language-server/releases/download/3.18.2/lua-language-server-3.18.2-linux-x64.tar.gz -q -O lusls.tar.gz
|
||||
mkdir luals && tar -xf lusls.tar.gz -C luals && rm lusls.tar.gz
|
||||
curl -fsSL "https://github.com/EmmyLuaLs/emmylua-analyzer-rust/releases/download/${EMMYLUA_CHECK_VERSION}/emmylua_check-linux-x64.tar.gz" \
|
||||
| tar -xz -C "$RUNNER_TEMP"
|
||||
- name: Run Lint Report
|
||||
shell: bash
|
||||
run: |
|
||||
./luals/bin/lua-language-server --check=. --logpath=. --configpath=check.luarc.json --checklevel=Information --check_out_path=check.json
|
||||
# The typedefs are generated per run, clusterio comes from CLUSTERIO above
|
||||
jq -n --arg lib "$RUNNER_TEMP/factorio/library" \
|
||||
'{ workspace: { library: [ $lib ], ignoreGlobs: [ ".clusterio/**" ] } }' \
|
||||
> "$RUNNER_TEMP/ci.emmyrc.json"
|
||||
|
||||
# Exits non zero on error severity, so the gate below is used instead
|
||||
"$RUNNER_TEMP/emmylua_check" . --config ".emmyrc.json,$RUNNER_TEMP/ci.emmyrc.json" \
|
||||
--output-format json --output check.json || true
|
||||
|
||||
# Credit to https://github.com/Krealle/luals-check-action/blob/main/action.yml
|
||||
# Although some minor fixes were needed
|
||||
|
||||
# Format and print the messages (would be nice to format as a table, but that's too complex for jq)
|
||||
cat check.json | \
|
||||
jq -r \
|
||||
'to_entries | map(.key as $file | .value[] |
|
||||
jq -r --arg root "$PWD/" \
|
||||
'.[] | (.file | ltrimstr($root)) as $file | .diagnostics[] |
|
||||
{
|
||||
file: $file | sub("file://${{ github.workspace }}/./"; ""),
|
||||
file: $file,
|
||||
code: .code,
|
||||
line: .range.start.line,
|
||||
message: (.message | split("\n")
|
||||
| map(if startswith("- ") then .[2:] else . end)
|
||||
| join("\n")),
|
||||
severity: (if .severity <= 1 then "ERR" else "WARN" end)
|
||||
}) |
|
||||
map("**[\(.severity)] \(.code):** \(.file)#L\(.line)<br><code>\(.message)</code>") | .[]' \
|
||||
> $GITHUB_STEP_SUMMARY
|
||||
} |
|
||||
"**[\(.severity)] \(.code):** \(.file)#L\(.line + 1)<br><code>\(.message)</code>"' \
|
||||
check.json > "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
echo ""
|
||||
|
||||
# Github Annotations (limited to 10)
|
||||
cat check.json | \
|
||||
jq -r \
|
||||
'to_entries | map(.key as $file | .value[] |
|
||||
{
|
||||
file: $file | sub("file://${{ github.workspace }}/./"; ""),
|
||||
title: .code,
|
||||
line: .range.start.line,
|
||||
endLine: .range.end.line,
|
||||
col: .range.start.character,
|
||||
endColumn: .range.end.character,
|
||||
message: .message | gsub("\n"; "%0A"; "m"),
|
||||
level: (if .severity <= 1 then "error" else "warning" end)
|
||||
}) |
|
||||
map("::\(.level) file=\(.file),line=\(.line+1),endLine=\(.line+1),col=\(.col+1),endColumn=\(.endColumn+1),title=\(.title)::\(.message) (\(.title))") | .[]'
|
||||
jq -r --arg root "$PWD/" \
|
||||
'.[] | (.file | ltrimstr($root)) as $file | .diagnostics[] |
|
||||
{
|
||||
file: $file,
|
||||
title: .code,
|
||||
line: .range.start.line,
|
||||
endLine: .range.end.line,
|
||||
col: .range.start.character,
|
||||
endColumn: .range.end.character,
|
||||
message: (.message | gsub("\n"; "%0A"; "m")),
|
||||
level: (if .severity <= 1 then "error" else "warning" end)
|
||||
} |
|
||||
"::\(.level) file=\(.file),line=\(.line + 1),endLine=\(.endLine + 1),col=\(.col + 1),endColumn=\(.endColumn + 1),title=\(.title)::\(.message) (\(.title))"' \
|
||||
check.json
|
||||
|
||||
if [[ $(wc -l < check.json) > 1 ]] ; then
|
||||
# An entry is emitted for every file checked, including clean ones, so
|
||||
# the gate counts diagnostics and asserts the workspace was actually read
|
||||
if [[ $(jq 'length' check.json) -lt 100 ]] ; then
|
||||
echo "::error::Only $(jq 'length' check.json) files were checked, expected the whole workspace"
|
||||
exit 1
|
||||
elif [[ $(jq '[.[].diagnostics[]] | length' check.json) -gt 0 ]] ; then
|
||||
exit 1
|
||||
else
|
||||
echo "✅ All checks succeeded!" | tee $GITHUB_STEP_SUMMARY
|
||||
echo "✅ All checks succeeded!" | tee "$GITHUB_STEP_SUMMARY"
|
||||
fi
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
dist/
|
||||
node_modules/
|
||||
.vscode
|
||||
.luarc.json
|
||||
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
|
||||
"workspace.ignoreDir": [
|
||||
".vscode", ".github", "luals", "factorio", "web"
|
||||
],
|
||||
"completion.requireSeparator": "/",
|
||||
"runtime.pluginArgs": [
|
||||
"--clusterio-modules"
|
||||
],
|
||||
"doc": {
|
||||
"regengine": "glob",
|
||||
"privateName": [ "__*" ],
|
||||
"packageName": [ "_*" ]
|
||||
},
|
||||
"type": {
|
||||
"checkTableShape": true,
|
||||
"inferParamType": true
|
||||
},
|
||||
"$comment-name-style-check": "Disabled below until config issue fixed: https://github.com/LuaLS/lua-language-server/issues/2643",
|
||||
"$comment-type-mismatch": "Disabled unless opened due to performance concerns, time reduced to 10s from 400s",
|
||||
"diagnostics": {
|
||||
"unusedLocalExclude": [ "_*", "i", "j", "k", "v" ],
|
||||
"groupFileStatus": {
|
||||
"ambiguity": "Any",
|
||||
"await": "None",
|
||||
"codestyle": "Opened",
|
||||
"conventions": "Any",
|
||||
"duplicate": "Any",
|
||||
"global": "Any",
|
||||
"luadoc": "Opened",
|
||||
"redefined": "Opened",
|
||||
"strict": "Any",
|
||||
"strong": "Any",
|
||||
"type-check": "Any",
|
||||
"unbalanced": "Opened",
|
||||
"unused": "Opened"
|
||||
},
|
||||
"neededFileStatus": {
|
||||
"no-unknown": "None!",
|
||||
"spell-check": "None!",
|
||||
"name-style-check": "None!",
|
||||
"assign-type-mismatch": "Opened!",
|
||||
"return-type-mismatch": "Opened!",
|
||||
"param-type-mismatch": "Opened!"
|
||||
}
|
||||
},
|
||||
"nameStyle.config": {
|
||||
"local_name_style": [{
|
||||
"type" : "pattern",
|
||||
"param": "_?_?(\\S*)",
|
||||
"$1": "snake_case"
|
||||
}],
|
||||
"module_local_name_style": [{
|
||||
"type" : "pattern",
|
||||
"param": "_?_?(\\S*)",
|
||||
"$1": "snake_case"
|
||||
}, {
|
||||
"type" : "pattern",
|
||||
"param": "_?_?(\\S*)",
|
||||
"$1": "upper_snake_case"
|
||||
}, {
|
||||
"type" : "pattern",
|
||||
"param": "_?_?(\\S*)",
|
||||
"$1": "pascal_case"
|
||||
}],
|
||||
"function_param_name_style": [{
|
||||
"type" : "pattern",
|
||||
"param": "_?_?(\\S*)",
|
||||
"$1": "snake_case"
|
||||
}],
|
||||
"function_name_style": [{
|
||||
"type" : "pattern",
|
||||
"param": "_?_?(\\S*)",
|
||||
"$1": "snake_case"
|
||||
}],
|
||||
"local_function_name_style": [{
|
||||
"type" : "pattern",
|
||||
"param": "_?_?(\\S*)",
|
||||
"$1": "snake_case"
|
||||
}],
|
||||
"table_field_name_style": [{
|
||||
"type" : "pattern",
|
||||
"param": "_?_?(\\S*)",
|
||||
"$1": "snake_case"
|
||||
}],
|
||||
"global_variable_name_style": [{
|
||||
"type" : "pattern",
|
||||
"param": "_?_?(\\S*)",
|
||||
"$1": "snake_case"
|
||||
}, {
|
||||
"type" : "pattern",
|
||||
"param": "_?_?(\\S*)",
|
||||
"$1": "upper_snake_case"
|
||||
}],
|
||||
"module_name_style": [ "pascal_case", "snake_case" ],
|
||||
"require_module_name_style": [ "pascal_case", "snake_case" ],
|
||||
"class_name_style": "pascal_case",
|
||||
"const_variable_name_style": "upper_snake_case"
|
||||
},
|
||||
"format.defaultConfig": {
|
||||
"continuation_indent.in_expr": "0"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ All are welcome to make bug reports, feature requests, and pull requests for our
|
||||
For developers wanting to add features please follow these guidelines:
|
||||
|
||||
- All lua code is documented using ldoc.
|
||||
- Set the `CLUSTERIO` environment variable to your clusterio development install path, the lint needs it to resolve `modules/clusterio/*`.
|
||||
- Lua is checked with [emmylua](https://github.com/EmmyLuaLs/emmylua-analyzer-rust), configured by `.emmyrc.json`. Install the EmmyLua extension rather than sumnekolua / luals, and use factoriomod-debug to generate the factorio api types. Note that an inline cast must be written `--[[@as T]]`, the spaced form is not parsed.
|
||||
- Changes should be made on your own fork and merged into `main` through a pull request.
|
||||
- Each pull request should be limited to one feature or a few bug fixes and link to the related issue page.
|
||||
- Pull requests are automatically linted and documentation checked.
|
||||
|
||||
@@ -10,7 +10,7 @@ The default permission authorities controlled by the flags: admin_only, system_o
|
||||
|
||||
local Storage = require("modules/exp_util/storage")
|
||||
|
||||
local Commands = require("modules/exp_commands") --- @class Commands
|
||||
local Commands = require("modules/exp_commands") --- @class (partial) Commands
|
||||
local add, allow, deny = Commands.add_permission_authority, Commands.status.success, Commands.status.unauthorised
|
||||
|
||||
local authorities = {}
|
||||
@@ -28,13 +28,13 @@ end)
|
||||
--- Allow a player access to system commands, use for debug purposes only
|
||||
--- @param player_name string? The name of the player to give access to, default is the current player
|
||||
function Commands.unlock_system_commands(player_name)
|
||||
system_players[player_name or game.player.name] = true
|
||||
system_players[player_name or assert(game.player).name] = true
|
||||
end
|
||||
|
||||
--- Remove access from system commands for a player, use for debug purposes only
|
||||
--- @param player_name string? The name of the player to give access to, default is the current player
|
||||
function Commands.lock_system_commands(player_name)
|
||||
system_players[player_name or game.player.name] = nil
|
||||
system_players[player_name or assert(game.player).name] = nil
|
||||
end
|
||||
|
||||
--- Get a list of all players who have system commands unlocked
|
||||
|
||||
@@ -25,18 +25,18 @@ end)
|
||||
--- @param page_size number The number of requests to show per page
|
||||
--- @return LocalisedString[][], number
|
||||
local function format_as_pages(commands, page_size)
|
||||
local pages = { {} }
|
||||
local current_page = {}
|
||||
local pages = { current_page }
|
||||
local page_length = 0
|
||||
local current_page = 1
|
||||
local total = 0
|
||||
|
||||
for _, command in pairs(commands) do
|
||||
total = total + 1
|
||||
page_length = page_length + 1
|
||||
if page_length > page_size then
|
||||
current_page = current_page + 1
|
||||
pages[current_page] = {}
|
||||
page_length = 1
|
||||
current_page = {}
|
||||
pages[#pages + 1] = current_page
|
||||
end
|
||||
|
||||
local description
|
||||
@@ -48,7 +48,7 @@ local function format_as_pages(commands, page_size)
|
||||
end
|
||||
|
||||
local aliases = #command.aliases > 0 and { "exp-commands_help.aliases", table.concat(command.aliases, ", ") } or ""
|
||||
pages[current_page][page_length] = { "exp-commands_help.format", command.name, description, aliases }
|
||||
current_page[page_length] = { "exp-commands_help.format", command.name, description, aliases }
|
||||
end
|
||||
|
||||
return pages, total
|
||||
@@ -71,7 +71,7 @@ Commands.new("commands", { "exp-commands_help.description" })
|
||||
page = as_number
|
||||
end
|
||||
|
||||
keyword = keyword:lower()
|
||||
keyword = tostring(keyword):lower()
|
||||
local pages, found
|
||||
if cache and cache.keyword == keyword then
|
||||
-- Cached value found, no search is needed
|
||||
|
||||
@@ -12,7 +12,7 @@ local ExpUtil = require("modules/exp_util")
|
||||
local Async = require("modules/exp_util/async")
|
||||
local Storage = require("modules/exp_util/storage")
|
||||
|
||||
local Commands = require("modules/exp_commands") --- @class Commands
|
||||
local Commands = require("modules/exp_commands") --- @class (partial) Commands
|
||||
|
||||
local rcon_env = {} --- @type table<string, any>
|
||||
local rcon_static = {} --- @type table<string, any>
|
||||
@@ -21,12 +21,10 @@ setmetatable(rcon_static, { __index = _G })
|
||||
setmetatable(rcon_env, { __index = rcon_static })
|
||||
|
||||
--- Some common static values which can be added now
|
||||
--- @diagnostic disable: name-style-check
|
||||
rcon_static.Async = Async
|
||||
rcon_static.ExpUtil = ExpUtil
|
||||
rcon_static.Commands = Commands
|
||||
rcon_static.print = Commands.print
|
||||
--- @diagnostic enable: name-style-check
|
||||
|
||||
--- Some common callback values which are useful when a player uses the command
|
||||
--- @alias ExpCommand.RconDynamic fun(player: LuaPlayer?): any
|
||||
|
||||
@@ -19,7 +19,7 @@ Commands.new("_sudo", { "exp-commands_sudo.description" })
|
||||
--- @cast command ExpCommand
|
||||
--- @cast parameter string
|
||||
|
||||
--- @diagnostic disable-next-line: invisible
|
||||
--- @diagnostic disable-next-line: access-invisible
|
||||
return Commands._event_handler{
|
||||
name = command.name,
|
||||
tick = game.tick,
|
||||
|
||||
@@ -25,7 +25,7 @@ local Commands = require("modules/exp_commands")
|
||||
local add, parse = Commands.add_data_type, Commands.parse_input
|
||||
local valid, invalid = Commands.status.success, Commands.status.invalid_input
|
||||
|
||||
local types = {} --- @class Commands.types
|
||||
local types = {} --- @class (partial) Commands.types
|
||||
|
||||
--- A boolean value where true is one of: yes, y, true, 1
|
||||
types.boolean =
|
||||
|
||||
@@ -61,7 +61,7 @@ local Search = require("modules/exp_commands/search")
|
||||
--- @type LuaPlayer?
|
||||
local _print_player
|
||||
|
||||
--- @class Commands
|
||||
--- @class (partial) Commands
|
||||
local Commands = {
|
||||
color = ExpUtil.color,
|
||||
format_rich_text_color = ExpUtil.format_rich_text_color,
|
||||
@@ -84,7 +84,7 @@ local Commands = {
|
||||
--- Contains the different status values a command can return
|
||||
Commands.status = {}
|
||||
|
||||
--- @class Commands.types: table<string, Commands.InputParser | Commands.InputParserFactory>
|
||||
--- @class (partial) Commands.types: table<string, Commands.InputParser<any> | Commands.InputParserFactory<any>>
|
||||
--- Stores all input parsers and validators for different data types
|
||||
Commands.types = {}
|
||||
|
||||
@@ -103,7 +103,7 @@ end
|
||||
--- @class Commands.Argument
|
||||
--- @field name string The name of the argument
|
||||
--- @field description LocalisedString? The description of the argument
|
||||
--- @field input_parser Commands.InputParser The input parser for the argument
|
||||
--- @field input_parser Commands.InputParser<any> The input parser for the argument
|
||||
--- @field optional boolean True when the argument is optional
|
||||
--- @field default any? The default value of the argument
|
||||
|
||||
@@ -159,7 +159,7 @@ Commands.server = setmetatable({
|
||||
Commands.error("Command does not support rcon usage, requires LuaPlayer." .. key)
|
||||
error("Command does not support rcon usage, requires LuaPlayer." .. key)
|
||||
end,
|
||||
}) --[[ @as LuaPlayer ]]
|
||||
}) --[[@as LuaPlayer]]
|
||||
|
||||
--- Status Returns.
|
||||
-- Return values used by command callbacks
|
||||
@@ -170,7 +170,8 @@ Commands.server = setmetatable({
|
||||
--- @param msg LocalisedString? An optional message to be included when a command completes (only has an effect in command callbacks)
|
||||
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
|
||||
function Commands.status.success(msg)
|
||||
return Commands.status.success, msg == nil and { "exp-commands.success" } or msg
|
||||
if msg == nil then return Commands.status.success, { "exp-commands.success" } end
|
||||
return Commands.status.success, msg
|
||||
end
|
||||
|
||||
--- Used to signal an error has occurred in a command, data type parser, or permission authority
|
||||
@@ -178,7 +179,8 @@ end
|
||||
--- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided
|
||||
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
|
||||
function Commands.status.error(msg)
|
||||
return Commands.status.error, { "exp-commands.error", msg == nil and { "exp-commands.error-default" } or msg }
|
||||
if msg == nil then msg = { "exp-commands.error-default" } end
|
||||
return Commands.status.error, { "exp-commands.error", msg }
|
||||
end
|
||||
|
||||
--- Used to signal the player is unauthorised to use a command, primarily used by permission authorities but can be used in a command callback
|
||||
@@ -186,7 +188,8 @@ end
|
||||
--- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided
|
||||
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
|
||||
function Commands.status.unauthorised(msg)
|
||||
return Commands.status.unauthorised, { "exp-commands.unauthorized", msg == nil and { "exp-commands.unauthorized-default" } or msg }
|
||||
if msg == nil then msg = { "exp-commands.unauthorized-default" } end
|
||||
return Commands.status.unauthorised, { "exp-commands.unauthorized", msg }
|
||||
end
|
||||
|
||||
--- Used to signal the player provided invalid input to an command, primarily used by data type parsers but can be used in a command callback
|
||||
@@ -194,15 +197,16 @@ end
|
||||
--- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided
|
||||
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
|
||||
function Commands.status.invalid_input(msg)
|
||||
return Commands.status.invalid_input, msg == nil and { "exp-commands.invalid-input" } or msg
|
||||
if msg == nil then return Commands.status.invalid_input, { "exp-commands.invalid-input" } end
|
||||
return Commands.status.invalid_input, msg
|
||||
end
|
||||
|
||||
--- Used to signal an internal error has occurred, this is reserved for internal use only
|
||||
--- @param msg LocalisedString A message detailing the error which has occurred, will be logged and outputted
|
||||
--- @param msg LocalisedString? A message detailing the error which has occurred, will be logged and outputted
|
||||
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
|
||||
--- @package
|
||||
function Commands.status.internal_error(msg)
|
||||
return Commands.status.internal_error, { "exp-commands.internal-error", msg }
|
||||
return Commands.status.internal_error, { "exp-commands.internal-error", msg or "" }
|
||||
end
|
||||
|
||||
--- @type table<Commands.Status, string>
|
||||
@@ -281,7 +285,7 @@ end
|
||||
--- @alias Commands.InputParserFactory<T> fun(...: any): Commands.InputParser<T>
|
||||
|
||||
--- Add a new input parser to the command library, this method validates that it does not already exist
|
||||
--- @generic T : Commands.InputParser | Commands.InputParserFactory
|
||||
--- @generic T : Commands.InputParser<any> | Commands.InputParserFactory<any>
|
||||
--- @param data_type string The name of the data type the input parser reads in and validates, becomes a key of Commands.types
|
||||
--- @param input_parser T The function used to parse and validate the data type
|
||||
--- @return T # The function which was provided as the second argument
|
||||
@@ -295,7 +299,7 @@ function Commands.add_data_type(data_type, input_parser)
|
||||
end
|
||||
|
||||
--- Remove an input parser for a data type, must be the same string that was passed to add_input_parser
|
||||
--- @param data_type string | Commands.InputParser | Commands.InputParserFactory The data type or input parser you want to remove the input parser for
|
||||
--- @param data_type string | Commands.InputParser<any> | Commands.InputParserFactory<any> The data type or input parser you want to remove the input parser for
|
||||
function Commands.remove_data_type(data_type)
|
||||
Commands.types[data_type] = nil
|
||||
for k, v in pairs(Commands.types) do
|
||||
@@ -433,7 +437,7 @@ end
|
||||
--- Add a new required argument to the command of the given data type
|
||||
--- @param name string The name of the argument being added
|
||||
--- @param description LocalisedString? The description of the argument being added
|
||||
--- @param input_parser Commands.InputParser The input parser to be used for the argument
|
||||
--- @param input_parser Commands.InputParser<any> The input parser to be used for the argument
|
||||
--- @return ExpCommand
|
||||
function Commands._prototype:argument(name, description, input_parser)
|
||||
assert_command_mutable(self)
|
||||
@@ -454,7 +458,7 @@ end
|
||||
--- Add a new optional argument to the command of the given data type
|
||||
--- @param name string The name of the argument being added
|
||||
--- @param description LocalisedString? The description of the argument being added
|
||||
--- @param input_parser Commands.InputParser The input parser to be used for the argument
|
||||
--- @param input_parser Commands.InputParser<any> The input parser to be used for the argument
|
||||
--- @return ExpCommand
|
||||
function Commands._prototype:optional(name, description, input_parser)
|
||||
assert_command_mutable(self)
|
||||
|
||||
@@ -3,7 +3,7 @@ local Search = {}
|
||||
local Storage = require("modules/exp_util/storage")
|
||||
|
||||
--- Setup the storage to contain the pending translations and the completed ones
|
||||
local pending = {} --- @type { [1]: string, [2]: string }[]
|
||||
local pending = {} --- @type table<uint, [string, string]>
|
||||
local translations = {} --- @type table<string, table<string, string>>
|
||||
Storage.register({
|
||||
pending,
|
||||
@@ -50,6 +50,7 @@ function Search.prepare(custom_commands)
|
||||
name = name,
|
||||
description = locale_desc,
|
||||
help_text = locale_desc,
|
||||
usage = locale_desc,
|
||||
aliases = {},
|
||||
}
|
||||
end
|
||||
@@ -65,7 +66,7 @@ function Search.on_player_locale_changed(event)
|
||||
local ids = player.request_translations(required_translations)
|
||||
assert(ids, "Translation ids was nil")
|
||||
for i, command_name in ipairs(command_names) do
|
||||
pending[ids[i]] = { locale, command_name }
|
||||
pending[assert(ids[i])] = { locale, command_name }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,7 +3,7 @@ Adds permission group syncing to clusterio
|
||||
]]
|
||||
|
||||
local clusterio_api = require("modules/clusterio/api")
|
||||
local compat = require("modules/clusterio/compat")
|
||||
local compat = require("modules/clusterio/compat") --[[@as LibCompat]]
|
||||
|
||||
--- Top level module table, contains event handlers and public methods
|
||||
--- @class ExpGroups
|
||||
|
||||
@@ -5,7 +5,7 @@ Therefore, we advise that this should be the only file in your module to expose
|
||||
Typically this would be your control file as shown in the example below
|
||||
]]
|
||||
|
||||
--- @diagnostic disable: global-element
|
||||
--- @diagnostic disable: global-in-non-module
|
||||
|
||||
-- Access using `/sc exp_groups.foo()`
|
||||
exp_groups = require("modules/exp_groups/control")
|
||||
|
||||
+17
-12
@@ -16,7 +16,7 @@ Storage.register(player_elements, function(tbl)
|
||||
player_elements = tbl
|
||||
end)
|
||||
|
||||
--- @class Gui
|
||||
--- @class (partial) Gui
|
||||
local Gui = {
|
||||
define = ExpElement.new,
|
||||
from_argument = ExpElement.from_argument,
|
||||
@@ -46,9 +46,11 @@ end
|
||||
--- @return LuaPlayer
|
||||
function Gui.get_player(input)
|
||||
if type(input) == "table" and not input.player_index then
|
||||
return assert(game.get_player(input.element.player_index))
|
||||
--- @cast input { element: LuaGuiElement }
|
||||
return (assert(game.get_player(input.element.player_index)))
|
||||
end
|
||||
return assert(game.get_player(input.player_index))
|
||||
--- @cast input LuaGuiElement | { player_index: uint }
|
||||
return (assert(game.get_player(input.player_index)))
|
||||
end
|
||||
|
||||
--- Toggle the enable state of an element
|
||||
@@ -88,7 +90,7 @@ end
|
||||
--- @param define ExpElement
|
||||
--- @param visible Gui.VisibleCallback | boolean | nil
|
||||
function Gui.add_top_element(define, visible)
|
||||
assert(Gui.top_elements[define.name] == nil, "Element is already added to the top flow")
|
||||
assert(Gui.top_elements[define] == nil, "Element is already added to the top flow")
|
||||
Gui.top_elements[define] = visible or false
|
||||
end
|
||||
|
||||
@@ -96,7 +98,7 @@ end
|
||||
--- @param define ExpElement
|
||||
--- @param visible Gui.VisibleCallback | boolean | nil
|
||||
function Gui.add_left_element(define, visible)
|
||||
assert(Gui.left_elements[define.name] == nil, "Element is already added to the left flow")
|
||||
assert(Gui.left_elements[define] == nil, "Element is already added to the left flow")
|
||||
Gui.left_elements[define] = visible or false
|
||||
|
||||
end
|
||||
@@ -105,7 +107,7 @@ end
|
||||
--- @param define ExpElement
|
||||
--- @param visible Gui.VisibleCallback | boolean | nil
|
||||
function Gui.add_relative_element(define, visible)
|
||||
assert(Gui.relative_elements[define.name] == nil, "Element is already added to the relative flow")
|
||||
assert(Gui.relative_elements[define] == nil, "Element is already added to the relative flow")
|
||||
Gui.relative_elements[define] = visible or false
|
||||
end
|
||||
|
||||
@@ -114,7 +116,8 @@ end
|
||||
--- @param player LuaPlayer
|
||||
--- @return LuaGuiElement
|
||||
function Gui.get_top_element(define, player)
|
||||
return assert(player_elements[player.index].top[define.name], "Element is not on the top flow")
|
||||
local elements = assert(player_elements[player.index])
|
||||
return (assert(elements.top[define.name], "Element is not on the top flow"))
|
||||
end
|
||||
|
||||
--- Register a element define to be drawn to the left flow on join
|
||||
@@ -122,7 +125,8 @@ end
|
||||
--- @param player LuaPlayer
|
||||
--- @return LuaGuiElement
|
||||
function Gui.get_left_element(define, player)
|
||||
return assert(player_elements[player.index].left[define.name], "Element is not on the left flow")
|
||||
local elements = assert(player_elements[player.index])
|
||||
return (assert(elements.left[define.name], "Element is not on the left flow"))
|
||||
end
|
||||
|
||||
--- Register a element define to be drawn to the relative flow on join
|
||||
@@ -130,7 +134,8 @@ end
|
||||
--- @param player LuaPlayer
|
||||
--- @return LuaGuiElement
|
||||
function Gui.get_relative_element(define, player)
|
||||
return assert(player_elements[player.index].relative[define.name], "Element is not on the relative flow")
|
||||
local elements = assert(player_elements[player.index])
|
||||
return (assert(elements.relative[define.name], "Element is not on the relative flow"))
|
||||
end
|
||||
|
||||
--- Ensure all the correct elements are visible and exist
|
||||
@@ -188,9 +193,9 @@ function Gui._ensure_consistency(event)
|
||||
|
||||
-- This check isn't needed, but allows the toolbar file to be deleted without modifying any lib code
|
||||
if Gui.toolbar then
|
||||
--- @diagnostic disable-next-line invisible
|
||||
--- @diagnostic disable-next-line: access-invisible
|
||||
Gui.toolbar._create_elements(player)
|
||||
--- @diagnostic disable-next-line invisible
|
||||
--- @diagnostic disable-next-line: access-invisible
|
||||
Gui.toolbar._ensure_consistency(player)
|
||||
end
|
||||
end
|
||||
@@ -211,7 +216,7 @@ local function on_gui_opened(event)
|
||||
|
||||
if visible then
|
||||
event.element = element
|
||||
--- @diagnostic disable-next-line invisible
|
||||
--- @diagnostic disable-next-line: access-invisible
|
||||
define:raise_event(event)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -62,6 +62,7 @@ local GuiData = {
|
||||
--- @field player_data table<uint, any>
|
||||
--- @field force_data table<uint, any>
|
||||
--- @field global_data table
|
||||
--- @field [DataKey] any
|
||||
-- This class has no prototype methods
|
||||
-- Same as raw but __index ensures the values exist
|
||||
|
||||
@@ -89,13 +90,16 @@ function GuiData._metatable.__index(self, key)
|
||||
assert(type(key) == "userdata", "Index type '" .. ExpUtil.get_class_name(key) .. "' given to GuiData. Must be of type userdata.")
|
||||
local object_name = key.object_name --- @diagnostic disable-line assign-type-mismatch
|
||||
if object_name == "LuaGuiElement" then
|
||||
--- @cast key LuaGuiElement
|
||||
local data = self._raw.element_data
|
||||
local player_elements = data and data[key.player_index]
|
||||
return player_elements and player_elements[key.index]
|
||||
elseif object_name == "LuaPlayer" then
|
||||
--- @cast key LuaPlayer
|
||||
local data = self._raw.player_data
|
||||
return data and data[key.index]
|
||||
elseif object_name == "LuaForce" then
|
||||
--- @cast key LuaForce
|
||||
local data = self._raw.force_data
|
||||
return data and data[key.index]
|
||||
else
|
||||
@@ -153,7 +157,7 @@ end
|
||||
--- @param scope string
|
||||
--- @return GuiData
|
||||
function GuiData.get(scope)
|
||||
return GuiData._scopes[scope] --[[ @as GuiData ]]
|
||||
return GuiData._scopes[scope] --[[@as GuiData]]
|
||||
end
|
||||
|
||||
--- Used to clean up data from destroyed elements
|
||||
@@ -168,7 +172,7 @@ local function on_object_destroyed(event)
|
||||
for _, scope in pairs(registered_scopes) do
|
||||
local data = scope._raw.element_data
|
||||
local player_elements = data and data[player_index]
|
||||
if player_elements then
|
||||
if data and player_elements then
|
||||
player_elements[element_index] = nil
|
||||
if not next(player_elements) then
|
||||
data[player_index] = nil
|
||||
|
||||
+17
-17
@@ -1,4 +1,4 @@
|
||||
--- @class Gui
|
||||
--- @class (partial) Gui
|
||||
local Gui = require("modules/exp_gui")
|
||||
|
||||
--- @class Gui.elements
|
||||
@@ -28,7 +28,7 @@ Elements.aligned_flow = Gui.define("aligned_flow")
|
||||
vertically_stretchable = vertical_align ~= "center",
|
||||
horizontally_stretchable = horizontal_align ~= "center",
|
||||
}
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- A solid horizontal white bar element
|
||||
--- @class Gui.elements.bar: ExpElement
|
||||
@@ -48,11 +48,11 @@ Elements.bar = Gui.define("bar")
|
||||
else
|
||||
style.horizontally_stretchable = true
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- A label which is centered
|
||||
--- @class Gui.elements.centered_label: ExpElement
|
||||
--- @overload fun(parent: LuaGuiElement, width: number, caption: LocalisedString, tooltip: LocalisedString?): LuaGuiElement
|
||||
--- @overload fun(parent: LuaGuiElement, width: number, caption: LocalisedString?, tooltip: LocalisedString?): LuaGuiElement
|
||||
Elements.centered_label = Gui.define("centered_label")
|
||||
:draw{
|
||||
type = "label",
|
||||
@@ -63,7 +63,7 @@ Elements.centered_label = Gui.define("centered_label")
|
||||
horizontal_align = "center",
|
||||
single_line = false,
|
||||
width = Gui.from_argument(1),
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- A label which has two white bars on either side of it
|
||||
--- @class Gui.elements.title_label: ExpElement
|
||||
@@ -91,7 +91,7 @@ Elements.title_label = Gui.define("title_label")
|
||||
Elements.bar(flow)
|
||||
|
||||
return label
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- A fixed size vertical scroll pane
|
||||
--- @class Gui.elements.scroll_pane: ExpElement
|
||||
@@ -109,7 +109,7 @@ Elements.scroll_pane = Gui.define("scroll_pane")
|
||||
padding = { 1, 3 },
|
||||
maximal_height = Gui.from_argument(1),
|
||||
horizontally_stretchable = true,
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- A fixed size vertical scroll pane containing a table
|
||||
--- @class Gui.elements.scroll_table: ExpElement
|
||||
@@ -132,7 +132,7 @@ Elements.scroll_table = Gui.define("scroll_table")
|
||||
cell_padding = 1,
|
||||
vertical_align = "center",
|
||||
horizontally_stretchable = true,
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- A container frame
|
||||
--- @class Gui.elements.container: ExpElement
|
||||
@@ -159,13 +159,13 @@ Elements.container = Gui.define("container")
|
||||
vertically_stretchable = false,
|
||||
horizontally_stretchable = false,
|
||||
minimal_width = Gui.from_argument(1),
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- Get the root element of a container
|
||||
--- @param container LuaGuiElement
|
||||
--- @return LuaGuiElement
|
||||
function Elements.container.get_root_element(container)
|
||||
return container.parent
|
||||
return assert(container.parent)
|
||||
end
|
||||
|
||||
--- A frame within a container
|
||||
@@ -183,7 +183,7 @@ Elements.subframe_base = Gui.define("container_subframe")
|
||||
padding = { 3, 6, 0, 6 },
|
||||
use_header_filler = false,
|
||||
horizontally_stretchable = true,
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- @class Gui.elements.header.opts
|
||||
--- @field name string?
|
||||
@@ -212,7 +212,7 @@ Elements.header = Gui.define("container_header")
|
||||
subframe.add{ type = "empty-widget" }.style.horizontally_stretchable = true
|
||||
|
||||
return subframe
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- @class Gui.elements.footer.opts
|
||||
--- @field name string?
|
||||
@@ -241,7 +241,7 @@ Elements.footer = Gui.define("container_footer")
|
||||
subframe.add{ type = "empty-widget" }.style.horizontally_stretchable = true
|
||||
|
||||
return subframe
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- A button used to destroy its target when clicked, intended for screen frames
|
||||
--- @class Gui.elements.screen_frame_close: ExpElement
|
||||
@@ -259,7 +259,7 @@ Elements.screen_frame_close = Gui.define("screen_frame_close")
|
||||
:on_click(function(def, player, element, event)
|
||||
--- @cast def Gui.elements.screen_frame_close
|
||||
Gui.destroy_if_valid(def.data[element])
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- A draggable frame with close button and button flow
|
||||
--- @class Gui.elements.screen_frame: ExpElement
|
||||
@@ -313,20 +313,20 @@ Elements.screen_frame = Gui.define("screen_frame")
|
||||
direction = "vertical",
|
||||
style = "inside_shallow_frame_packed",
|
||||
}
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Get the button flow for a screen frame
|
||||
--- @param screen_frame LuaGuiElement
|
||||
--- @return LuaGuiElement
|
||||
function Elements.screen_frame.get_button_flow(screen_frame)
|
||||
return assert(Elements.screen_frame.data[screen_frame.parent], "Screen frame has no button flow")
|
||||
return (assert(Elements.screen_frame.data[assert(screen_frame.parent)], "Screen frame has no button flow"))
|
||||
end
|
||||
|
||||
--- Get the root element of a screen frame
|
||||
--- @param screen_frame LuaGuiElement
|
||||
--- @return LuaGuiElement
|
||||
function Elements.screen_frame.get_root_element(screen_frame)
|
||||
return screen_frame.parent
|
||||
return assert(screen_frame.parent)
|
||||
end
|
||||
|
||||
return Elements
|
||||
|
||||
@@ -166,7 +166,6 @@ end
|
||||
function GuiIter.get_tracked_elements(scope, filter)
|
||||
local class_name = ExpUtil.get_class_name(filter)
|
||||
if class_name == "nil" then
|
||||
--- @cast filter nil
|
||||
return GuiIter.all_elements(scope)
|
||||
elseif class_name == "LuaPlayer" then
|
||||
--- @cast filter LuaPlayer
|
||||
@@ -189,7 +188,6 @@ end
|
||||
function GuiIter.get_online_elements(scope, filter)
|
||||
local class_name = ExpUtil.get_class_name(filter)
|
||||
if class_name == "nil" then
|
||||
--- @cast filter nil
|
||||
return GuiIter.filtered_elements(scope, game.connected_players)
|
||||
elseif class_name == "LuaPlayer" then
|
||||
--- @cast filter LuaPlayer
|
||||
@@ -235,7 +233,7 @@ end
|
||||
function GuiIter.remove_element(scope, player_index, element_index)
|
||||
local scope_elements = registered_scopes[scope]
|
||||
if not scope_elements then return end
|
||||
local player_elements = registered_scopes[player_index]
|
||||
local player_elements = scope_elements[player_index]
|
||||
if not player_elements then return end
|
||||
player_elements[element_index] = nil
|
||||
end
|
||||
|
||||
@@ -43,6 +43,8 @@ ExpElement.events = {}
|
||||
--- @field _force_data ExpElement.PostDrawCallback?
|
||||
--- @field _global_data ExpElement.PostDrawCallback?
|
||||
--- @field _events table<defines.events, ExpElement.EventHandler<EventData>[]>
|
||||
--- @field _has_handlers boolean
|
||||
--- @field _track_elements boolean
|
||||
--- @overload fun(parent: LuaGuiElement, ...: any): LuaGuiElement
|
||||
ExpElement._prototype = {
|
||||
_track_elements = false,
|
||||
@@ -158,7 +160,7 @@ function ExpElement.new(name)
|
||||
},
|
||||
}
|
||||
|
||||
ExpElement._elements[element_name] = instance --[[ @as ExpElement ]]
|
||||
ExpElement._elements[element_name] = instance --[[@as ExpElement]]
|
||||
return setmetatable(instance, ExpElement._metatable)
|
||||
end
|
||||
|
||||
@@ -166,7 +168,7 @@ end
|
||||
--- @param name string
|
||||
--- @return ExpElement
|
||||
function ExpElement.get(name)
|
||||
return assert(ExpElement._elements[name], "ExpElement is not defined: " .. tostring(name))
|
||||
return (assert(ExpElement._elements[name], "ExpElement is not defined: " .. tostring(name)))
|
||||
end
|
||||
|
||||
--- Create a new instance of this element definition
|
||||
@@ -460,7 +462,7 @@ function ExpElement._prototype:raise_event(event)
|
||||
for _, handler in ipairs(handlers) do
|
||||
-- All gui elements will contain player and element, other events might have these as nil
|
||||
-- Therefore only the signature of on_event has these values as optional
|
||||
handler(self, player --[[ @as LuaPlayer ]], event.element, event --[[ @as EventData ]])
|
||||
handler(self, player --[[@as LuaPlayer]], event.element, event --[[@as EventData]])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
--- @class Gui
|
||||
--- @class (partial) Gui
|
||||
local Gui = require("modules/exp_gui")
|
||||
|
||||
--- @class Gui.styles
|
||||
|
||||
+18
-16
@@ -1,5 +1,5 @@
|
||||
|
||||
--- @class Gui
|
||||
--- @class (partial) Gui
|
||||
local Gui = require("modules/exp_gui")
|
||||
local ExpElement = require("modules/exp_gui/prototype")
|
||||
local mod_gui = require("mod-gui")
|
||||
@@ -29,7 +29,7 @@ Toolbar.on_gui_button_toggled = script.generate_event_name()
|
||||
--- @class _ExpElement._prototype
|
||||
--- @field on_button_toggled ExpElement.OnEventAdder<EventData.on_gui_button_toggled>
|
||||
|
||||
--- @diagnostic disable-next-line: invisible, inject-field
|
||||
--- @diagnostic disable-next-line: access-invisible, inject-field
|
||||
function ExpElement._prototype.on_button_toggled(self, handler)
|
||||
return self:on_event(Toolbar.on_gui_button_toggled, handler)
|
||||
end
|
||||
@@ -85,7 +85,7 @@ function Toolbar.set_button_toggled_state(define, player, state, _from_left)
|
||||
button.style = state and toolbar_button_active_style or toolbar_button_default_style
|
||||
|
||||
-- Make the extra required adjustments
|
||||
local style = button.style
|
||||
local style = button.style --[[@as LuaStyle]]
|
||||
style.minimal_width = original_width
|
||||
style.maximal_height = original_height
|
||||
if button.type == "sprite-button" then
|
||||
@@ -335,9 +335,10 @@ Below here is the toolbar settings GUI and its associated functions
|
||||
--- @param dst LuaGuiElement
|
||||
local function copy_style(src, dst)
|
||||
dst.style = src.style.name
|
||||
dst.style.height = toolbar_button_small
|
||||
dst.style.width = toolbar_button_small
|
||||
dst.style.padding = -2
|
||||
local style = dst.style --[[@as LuaStyle]]
|
||||
style.height = toolbar_button_small
|
||||
style.width = toolbar_button_small
|
||||
style.padding = -2
|
||||
end
|
||||
|
||||
--- Reorder the buttons relative to each other, this will update the datastore
|
||||
@@ -350,7 +351,7 @@ local function move_toolbar_button(player, item, offset)
|
||||
|
||||
-- Swap the position in the list
|
||||
local list = assert(item.parent)
|
||||
local other_item = list.children[new_index]
|
||||
local other_item = assert(list.children[new_index])
|
||||
list.swap_children(old_index, new_index)
|
||||
|
||||
-- Swap the position in the top flow, offset by 1 because of settings button
|
||||
@@ -365,7 +366,7 @@ local function move_toolbar_button(player, item, offset)
|
||||
local other_element = Gui.get_left_element(other_left_element, player)
|
||||
local left_index = element.get_index_in_parent()
|
||||
local other_index = other_element.get_index_in_parent()
|
||||
element.parent.swap_children(left_index, other_index)
|
||||
assert(element.parent).swap_children(left_index, other_index)
|
||||
end
|
||||
|
||||
-- If we are moving in/out of first/last place we need to update the move buttons
|
||||
@@ -393,7 +394,7 @@ end
|
||||
--- @param player LuaPlayer
|
||||
--- @param order Gui.ToolbarOrder
|
||||
function Toolbar.set_order(player, order)
|
||||
local list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]]
|
||||
local list = elements.toolbar_settings.data[player] --[[@as LuaGuiElement]]
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
|
||||
@@ -466,7 +467,7 @@ end
|
||||
function Toolbar.get_state(player)
|
||||
-- Get the order of toolbar buttons
|
||||
local order = {}
|
||||
local list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]]
|
||||
local list = elements.toolbar_settings.data[player] --[[@as LuaGuiElement]]
|
||||
for index, item in pairs(list.children) do
|
||||
order[index] = { name = item.name, favourite = elements.toolbar_list_item.data[item].set_favourite.state }
|
||||
end
|
||||
@@ -487,7 +488,7 @@ end
|
||||
--- @param player LuaPlayer
|
||||
function Toolbar._create_elements(player)
|
||||
-- Add any missing items to the gui
|
||||
local toolbar_list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]]
|
||||
local toolbar_list = elements.toolbar_settings.data[player] --[[@as LuaGuiElement]]
|
||||
local previous_last_index = #toolbar_list.children_names
|
||||
for define in pairs(Gui.top_elements) do
|
||||
if define ~= elements.close_toolbar and toolbar_list[define.name] == nil then
|
||||
@@ -499,7 +500,8 @@ function Toolbar._create_elements(player)
|
||||
-- Reset the state of the previous last child
|
||||
local children = toolbar_list.children
|
||||
if previous_last_index > 0 then
|
||||
elements.toolbar_list_item.data[children[previous_last_index]].move_item_down.enabled = true
|
||||
local previous_last = assert(children[previous_last_index])
|
||||
elements.toolbar_list_item.data[previous_last].move_item_down.enabled = true
|
||||
end
|
||||
|
||||
-- Set the state of the move buttons for the first and last element
|
||||
@@ -513,7 +515,7 @@ end
|
||||
--- @param player LuaPlayer
|
||||
function Toolbar._ensure_consistency(player)
|
||||
-- Update the toolbar buttons
|
||||
local list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]]
|
||||
local list = elements.toolbar_settings.data[player] --[[@as LuaGuiElement]]
|
||||
for _, button in ipairs(toolbar_buttons) do
|
||||
-- Update the visible state based on if the player is allowed the button
|
||||
local element = Gui.get_top_element(button, player)
|
||||
@@ -619,7 +621,7 @@ elements.move_item_up = Gui.define("move_item_up")
|
||||
size = toolbar_button_small,
|
||||
})
|
||||
:on_click(function(def, player, element)
|
||||
local item = assert(element.parent.parent)
|
||||
local item = assert(assert(element.parent).parent)
|
||||
move_toolbar_button(player, item, -1)
|
||||
end)
|
||||
|
||||
@@ -634,7 +636,7 @@ elements.move_item_down = Gui.define("move_item_down")
|
||||
size = toolbar_button_small,
|
||||
})
|
||||
:on_click(function(def, player, element)
|
||||
local item = assert(element.parent.parent)
|
||||
local item = assert(assert(element.parent).parent)
|
||||
move_toolbar_button(player, item, 1)
|
||||
end)
|
||||
|
||||
@@ -658,7 +660,7 @@ elements.set_favourite = Gui.define("set_favourite")
|
||||
width = 180,
|
||||
}
|
||||
:on_checked_state_changed(function(def, player, element)
|
||||
local define = ExpElement.get(element.tags.element_name --[[ @as string ]])
|
||||
local define = ExpElement.get(element.tags.element_name --[[@as string]])
|
||||
local top_element = Gui.get_top_element(define, player)
|
||||
local had_visible = Toolbar.has_visible_buttons(player)
|
||||
top_element.visible = element.state
|
||||
|
||||
@@ -24,6 +24,7 @@ local afk_time_units = {
|
||||
}
|
||||
|
||||
return {
|
||||
--- @type table<string, LocalisedString | fun(player: LuaPlayer, is_command: boolean): LocalisedString>
|
||||
messages = { --- @setting messages will trigger when ever the word is said
|
||||
["discord"] = { "info.discord" },
|
||||
["expgaming"] = { "info.website" },
|
||||
@@ -66,6 +67,7 @@ return {
|
||||
command_admin_only = false, --- @setting command_admin_only when true will only allow chat commands for admins
|
||||
command_permission = "command/chat-commands", --- @setting command_permission the permission used to allow command prefixes
|
||||
command_prefix = "!", --- @setting command_prefix prefix used for commands below and to print to all players (if enabled above)
|
||||
--- @type table<string, LocalisedString | fun(player: LuaPlayer, is_command: boolean): LocalisedString>
|
||||
commands = { --- @setting commands will trigger only when command prefix is given
|
||||
["dev"] = { "exp_chat-auto-reply.reply-dev" },
|
||||
["magic"] = { "exp_chat-auto-reply.reply-magic" },
|
||||
|
||||
@@ -15,7 +15,8 @@ local Colors = require("modules/exp_util/include/color")
|
||||
local format_player_name = ExpUtil.format_player_name_locale
|
||||
|
||||
--- Accessors injected by the gui so the actions can read the selected player and set the selected action
|
||||
local get_selected_player, set_selected_action
|
||||
local get_selected_player --- @type fun(player: LuaPlayer): LuaPlayer
|
||||
local set_selected_action --- @type fun(player: LuaPlayer, action: string?)
|
||||
local function set_accessors(player_getter, action_setter)
|
||||
get_selected_player, set_selected_action = player_getter, action_setter
|
||||
end
|
||||
@@ -31,7 +32,7 @@ end
|
||||
|
||||
-- gets the action player and a coloured name for the action to be used on
|
||||
local function get_action_player(player)
|
||||
local selected_player = get_selected_player(player) --[[ @as LuaPlayer ]]
|
||||
local selected_player = get_selected_player(player) --[[@as LuaPlayer]]
|
||||
local selected_player_color = format_player_name(selected_player)
|
||||
return selected_player, selected_player_color
|
||||
end
|
||||
|
||||
@@ -87,7 +87,7 @@ return {
|
||||
amount = 4000,
|
||||
size = { 26, 27 },
|
||||
-- offset = {-64,-32}
|
||||
offset = { -64, -64 },
|
||||
offset = { x = -64, y = -64 },
|
||||
},
|
||||
{
|
||||
enabled = false,
|
||||
@@ -95,7 +95,7 @@ return {
|
||||
amount = 4000,
|
||||
size = { 26, 27 },
|
||||
-- offset = {-64, 0}
|
||||
offset = { 64, -64 },
|
||||
offset = { x = 64, y = -64 },
|
||||
},
|
||||
{
|
||||
enabled = false,
|
||||
@@ -103,7 +103,7 @@ return {
|
||||
amount = 4000,
|
||||
size = { 22, 20 },
|
||||
-- offset = {-64, 32}
|
||||
offset = { -64, 64 },
|
||||
offset = { x = -64, y = 64 },
|
||||
},
|
||||
{
|
||||
enabled = false,
|
||||
@@ -111,7 +111,7 @@ return {
|
||||
amount = 4000,
|
||||
size = { 22, 20 },
|
||||
-- offset = {-64, -64}
|
||||
offset = { 64, 64 },
|
||||
offset = { x = 64, y = 64 },
|
||||
},
|
||||
{
|
||||
enabled = false,
|
||||
@@ -119,7 +119,7 @@ return {
|
||||
amount = 4000,
|
||||
size = { 22, 20 },
|
||||
-- offset = {-64, -96}
|
||||
offset = { 0, 64 },
|
||||
offset = { x = 0, y = 64 },
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -132,7 +132,7 @@ return {
|
||||
num_patches = 4,
|
||||
amount = 4000000,
|
||||
-- offset = {-80, -12},
|
||||
offset = { -12, 64 },
|
||||
offset = { x = -12, y = 64 },
|
||||
-- offset_next = {0, 6}
|
||||
offset_next = { 6, 0 },
|
||||
},
|
||||
|
||||
@@ -35,6 +35,20 @@ return {
|
||||
storage_output = 1, -- >0 allows for item teleportation (allowed_items only)
|
||||
},
|
||||
|
||||
--- @class Vlayer.ItemProperties
|
||||
--- @field starting_value number
|
||||
--- @field required_area number
|
||||
--- @field production number?
|
||||
--- @field discharge number?
|
||||
--- @field capacity number?
|
||||
--- @field surface_area number?
|
||||
--- @field fuel_value number?
|
||||
--- @field power boolean?
|
||||
--- @field modded boolean? Set when the item is registered from a modded equivalent
|
||||
--- @field base_game_equivalent string?
|
||||
--- @field multiplier number?
|
||||
|
||||
--- @type table<string, Vlayer.ItemProperties>
|
||||
allowed_items = { --- @setting allowed_items List of all items allowed in vlayer storage and their properties
|
||||
--[[
|
||||
Allowed properties:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
-- @config Warnings
|
||||
|
||||
return {
|
||||
--- @type (LocalisedString[] | fun(player: LuaPlayer, by_player_name: string, number_of_warnings: number))[]
|
||||
actions = { --- @setting actions what actions are taking at number of warnings
|
||||
-- if a localized string is used then __1__ will by_player_name and __2__ will be the current warning count (auto inserted)
|
||||
{ "warnings.received", "" },
|
||||
|
||||
@@ -149,9 +149,23 @@ PlayerData.Statistics:combine('JoinCount')
|
||||
local Storage = require("modules/exp_util/storage")
|
||||
|
||||
local DatastoreManager = {}
|
||||
local Datastores = {}
|
||||
local Datastore = {}
|
||||
local Datastores = {} --- @type table<string, Datastore>
|
||||
local Data = {}
|
||||
|
||||
--- @class Datastore
|
||||
--- @field name string
|
||||
--- @field value_name string
|
||||
--- @field auto_save boolean
|
||||
--- @field save_to_disk boolean
|
||||
--- @field propagate_changes boolean
|
||||
--- @field serializer function | false
|
||||
--- @field parent Datastore | false
|
||||
--- @field children table<string, Datastore>
|
||||
--- @field metadata table
|
||||
--- @field events table<string, function[]>
|
||||
--- @field data table
|
||||
local Datastore = {}
|
||||
|
||||
local copy = table.deep_copy
|
||||
local trace = debug.traceback
|
||||
local table_to_json = helpers.table_to_json
|
||||
|
||||
@@ -14,7 +14,8 @@ end
|
||||
|
||||
]]
|
||||
|
||||
local ext, var
|
||||
local ext --- @type table<string, any>
|
||||
local var --- @type table<string, any>
|
||||
local concat = table.concat
|
||||
|
||||
local External = {}
|
||||
@@ -29,12 +30,13 @@ end
|
||||
|
||||
]]
|
||||
function External.valid()
|
||||
if storage.ext == nil then return false end
|
||||
if ext == storage.ext and var == ext.var then
|
||||
local stored = storage.ext
|
||||
if stored == nil then return false end
|
||||
if ext == stored and var == ext.var then
|
||||
return var ~= nil
|
||||
else
|
||||
ext = storage.ext
|
||||
var = ext.var
|
||||
ext = stored
|
||||
var = stored.var
|
||||
return var ~= nil
|
||||
end
|
||||
end
|
||||
@@ -48,7 +50,7 @@ local servers = External.get_servers()
|
||||
]]
|
||||
function External.get_servers()
|
||||
assert(ext, "No external data was found, use External.valid() to ensure external data exists.")
|
||||
return assert(ext.servers, "No server list was found, please ensure that the external service is running")
|
||||
return (assert(ext.servers, "No server list was found, please ensure that the external service is running"))
|
||||
end
|
||||
|
||||
--[[-- Gets a table of all the servers filtered by name, key is the server id, value is the server details
|
||||
@@ -83,7 +85,7 @@ function External.get_current_server()
|
||||
assert(ext, "No external data was found, use External.valid() to ensure external data exists.")
|
||||
local servers = assert(ext.servers, "No server list was found, please ensure that the external service is running")
|
||||
local server_id = assert(ext.current, "No current id was found, please ensure that the external service is running")
|
||||
return assert(servers[server_id], "No details found for server with id: " .. tostring(server_id))
|
||||
return (assert(servers[server_id], "No details found for server with id: " .. tostring(server_id)))
|
||||
end
|
||||
|
||||
--[[-- Gets the details of the given server
|
||||
@@ -97,7 +99,7 @@ local server = External.get_server_details('eu-01')
|
||||
function External.get_server_details(server_id)
|
||||
assert(ext, "No external data was found, use External.valid() to ensure external data exists.")
|
||||
local servers = assert(ext.servers, "No server list was found, please ensure that the external service is running")
|
||||
return assert(servers[server_id], "No details found for server with id: " .. tostring(server_id))
|
||||
return (assert(servers[server_id], "No details found for server with id: " .. tostring(server_id)))
|
||||
end
|
||||
|
||||
--[[-- Gets the status of the given server
|
||||
|
||||
@@ -142,7 +142,7 @@ group:set_action('toggle_map_editor', false)
|
||||
|
||||
]]
|
||||
function PermissionsGroups._prototype:set_action(action, state)
|
||||
local input_action = defines.input_action[action] --[[ @as defines.input_action? ]]
|
||||
local input_action = defines.input_action[action] --[[@as defines.input_action?]]
|
||||
if input_action == nil then input_action = action end
|
||||
assert(type(input_action) == "number", tostring(action) .. " is not a valid input action")
|
||||
self.actions[input_action] = state
|
||||
|
||||
@@ -55,7 +55,7 @@ PlayerData:set_serializer(Datastore.name_serializer) -- use player name
|
||||
|
||||
--- Store and enum for the data saving preference
|
||||
local DataSavingPreference = PlayerData:combine("DataSavingPreference")
|
||||
local PreferenceEnum = { "All", "Statistics", "Settings", "Required" }
|
||||
local PreferenceEnum = { "All", "Statistics", "Settings", "Required" } --- @type table<string | number, string | number>
|
||||
for k, v in ipairs(PreferenceEnum) do PreferenceEnum[v] = k end
|
||||
|
||||
DataSavingPreference:set_default("All")
|
||||
|
||||
@@ -117,11 +117,28 @@ local Groups = require("modules.exp_legacy.expcore.permission_groups")
|
||||
local Colours = ExpUtil.color
|
||||
local write_json = ExpUtil.write_json
|
||||
|
||||
|
||||
--- @class Roles.Role
|
||||
--- @field name string
|
||||
--- @field short_hand string
|
||||
--- @field index number Position within the role order
|
||||
--- @field allowed_actions table<string, boolean>
|
||||
--- @field allow_all_actions boolean
|
||||
--- @field flags table<string, boolean>
|
||||
--- @field disallowed_actions table<string, boolean>?
|
||||
--- @field permission_group ([boolean, string] | string)?
|
||||
--- @field custom_tag string?
|
||||
--- @field custom_color Color?
|
||||
--- @field parent string?
|
||||
--- @field block_auto_assign boolean?
|
||||
--- @field auto_assign_condition function?
|
||||
--- @field set_allow_all fun(self: Roles.Role, state: boolean?): Roles.Role Defined on Roles._prototype
|
||||
|
||||
local Roles = {
|
||||
_prototype = {},
|
||||
config = {
|
||||
order = {}, -- Contains the order of the roles, lower index is better
|
||||
roles = {}, -- Contains the raw info for the roles, indexed by role name
|
||||
order = {}, --- @type string[] Contains the order of the roles, lower index is better
|
||||
roles = {}, --- @type table<string, Roles.Role> Contains the raw info for the roles, indexed by role name
|
||||
flags = {}, -- Contains functions that run when a flag is added/removed from a player
|
||||
internal = {}, -- Contains all internally accessed roles, such as root, default
|
||||
players = {}, -- Contains the roles that players have
|
||||
@@ -200,7 +217,7 @@ function Roles.debug()
|
||||
local output = ""
|
||||
for index, role_name in ipairs(Roles.config.order) do
|
||||
local role = Roles.config.roles[role_name]
|
||||
local color = role.custom_color or Colours.white
|
||||
local color = (role.custom_color or Colours.white) --[[@as Color.struct]]
|
||||
local color_str = string.format("[color=%d, %d, %d]", color.r, color.g, color.b)
|
||||
output = output .. string.format("\n%s %s) %s[/color]", color_str, index, serpent.line(role))
|
||||
end
|
||||
@@ -287,6 +304,7 @@ local role = Roles.get_role_by_name(2)
|
||||
]]
|
||||
function Roles.get_role_by_order(index)
|
||||
local name = Roles.config.order[index]
|
||||
if not name then return end
|
||||
return Roles.config.roles[name]
|
||||
end
|
||||
|
||||
@@ -348,16 +366,17 @@ end
|
||||
local role = Roles.get_player_highest_role(game.player)
|
||||
|
||||
]]
|
||||
--- @return Roles.Role
|
||||
function Roles.get_player_highest_role(player)
|
||||
local roles = Roles.get_player_roles(player)
|
||||
local highest
|
||||
local highest --- @type Roles.Role?
|
||||
for _, role in ipairs(roles) do
|
||||
if not highest or role.index < highest.index then
|
||||
highest = role
|
||||
end
|
||||
end
|
||||
|
||||
return highest
|
||||
return (assert(highest, "Player has no roles"))
|
||||
end
|
||||
|
||||
--- Assignment.
|
||||
@@ -458,7 +477,7 @@ function Roles.unassign_player(player, roles, by_player_name, skip_checks, silen
|
||||
|
||||
-- If the player has a role that needs to defer the role changes, save the roles that need to be unassigned later into a table
|
||||
local defer_changes = Roles.player_has_flag(player, "defer_role_changes")
|
||||
if defer_changes then
|
||||
if defer_changes and valid_player then
|
||||
local assign_later = Roles.config.deferred_roles[valid_player.name] or {}
|
||||
for _, role in ipairs(role_objects) do
|
||||
local role_change = assign_later[role.name]
|
||||
@@ -719,7 +738,7 @@ local role = Roles.new_role('Moderator', 'Mod')
|
||||
]]
|
||||
function Roles.new_role(name, short_hand)
|
||||
ExpUtil.assert_not_runtime()
|
||||
if Roles.config.roles[name] then return error("Role name is non unique") end
|
||||
if Roles.config.roles[name] then error("Role name is non unique") end
|
||||
local role = setmetatable({
|
||||
name = name,
|
||||
short_hand = short_hand or name,
|
||||
@@ -894,10 +913,9 @@ role:set_permission_group('Admin')
|
||||
function Roles._prototype:set_permission_group(name, use_factorio_api)
|
||||
ExpUtil.assert_not_runtime()
|
||||
if use_factorio_api then
|
||||
self.permission_group = { true, name }
|
||||
self.permission_group = { true, name } --[[@as [boolean, string] ]]
|
||||
else
|
||||
local group = Groups.get_group_by_name(name)
|
||||
if not group then return end
|
||||
assert(Groups.get_group_by_name(name), "Permission group not found: " .. name)
|
||||
self.permission_group = name
|
||||
end
|
||||
return self
|
||||
@@ -1115,8 +1133,9 @@ local function role_update(event)
|
||||
-- Updates the players permission group
|
||||
local highest = Roles.get_player_highest_role(player)
|
||||
if highest.permission_group then
|
||||
if highest.permission_group[1] then
|
||||
local group = game.permissions.get_group(highest.permission_group[2])
|
||||
local permission_group = highest.permission_group --[[@as [boolean, string] ]]
|
||||
if permission_group[1] then
|
||||
local group = game.permissions.get_group(permission_group[2])
|
||||
if group then
|
||||
Groups.add_to_permission_group_async(group, player)
|
||||
end
|
||||
|
||||
@@ -34,7 +34,7 @@ for _, config_key in ipairs{ "always_protected_names", "always_protected_types",
|
||||
end
|
||||
|
||||
-- Require roles if a permission is assigned in the config
|
||||
local Roles
|
||||
local Roles --- @type table<string, any>
|
||||
if config.ignore_permission then
|
||||
Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ local Gui = require("modules/exp_gui")
|
||||
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
|
||||
|
||||
----- Locals -----
|
||||
local follow_label -- Gui constructor
|
||||
local follow_label --- @type ExpElement Gui constructor
|
||||
local following = {}
|
||||
local spectating = {}
|
||||
local Public = {}
|
||||
|
||||
@@ -14,10 +14,10 @@ local mega = 1000000
|
||||
local vlayer = {}
|
||||
local vlayer_data = {
|
||||
entity_interfaces = {
|
||||
energy = {},
|
||||
circuit = {},
|
||||
storage_input = {},
|
||||
storage_output = {},
|
||||
energy = {}, --- @type LuaEntity[]
|
||||
circuit = {}, --- @type LuaEntity[]
|
||||
storage_input = {}, --- @type LuaEntity[]
|
||||
storage_output = {}, --- @type LuaEntity[]
|
||||
},
|
||||
properties = {
|
||||
total_surface_area = 0,
|
||||
@@ -28,10 +28,10 @@ local vlayer_data = {
|
||||
capacity = 0,
|
||||
},
|
||||
storage = {
|
||||
items = {},
|
||||
power_items = {},
|
||||
items = {}, --- @type table<string, number>
|
||||
power_items = {}, --- @type table<string, { value: number, count: number }>
|
||||
energy = 0,
|
||||
unallocated = {},
|
||||
unallocated = {}, --- @type table<string, number>
|
||||
},
|
||||
surface = table.deep_copy(config.surface),
|
||||
}
|
||||
@@ -45,7 +45,7 @@ for name, properties in pairs(config.allowed_items) do
|
||||
|
||||
if properties.power then
|
||||
vlayer_data.storage.power_items[name] = {
|
||||
value = properties.fuel_value * 1000000,
|
||||
value = assert(properties.fuel_value) * 1000000,
|
||||
count = 0,
|
||||
}
|
||||
end
|
||||
@@ -361,7 +361,7 @@ local function handle_input_interfaces()
|
||||
if not interface.valid then
|
||||
vlayer_data.entity_interfaces.storage_input[index] = nil
|
||||
else
|
||||
local inventory = interface.get_inventory(defines.inventory.chest)
|
||||
local inventory = assert(interface.get_inventory(defines.inventory.chest))
|
||||
|
||||
for _, v in pairs(inventory.get_contents()) do
|
||||
if config.allowed_items[v.name] then
|
||||
@@ -384,8 +384,9 @@ local function handle_input_interfaces()
|
||||
|
||||
if count_deduct and count_add then
|
||||
if config.allowed_items[v.name].modded then
|
||||
local modded_item = assert(config.modded_items[v.name])
|
||||
if config.modded_auto_downgrade then
|
||||
vlayer.insert_item(config.modded_items[v.name].base_game_equivalent, count_add * config.modded_items[v.name].multiplier)
|
||||
vlayer.insert_item(modded_item.base_game_equivalent, count_add * modded_item.multiplier)
|
||||
else
|
||||
vlayer.insert_item(v.name, count_add)
|
||||
end
|
||||
@@ -439,14 +440,14 @@ local function handle_output_interfaces()
|
||||
if not interface.valid then
|
||||
vlayer_data.entity_interfaces.storage_output[index] = nil
|
||||
else
|
||||
local inventory = interface.get_inventory(defines.inventory.chest)
|
||||
local inventory_request_sections = interface.get_logistic_sections().sections
|
||||
local inventory = assert(interface.get_inventory(defines.inventory.chest))
|
||||
local inventory_request_sections = assert(interface.get_logistic_sections()).sections
|
||||
|
||||
for i = 1, #inventory_request_sections do
|
||||
for _, v in pairs(inventory_request_sections[i].filters) do
|
||||
if v.value and config.allowed_items[v.value.name] then
|
||||
local current_amount = inventory.get_item_count(v.value.name)
|
||||
local request_amount = math.min(v.min - current_amount, vlayer_data.storage.items[v.value.name])
|
||||
local request_amount = math.min(assert(v.min) - current_amount, vlayer_data.storage.items[v.value.name])
|
||||
|
||||
if request_amount > 0 and inventory.can_insert{ name = v.value.name, count = request_amount } then
|
||||
local removed_item_count = vlayer.remove_item(v.value.name, request_amount)
|
||||
@@ -582,11 +583,11 @@ local function handle_circuit_interfaces()
|
||||
if not interface.valid then
|
||||
vlayer_data.entity_interfaces.circuit[index] = nil
|
||||
else
|
||||
local circuit_oc = interface.get_or_create_control_behavior()
|
||||
if circuit_oc.sections_count == 0 then
|
||||
circuit_oc.add_section()
|
||||
local control = interface.get_or_create_control_behavior() --[[@as LuaConstantCombinatorControlBehavior]]
|
||||
if control.sections_count == 0 then
|
||||
control.add_section()
|
||||
end
|
||||
circuit_oc = circuit_oc.sections[1]
|
||||
local circuit_oc = assert(control.sections[1])
|
||||
local signal_index = 1
|
||||
local circuit = vlayer.get_circuits()
|
||||
|
||||
@@ -617,7 +618,7 @@ local function handle_circuit_interfaces()
|
||||
|
||||
-- Clear remaining signals to prevent outdated values being present (caused by count > 0 check)
|
||||
for clear_index = signal_index, #circuit do
|
||||
if not circuit_oc.get_slot(clear_index).signal then
|
||||
if not circuit_oc.get_slot(clear_index).value then
|
||||
break -- There are no more signals to clear
|
||||
end
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ function Warnings.add_warning(player, by_player_name, reason)
|
||||
|
||||
reason = reason or "None given."
|
||||
|
||||
local warning_count
|
||||
local warning_count --- @type number
|
||||
PlayerWarnings:update(player.name, function(_, warnings)
|
||||
local warning = {
|
||||
by_player_name = by_player_name,
|
||||
|
||||
@@ -18,7 +18,7 @@ ToolbarState:on_load(function(player_name, value)
|
||||
|
||||
local decompressed = helpers.json_to_table(assert(helpers.decode_string(value), "Failed String Decode"))
|
||||
local player = assert(game.get_player(player_name))
|
||||
Gui.toolbar.set_state(player, decompressed --[[ @as Gui.ToolbarState ]])
|
||||
Gui.toolbar.set_state(player, decompressed --[[@as Gui.ToolbarState]])
|
||||
|
||||
return nil -- We don't save the state, use Gui.toolbar.get_state
|
||||
end)
|
||||
|
||||
@@ -126,19 +126,19 @@ lib.collect_loginet = function()
|
||||
end
|
||||
|
||||
if config.modules.logistorage then
|
||||
for name, v in pairs(network.get_contents()) do
|
||||
stats.items[name] = (stats.items[name] or 0) + v
|
||||
for _, item in pairs(network.get_contents()) do
|
||||
stats.items[item.name] = (stats.items[item.name] or 0) + item.count
|
||||
end
|
||||
|
||||
-- pickups and deliveries of items
|
||||
for _, point_list in pairs{ network.provider_points, network.requester_points, network.storage_points } do
|
||||
for _, point in pairs(point_list) do
|
||||
for name, qty in pairs(point.targeted_items_pickup) do
|
||||
stats.pickups[name] = (stats.pickups[name] or 0) + qty
|
||||
for _, item in pairs(point.targeted_items_pickup) do
|
||||
stats.pickups[item.name] = (stats.pickups[item.name] or 0) + item.count
|
||||
end
|
||||
|
||||
for name, qty in pairs(point.targeted_items_deliver) do
|
||||
stats.deliveries[name] = (stats.deliveries[name] or 0) + qty
|
||||
for _, item in pairs(point.targeted_items_deliver) do
|
||||
stats.deliveries[item.name] = (stats.deliveries[item.name] or 0) + item.count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,6 +2,6 @@ local Gui = require("modules/exp_gui")
|
||||
local Roles = require("modules.exp_legacy.expcore.roles")
|
||||
local Event = require("modules/exp_legacy/utils/event")
|
||||
|
||||
--- @diagnostic disable invisible
|
||||
--- @diagnostic disable: access-invisible
|
||||
Event.add(Roles.events.on_role_assigned, Gui._ensure_consistency)
|
||||
Event.add(Roles.events.on_role_unassigned, Gui._ensure_consistency)
|
||||
|
||||
@@ -22,9 +22,9 @@ local function aabb_align_expand(aabb)
|
||||
}
|
||||
end
|
||||
|
||||
local vlayer_container
|
||||
local vlayer_gui_control_type
|
||||
local vlayer_gui_control_list
|
||||
local vlayer_container --- @type ExpElement
|
||||
local vlayer_gui_control_type --- @type ExpElement
|
||||
local vlayer_gui_control_list --- @type ExpElement
|
||||
|
||||
local vlayer_control_type_list = {
|
||||
[1] = "energy",
|
||||
@@ -87,10 +87,10 @@ SelectArea:on_selection(function(event)
|
||||
local container = Gui.get_left_element(vlayer_container, player)
|
||||
local disp = container.frame["vlayer_st_2"].disp.table
|
||||
local target = vlayer_control_type_list[disp[vlayer_gui_control_type.name].selected_index]
|
||||
local entities
|
||||
local entities --- @type LuaEntity[]
|
||||
|
||||
if config.power_on_space and event.surface and event.surface.platform and target == "energy" then
|
||||
if player.force.technologies[config.power_on_space_research.name].level >= config.power_on_space_research.level then
|
||||
if (player.force --[[@as LuaForce]]).technologies[config.power_on_space_research.name].level >= config.power_on_space_research.level then
|
||||
entities = event.surface.find_entities_filtered{ area = area, name = "constant-combinator", force = player.force }
|
||||
else
|
||||
player.print{ "vlayer.power-on-space-research", config.power_on_space_research.name, config.power_on_space_research.level }
|
||||
@@ -116,7 +116,7 @@ SelectArea:on_selection(function(event)
|
||||
local e_pos = { x = string.format("%.1f", e.position.x), y = string.format("%.1f", e.position.y) }
|
||||
local e_circ = nil -- e.get_wire_connectors{ or_create = false }
|
||||
|
||||
if e.name and e.name == "steel-chest" and (not e.get_inventory(defines.inventory.chest).is_empty()) then
|
||||
if e.name and e.name == "steel-chest" and (not assert(e.get_inventory(defines.inventory.chest)).is_empty()) then
|
||||
player.print{ "vlayer.steel-chest-empty" }
|
||||
return
|
||||
end
|
||||
@@ -325,7 +325,9 @@ local function vlayer_gui_list_refresh(player)
|
||||
local interface = vlayer.get_interfaces()[vlayer_control_type_list[target]]
|
||||
|
||||
for i = 1, vlayer.get_interface_counts()[vlayer_control_type_list[target]], 1 do
|
||||
table.insert(full_list, i .. " X " .. interface[i].position.x .. " Y " .. interface[i].position.y)
|
||||
local entity = assert(interface[i])
|
||||
local entity_position = entity.position
|
||||
table.insert(full_list, i .. " X " .. entity_position.x .. " Y " .. entity_position.y)
|
||||
end
|
||||
|
||||
disp[vlayer_gui_control_list.name].items = full_list
|
||||
@@ -379,14 +381,13 @@ local vlayer_gui_control_see = Gui.define("vlayer_gui_control_see")
|
||||
}:style{
|
||||
width = 200,
|
||||
}:on_click(function(def, player, element, event)
|
||||
local target = element.parent[vlayer_gui_control_type.name].selected_index
|
||||
local n = element.parent[vlayer_gui_control_list.name].selected_index
|
||||
local target = assert(element.parent)[vlayer_gui_control_type.name].selected_index
|
||||
local n = assert(element.parent)[vlayer_gui_control_list.name].selected_index
|
||||
|
||||
if target and vlayer_control_type_list[target] and n > 0 then
|
||||
local i = vlayer.get_interfaces()
|
||||
local entity = i[vlayer_control_type_list[target]][n]
|
||||
if entity and entity.valid then
|
||||
local player = Gui.get_player(event)
|
||||
player.set_controller{ type = defines.controllers.remote, position = entity.position, surface = entity.surface }
|
||||
player.print{ "vlayer.result-interface-location", { "vlayer.control-type-" .. vlayer_control_type_list[target]:gsub("_", "-") }, pos_to_gps_string(entity.position, entity.surface.name) }
|
||||
end
|
||||
@@ -423,14 +424,15 @@ local vlayer_gui_control_remove = Gui.define("vlayer_gui_control_remove")
|
||||
}:style{
|
||||
width = 200,
|
||||
}:on_click(function(def, player, element)
|
||||
local target = element.parent[vlayer_gui_control_type.name].selected_index
|
||||
local n = element.parent[vlayer_gui_control_list.name].selected_index
|
||||
local target = assert(element.parent)[vlayer_gui_control_type.name].selected_index
|
||||
local n = assert(element.parent)[vlayer_gui_control_list.name].selected_index
|
||||
|
||||
if target and vlayer_control_type_list[target] and n > 0 then
|
||||
local i = vlayer.get_interfaces()
|
||||
|
||||
if i and i[vlayer_control_type_list[target]] then
|
||||
local interface_type, interface_surface, interface_position = vlayer.remove_interface(i[vlayer_control_type_list[target]][n].surface, i[vlayer_control_type_list[target]][n].position)
|
||||
local entity = assert(i[vlayer_control_type_list[target]][n])
|
||||
local interface_type, interface_surface, interface_position = vlayer.remove_interface(entity.surface, entity.position)
|
||||
|
||||
if interface_type then
|
||||
game.print{ "vlayer.interface-result", player.name, pos_to_gps_string(interface_position, interface_surface.name), { "vlayer.result-remove" }, { "vlayer.control-type-" .. interface_type } }
|
||||
|
||||
@@ -180,7 +180,7 @@ local warp_icon_button = Gui.define("warp_icon_button")
|
||||
:style(Styles.sprite32)
|
||||
:on_click(function(def, player, element)
|
||||
if element.type == "choose-elem-button" then return end
|
||||
local warp_id = element.parent.caption
|
||||
local warp_id = assert(element.parent).caption
|
||||
Warps.teleport_player(warp_id, player)
|
||||
|
||||
-- Reset the warp cooldown if the player does not have unlimited warps
|
||||
@@ -226,7 +226,7 @@ local warp_label = Gui.define("warp_label")
|
||||
horizontally_stretchable = true,
|
||||
}
|
||||
:on_click(function(def, player, element)
|
||||
local warp_id = element.parent.caption
|
||||
local warp_id = assert(element.parent).caption
|
||||
local warp = Warps.get_warp(warp_id)
|
||||
player.set_controller{ type = defines.controllers.remote, position = warp.position, surface = warp.surface }
|
||||
end)
|
||||
@@ -271,9 +271,9 @@ local warp_textfield = Gui.define("warp_textfield")
|
||||
right_margin = 2,
|
||||
}
|
||||
:on_confirmed(function(def, player, element)
|
||||
local warp_id = element.parent.caption
|
||||
local warp_id = assert(element.parent).caption
|
||||
local warp_name = element.text
|
||||
local warp_icon = element.parent.parent["icon-" .. warp_id][warp_icon_editing.name].elem_value --[[ @as SignalID ]]
|
||||
local warp_icon = assert(element.parent).parent["icon-" .. warp_id][warp_icon_editing.name].elem_value --[[@as SignalID]]
|
||||
if warp_icon.type == nil then warp_icon.type = "item" end
|
||||
Warps.set_editing(warp_id, player.name)
|
||||
Warps.update_warp(warp_id, warp_name, warp_icon, player.name)
|
||||
@@ -291,9 +291,13 @@ local confirm_edit_button = Gui.define("confirm_edit_button")
|
||||
}
|
||||
:style(Styles.sprite22)
|
||||
:on_click(function(def, player, element)
|
||||
local warp_id = element.parent.caption
|
||||
local warp_name = element.parent.parent["name-" .. warp_id][warp_textfield.name].text
|
||||
local warp_icon = element.parent.parent["icon-" .. warp_id][warp_icon_editing.name].elem_value --[[ @as SignalID ]]
|
||||
local parent = assert(element.parent)
|
||||
local grandparent = assert(parent.parent)
|
||||
local warp_id = parent.caption --[[@as string]]
|
||||
local name_flow = grandparent["name-" .. warp_id]
|
||||
local icon_flow = grandparent["icon-" .. warp_id]
|
||||
local warp_name = name_flow[warp_textfield.name].text
|
||||
local warp_icon = icon_flow[warp_icon_editing.name].elem_value --[[@as SignalID]]
|
||||
if warp_icon.type == nil then warp_icon.type = "item" end
|
||||
Warps.set_editing(warp_id, player.name)
|
||||
Warps.update_warp(warp_id, warp_name, warp_icon, player.name)
|
||||
@@ -311,7 +315,7 @@ local cancel_edit_button = Gui.define("cancel_edit_button")
|
||||
}
|
||||
:style(Styles.sprite22)
|
||||
:on_click(function(def, player, element)
|
||||
local warp_id = element.parent.caption
|
||||
local warp_id = assert(element.parent).caption
|
||||
-- Check if this is the first edit, if so remove the warp.
|
||||
local warp = Warps.get_warp(warp_id)
|
||||
if warp.updates == 1 then
|
||||
@@ -333,7 +337,7 @@ local remove_warp_button = Gui.define("remove_warp_button")
|
||||
}
|
||||
:style(Styles.sprite22)
|
||||
:on_click(function(def, player, element)
|
||||
local warp_id = element.parent.caption
|
||||
local warp_id = assert(element.parent).caption
|
||||
Warps.remove_warp(warp_id)
|
||||
end)
|
||||
|
||||
@@ -349,7 +353,7 @@ local edit_warp_button = Gui.define("edit_warp_button")
|
||||
}
|
||||
:style(Styles.sprite22)
|
||||
:on_click(function(def, player, element)
|
||||
local warp_id = element.parent.caption
|
||||
local warp_id = assert(element.parent).caption
|
||||
Warps.set_editing(warp_id, player.name, true)
|
||||
end)
|
||||
|
||||
@@ -429,8 +433,8 @@ local function update_warp_elements(element, warp, warp_player_is_on, on_cooldow
|
||||
-- Check if button element is valid
|
||||
if not element or not element.valid then return end
|
||||
|
||||
local label_style = element.parent.parent["name-" .. warp.warp_id][warp_label.name].style
|
||||
local warp_status_element = element.parent.parent["name-" .. warp.warp_id][warp_status.name]
|
||||
local label_style = assert(element.parent).parent["name-" .. warp.warp_id][warp_label.name].style
|
||||
local warp_status_element = assert(element.parent).parent["name-" .. warp.warp_id][warp_status.name]
|
||||
|
||||
-- If player is not on a warp
|
||||
if not warp_player_is_on then
|
||||
@@ -669,7 +673,7 @@ warp_list_container = Gui.define("warp_list_container")
|
||||
-- Draw the scroll table for the warps
|
||||
local scroll_table = Gui.elements.scroll_table(container, 250, 3, "scroll")
|
||||
-- Set the scroll panel to always show the scrollbar (not doing this will result in a changing gui size)
|
||||
scroll_table.parent.vertical_scroll_policy = "always"
|
||||
assert(scroll_table.parent).vertical_scroll_policy = "always"
|
||||
|
||||
-- Change the style of the scroll table
|
||||
local scroll_table_style = scroll_table.style
|
||||
@@ -778,7 +782,7 @@ Event.on_nth_tick(math.floor(60 / config.update_smoothing), function()
|
||||
end
|
||||
|
||||
-- Check if the force has any warps
|
||||
local closest_warp = nil
|
||||
local closest_warp = nil --- @type { warp_id: string, name: string }?
|
||||
local closest_distance = nil
|
||||
if #warp_ids > 0 then
|
||||
local surface = player.surface
|
||||
@@ -838,7 +842,7 @@ end)
|
||||
Event.add(defines.events.on_player_created, function(event)
|
||||
-- If the force has no spawn then make a spawn warp
|
||||
local player = game.players[event.player_index]
|
||||
local force = player.force
|
||||
local force = player.force --[[@as LuaForce]]
|
||||
local spawn_id = Warps.get_spawn_warp_id(force.name)
|
||||
if not spawn_id then
|
||||
local spawn_position = force.get_spawn_position(player.surface)
|
||||
@@ -870,7 +874,7 @@ local function role_update_event(event)
|
||||
-- Check if user has permission to add warps
|
||||
local allow_add_warp = check_player_permissions(player, "allow_add_warp")
|
||||
-- Update container size depending on whether the player is allowed to add warps
|
||||
frame.parent.style.width = allow_add_warp and 268 or 220
|
||||
assert(frame.parent).style.width = allow_add_warp and 268 or 220
|
||||
|
||||
-- Update the warps, in case the user can now edit them
|
||||
local scroll_table = frame.scroll.table
|
||||
|
||||
@@ -12,7 +12,7 @@ made with `assign_player_local`.
|
||||
]]
|
||||
|
||||
local clusterio_api = require("modules/clusterio/api")
|
||||
local compat = require("modules/clusterio/compat")
|
||||
local compat = require("modules/clusterio/compat") --[[@as LibCompat]]
|
||||
local Async = require("modules/exp_util/async")
|
||||
|
||||
--- @class ExpRoles
|
||||
@@ -284,7 +284,7 @@ local server_role = setmetatable({
|
||||
--- @param player LuaPlayer | string | nil
|
||||
--- @return ExpRoles.Role[]
|
||||
function ExpRoles.get_player_roles(player)
|
||||
local player_name = type(player) == "table" and player.name or player --[[ @as string? ]]
|
||||
local player_name = type(player) == "table" and player.name or player --[[@as string?]]
|
||||
-- The server is not a player and is allowed to do anything
|
||||
if player_name == nil then return { server_role } end
|
||||
|
||||
@@ -399,7 +399,7 @@ end
|
||||
--- @param self ExpRoles.Role
|
||||
--- @param action string
|
||||
--- @return boolean
|
||||
function Role:is_allowed(action)
|
||||
function Role.is_allowed(self, action)
|
||||
local allowed = self.allowed_actions
|
||||
return allowed["core.admin"] or allowed[permission_from_action(action)] or false
|
||||
end
|
||||
@@ -408,7 +408,7 @@ end
|
||||
--- @param self ExpRoles.Role
|
||||
--- @param name string
|
||||
--- @return boolean
|
||||
function Role:has_flag(name)
|
||||
function Role.has_flag(self, name)
|
||||
return self.allowed_actions[permission_from_flag(name)] or false
|
||||
end
|
||||
|
||||
@@ -416,7 +416,7 @@ end
|
||||
--- @param self ExpRoles.Role
|
||||
--- @param online boolean? When given, filter by connected state
|
||||
--- @return LuaPlayer[]
|
||||
function Role:get_players(online)
|
||||
function Role.get_players(self, online)
|
||||
local players = {}
|
||||
for player_name, role_names in pairs(ExpRoles.config.players) do
|
||||
for _, role_name in pairs(role_names) do
|
||||
@@ -437,7 +437,7 @@ end
|
||||
--- @param self ExpRoles.Role
|
||||
--- @param message LocalisedString
|
||||
--- @return number # Number of players the message was sent to
|
||||
function Role:print(message)
|
||||
function Role.print(self, message)
|
||||
local players = self:get_players(true)
|
||||
for _, player in pairs(players) do
|
||||
player.print(message)
|
||||
@@ -678,7 +678,7 @@ end
|
||||
--- @param silent boolean?
|
||||
--- @param sync boolean
|
||||
local function change_player_roles(player, roles, change_type, by_player_name, silent, sync)
|
||||
local player_name = type(player) == "table" and player.name or player --[[ @as string? ]]
|
||||
local player_name = type(player) == "table" and player.name or player --[[@as string?]]
|
||||
if not player_name then return end
|
||||
|
||||
local role_objects = resolve_roles(roles)
|
||||
|
||||
@@ -9,7 +9,10 @@ had, and event_handler expects `events` to be the handlers to register.
|
||||
local clusterio_api = require("modules/clusterio/api")
|
||||
local ExpRoles = require("modules/exp_roles/control")
|
||||
|
||||
return {
|
||||
--- @class ExpRoles.EventHandlers
|
||||
--- @field on_load fun()
|
||||
--- @field events table<defines.events, fun(event: EventData)>
|
||||
local handlers = {
|
||||
on_load = ExpRoles.on_load,
|
||||
events = {
|
||||
[clusterio_api.events.on_server_startup] = ExpRoles.on_server_startup,
|
||||
@@ -17,3 +20,5 @@ return {
|
||||
[defines.events.on_player_joined_game] = ExpRoles.on_player_joined_game,
|
||||
},
|
||||
}
|
||||
|
||||
return handlers
|
||||
|
||||
@@ -4,7 +4,7 @@ However, sometimes you need globals, for example to access functions within rcon
|
||||
Therefore, we advise that this should be the only file in your module to expose globals
|
||||
]]
|
||||
|
||||
--- @diagnostic disable: global-element
|
||||
--- @diagnostic disable: global-in-non-module
|
||||
|
||||
-- Access using `/sc exp_roles.foo()`
|
||||
exp_roles = require("modules/exp_roles/control")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@ local valid, invalid = Commands.status.success, Commands.status.invalid_input
|
||||
local Roles = require("modules.exp_legacy.expcore.roles")
|
||||
local highest_role = Roles.get_player_highest_role
|
||||
|
||||
local types = {} --- @class Commands.types
|
||||
local types = {} --- @class (partial) Commands.types
|
||||
|
||||
--- A role defined by exp roles
|
||||
types.role = add("role", Commands.types.key_of(Roles.config.roles))
|
||||
|
||||
@@ -15,11 +15,11 @@ local abs = math.abs
|
||||
local commands = {}
|
||||
|
||||
--- @param player LuaPlayer
|
||||
--- @param area BoundingBox
|
||||
--- @param area BoundingBox.struct
|
||||
--- @return boolean
|
||||
local function location_break(player, area)
|
||||
local surface = player.surface -- Allow remote view
|
||||
local is_charted = player.force.is_chunk_charted
|
||||
local is_charted = (player.force --[[@as LuaForce]]).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
|
||||
@@ -43,7 +43,7 @@ commands.artillery = Commands.new("artillery", { "exp-commands_artillery.descrip
|
||||
end
|
||||
SelectArea:start(player)
|
||||
return Commands.status.success{ "exp-commands_artillery.enter" }
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- when an area is selected to add protection to the area
|
||||
SelectArea:on_selection(function(event)
|
||||
@@ -63,13 +63,14 @@ SelectArea:on_selection(function(event)
|
||||
}
|
||||
|
||||
local count = 0
|
||||
local hits = {} --- @type MapPosition[]
|
||||
local hits = {} --- @type MapPosition.struct[]
|
||||
for _, entity in ipairs(entities) do
|
||||
local skip = false
|
||||
|
||||
local entity_position = entity.position
|
||||
for _, pos in ipairs(hits) do
|
||||
local x = abs(entity.position.x - pos.x)
|
||||
local y = abs(entity.position.y - pos.y)
|
||||
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
|
||||
|
||||
@@ -41,7 +41,7 @@ local function get_server_id(server)
|
||||
elseif status == "Offline" then
|
||||
return false, { "exp-commands_connect.offline", server_details.name }
|
||||
end
|
||||
return true, server_id
|
||||
return true, server_id --[[@as string]]
|
||||
elseif server_count_before > 0 then
|
||||
return false, { "exp-commands_connect.wrong-version", concat(server_names_before, ", ") }
|
||||
else
|
||||
|
||||
@@ -25,7 +25,7 @@ Commands.new("kill", { "exp-commands_kill.description" })
|
||||
if script.active_mods["space-age"] then
|
||||
other_player.surface.create_entity{ name = "lightning", position = { other_player.position.x, other_player.position.y - 16 }, target = other_player.character }
|
||||
end
|
||||
other_player.character.die()
|
||||
assert(other_player.character).die()
|
||||
else
|
||||
return Commands.status.unauthorised{ "exp-commands_kill.lower-role" }
|
||||
end
|
||||
|
||||
@@ -22,7 +22,7 @@ commands.lawnmower = Commands.new("lawnmower", { "exp-commands_lawnmower.descrip
|
||||
|
||||
SelectArea:start(player)
|
||||
return Commands.status.success{ "exp-commands_lawnmower.enter" }
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- When an area is selected to be handled
|
||||
SelectArea:on_selection(function(event)
|
||||
|
||||
@@ -37,7 +37,7 @@ end
|
||||
|
||||
--- Get the key used in protected_areas
|
||||
--- TODO expose this from EntityProtection
|
||||
--- @param area BoundingBox
|
||||
--- @param area BoundingBox.struct
|
||||
--- @return string
|
||||
local function get_area_key(area)
|
||||
return format_string("%i,%i", floor(area.left_top.x), floor(area.left_top.y))
|
||||
@@ -49,13 +49,15 @@ end
|
||||
local function show_protected_entity(player, entity)
|
||||
local key = get_entity_key(entity)
|
||||
if renders[player.index][key] then return end
|
||||
local rb = entity.selection_box.right_bottom
|
||||
local selection_box = entity.selection_box
|
||||
local rb = selection_box.right_bottom
|
||||
local position = entity.position
|
||||
renders[player.index][key] = rendering.draw_sprite{
|
||||
sprite = "utility/notification",
|
||||
target = entity,
|
||||
target_offset = {
|
||||
(rb.x - entity.position.x) * 0.75,
|
||||
(rb.y - entity.position.y) * 0.75,
|
||||
(rb.x - position.x) * 0.75,
|
||||
(rb.y - position.y) * 0.75,
|
||||
},
|
||||
x_scale = 2,
|
||||
y_scale = 2,
|
||||
@@ -67,7 +69,7 @@ end
|
||||
--- Show a protected area to a player
|
||||
--- @param player LuaPlayer
|
||||
--- @param surface LuaSurface
|
||||
--- @param area BoundingBox
|
||||
--- @param area BoundingBox.struct
|
||||
local function show_protected_area(player, surface, area)
|
||||
local key = get_area_key(area)
|
||||
if renders[player.index][key] then return end
|
||||
|
||||
@@ -7,7 +7,7 @@ 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
|
||||
local map_tags = {} --- @type table<string, boolean> Stores all protected map tags
|
||||
|
||||
Storage.register({
|
||||
active_players = active_players,
|
||||
|
||||
@@ -6,6 +6,12 @@ local Commands = require("modules/exp_commands")
|
||||
local format_player_name = Commands.format_player_name_locale
|
||||
local format_text = Commands.format_rich_text_color
|
||||
|
||||
--- A colour with every channel set, Color.struct leaves them optional
|
||||
--- @class ExpCommands_Rainbow.Color
|
||||
--- @field r number
|
||||
--- @field g number
|
||||
--- @field b number
|
||||
|
||||
--- Wraps one component into the next
|
||||
--- @param c1 number
|
||||
--- @param c2 number
|
||||
@@ -21,8 +27,8 @@ local function step_component(c1, c2)
|
||||
end
|
||||
|
||||
--- Wraps all components of a colour ensuring it remains valid
|
||||
--- @param color Color
|
||||
--- @return Color
|
||||
--- @param color ExpCommands_Rainbow.Color
|
||||
--- @return ExpCommands_Rainbow.Color
|
||||
local function step_color(color)
|
||||
color.r, color.g = step_component(color.r, color.g)
|
||||
color.g, color.b = step_component(color.g, color.b)
|
||||
@@ -32,9 +38,9 @@ local function step_color(color)
|
||||
end
|
||||
|
||||
--- Get the next colour in the rainbow by the given step
|
||||
--- @param color Color
|
||||
--- @param color ExpCommands_Rainbow.Color
|
||||
--- @param step number
|
||||
--- @return Color
|
||||
--- @return ExpCommands_Rainbow.Color
|
||||
local function next_color(color, step)
|
||||
step = step or 0.1
|
||||
local new_color = { r = 0, g = 0, b = 0 }
|
||||
|
||||
@@ -29,7 +29,7 @@ Commands.new("ratio", { "exp-commands_ratio.description" })
|
||||
|
||||
local amount_of_machines = 1
|
||||
if items_per_second then
|
||||
amount_of_machines = math.ceil(products[1].amount * crafts_per_second)
|
||||
amount_of_machines = math.ceil(assert(assert(products[1]).amount) * crafts_per_second)
|
||||
end
|
||||
|
||||
for _, ingredient in ipairs(ingredients) do
|
||||
@@ -43,7 +43,7 @@ Commands.new("ratio", { "exp-commands_ratio.description" })
|
||||
for i, product in ipairs(products) do
|
||||
Commands.print{
|
||||
product.type == "item" and "exp-commands_ratio.item-out" or "exp-commands_ratio.fluid-out",
|
||||
math.round(product.amount * crafts_per_second, 3),
|
||||
math.round(assert(product.amount) * crafts_per_second, 3),
|
||||
product.name
|
||||
}
|
||||
end
|
||||
|
||||
@@ -11,7 +11,10 @@ local player_has_flag = Roles.player_has_flag
|
||||
|
||||
local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports
|
||||
|
||||
--- @type Commands.InputParser
|
||||
--- @param input string
|
||||
--- @param player LuaPlayer
|
||||
--- @return Commands.Status
|
||||
--- @return LuaPlayer | LocalisedString
|
||||
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
|
||||
@@ -40,11 +43,11 @@ Commands.new("create-report", { "exp-commands_reports.description-create" })
|
||||
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)
|
||||
for _, connected_player in ipairs(game.connected_players) do
|
||||
if connected_player.admin then
|
||||
connected_player.print(admin_message)
|
||||
else
|
||||
player.print(user_message)
|
||||
connected_player.print(user_message)
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
@@ -42,7 +42,7 @@ Commands.new("get-roles", { "exp-commands_roles.description-get" })
|
||||
--- @cast other_player LuaPlayer?
|
||||
local roles = get_roles_ordered()
|
||||
local roles_formatted = { "" } --- @type LocalisedString
|
||||
local response = { "exp-commands_roles.list-roles", roles_formatted }
|
||||
local response = { "exp-commands_roles.list-roles", roles_formatted } --[[@as LocalisedString]]
|
||||
if other_player then
|
||||
roles = get_player_roles(other_player)
|
||||
response[1] = "exp-commands_roles.list-player"
|
||||
@@ -55,8 +55,7 @@ Commands.new("get-roles", { "exp-commands_roles.description-get" })
|
||||
end
|
||||
|
||||
local last = #roles_formatted
|
||||
--- @diagnostic disable-next-line nil-check
|
||||
roles_formatted[last] = roles_formatted[last][2]
|
||||
roles_formatted[last] = assert(roles_formatted[last])[2]
|
||||
|
||||
return Commands.status.success(response)
|
||||
end)
|
||||
|
||||
@@ -10,7 +10,10 @@ 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
|
||||
--- @param input string
|
||||
--- @param player LuaPlayer
|
||||
--- @return Commands.Status
|
||||
--- @return LuaItemPrototype | LocalisedString
|
||||
local function parse_item(input, player)
|
||||
-- First Case - internal name is given
|
||||
-- Second Case - rich text is given
|
||||
@@ -88,7 +91,7 @@ local function sort_results(results, func)
|
||||
end
|
||||
end
|
||||
|
||||
return sorted
|
||||
return sorted --[[@as SearchResult[] ]]
|
||||
end
|
||||
|
||||
local display_players_time_format = ExpUtil.format_time_factory_locale{ format = "short", hours = true, minutes = true }
|
||||
@@ -146,7 +149,8 @@ Commands.new("search-online", { "exp-commands_search.description-online" })
|
||||
end)
|
||||
|
||||
--- Return the amount of an item a player has
|
||||
--- @type SortFunction
|
||||
--- @param data SearchResult
|
||||
--- @return number
|
||||
local function sort_by_count(data)
|
||||
return data.count
|
||||
end
|
||||
|
||||
@@ -69,7 +69,7 @@ commands.clear_blueprints = Commands.new("clear-blueprints", { "exp-commands_sur
|
||||
|
||||
SelectArea:start(player)
|
||||
return Commands.status.success{ "exp-commands_surface.enter" }
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- When an area is selected
|
||||
SelectArea:on_selection(function(event)
|
||||
|
||||
@@ -34,7 +34,7 @@ commands.teleport = Commands.new("teleport", { "exp-commands_teleport.descriptio
|
||||
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) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Teleports a player to you.
|
||||
--- @class ExpCommands_Teleport.commands.bring: ExpCommand
|
||||
@@ -49,7 +49,7 @@ commands.bring = Commands.new("bring", { "exp-commands_teleport.description-brin
|
||||
elseif not teleport_player(other_player, player.physical_surface, player.physical_position) then
|
||||
return Commands.status.error{ "exp-commands_teleport.unavailable" }
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Teleports you to a player.
|
||||
--- @class ExpCommands_Teleport.commands.goto: ExpCommand
|
||||
@@ -64,7 +64,7 @@ commands["goto"] = Commands.new("goto", { "exp-commands_teleport.description-got
|
||||
elseif not teleport_player(player, other_player.physical_surface, other_player.physical_position) then
|
||||
return Commands.status.error{ "exp-commands_teleport.unavailable" }
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Teleport to spawn
|
||||
--- @class ExpCommands_Teleport.commands.spawn: ExpCommand
|
||||
@@ -92,7 +92,7 @@ commands.spawn = Commands.new("spawn", { "exp-commands_teleport.description-spaw
|
||||
else
|
||||
return Commands.status.unauthorised()
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
return {
|
||||
commands = commands,
|
||||
|
||||
@@ -10,7 +10,7 @@ local format_number = require("util").format_number
|
||||
local commands = {}
|
||||
|
||||
--- Set all trains to automatic
|
||||
--- @class ExpCommand_Artillery.commands.artillery: ExpCommand
|
||||
--- @class ExpCommand_Trains.commands.set_trains_to_automatic: ExpCommand
|
||||
--- @overload fun(player: LuaPlayer, surface: LuaSurface?, force: LuaForce?)
|
||||
commands.set_trains_to_automatic = Commands.new("set-trains-to-automatic", { "exp-commands_trains.description" })
|
||||
:optional("surface", { "exp-commands_trains.arg-surface" }, Commands.types.surface)
|
||||
@@ -32,7 +32,7 @@ commands.set_trains_to_automatic = Commands.new("set-trains-to-automatic", { "ex
|
||||
end
|
||||
|
||||
game.print{ "exp-commands_trains.response", format_player_name(player), format_number(#trains, false) }
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
return {
|
||||
commands = commands,
|
||||
|
||||
@@ -35,7 +35,7 @@ Commands.new("get-warnings", { "exp-commands_warnings.description-get" })
|
||||
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 }
|
||||
Commands.print{ "exp-commands_warnings.player-title", other_player_name, #warnings, #script_warnings, config.script_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 }
|
||||
@@ -47,12 +47,12 @@ Commands.new("get-warnings", { "exp-commands_warnings.description-get" })
|
||||
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 }
|
||||
Commands.print{ "exp-commands_warnings.list-element", player_name_formatted, #player_warnings, script_warning_count, config.script_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 }
|
||||
Commands.print{ "exp-commands_warnings.list-element", player_name_formatted, 0, #player_warnings, config.script_warning_limit }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,7 +36,7 @@ commands.waterfill = Commands.new("waterfill", { "exp-commands_waterfill.descrip
|
||||
SelectArea:start(player)
|
||||
return Commands.status.success{ "exp-commands_waterfill.enter" }
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- When an area is selected to be converted to water
|
||||
SelectArea:on_selection(function(event)
|
||||
@@ -70,7 +70,7 @@ SelectArea:on_selection(function(event)
|
||||
if #chests > 0 then
|
||||
for _, chest in pairs(chests) do
|
||||
tile_count = tile_count + 1
|
||||
if chest.get_inventory(defines.inventory.chest).is_empty() and tile_count <= item_count_total then
|
||||
if assert(chest.get_inventory(defines.inventory.chest)).is_empty() and tile_count <= item_count_total then
|
||||
tiles_to_make[tile_count] = { name = tile_to_apply, position = { chest.position.x, chest.position.y } }
|
||||
chest.destroy()
|
||||
else
|
||||
|
||||
@@ -8,7 +8,7 @@ local floor = math.floor
|
||||
--- Give a player their starting items
|
||||
--- @param player LuaPlayer
|
||||
local function give_starting_items(player)
|
||||
local get_prod_stats = player.force.get_item_production_statistics(player.physical_surface)
|
||||
local get_prod_stats = (player.force --[[@as LuaForce]]).get_item_production_statistics(player.physical_surface)
|
||||
local get_input_count = get_prod_stats.get_input_count
|
||||
local insert_param = { name = "", count = 0 }
|
||||
local insert = player.insert
|
||||
|
||||
@@ -26,11 +26,12 @@ local function on_entity_damaged(event)
|
||||
|
||||
-- Outputs the message as floating text
|
||||
if message then
|
||||
local entity_position = entity.position
|
||||
local entity_radius = max(1, entity.get_radius())
|
||||
local offset = (random() - 0.5) * entity_radius * config.damage_location_variance
|
||||
local position = { x = entity.position.x + offset, y = entity.position.y - entity_radius }
|
||||
local position = { x = entity_position.x + offset, y = entity_position.y - entity_radius }
|
||||
|
||||
local health_percentage = entity.get_health_ratio()
|
||||
local health_percentage = assert(entity.get_health_ratio())
|
||||
local color = { r = 1 - health_percentage, g = health_percentage, b = 0 }
|
||||
|
||||
FlyingText.create{
|
||||
|
||||
@@ -31,7 +31,7 @@ local function create_map_tag(corpse_data)
|
||||
message = message .. " at " .. time
|
||||
end
|
||||
|
||||
corpse_data.tag = player.force.add_chart_tag(corpse_data.corpse.surface, {
|
||||
corpse_data.tag = (player.force --[[@as LuaForce]]).add_chart_tag(corpse_data.corpse.surface, {
|
||||
position = corpse_data.corpse.position,
|
||||
icon = config.map_icon,
|
||||
text = message,
|
||||
|
||||
@@ -42,7 +42,7 @@ local function format_position(pos)
|
||||
end
|
||||
|
||||
--- Convert an area to a string
|
||||
--- @param area BoundingBox
|
||||
--- @param area BoundingBox.struct
|
||||
--- @return string
|
||||
local function format_area(area)
|
||||
return format_string("%.1f,%.1f,%.1f,%.1f", area.left_top.x, area.left_top.y, area.right_bottom.x, area.right_bottom.y)
|
||||
@@ -137,7 +137,8 @@ local function on_player_ammo_inventory_changed(event)
|
||||
if not player or not player.character then return end
|
||||
|
||||
local character_ammo = assert(player.get_inventory(defines.inventory.character_ammo))
|
||||
local item = character_ammo[player.character.selected_gun_index]
|
||||
local gun_index = player.character.selected_gun_index --[[@as uint]]
|
||||
local item = character_ammo[gun_index]
|
||||
if not item or not item.valid or not item.valid_for_read then
|
||||
return
|
||||
end
|
||||
|
||||
@@ -16,10 +16,9 @@ end
|
||||
|
||||
--- Replace a tile with the next tile in the degrade chain
|
||||
--- @param surface LuaSurface
|
||||
--- @param position MapPosition
|
||||
--- @param position MapPosition.struct
|
||||
local function degrade_tile(surface, position)
|
||||
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761
|
||||
local tile = surface.get_tile(position)
|
||||
local tile = surface.get_tile(position.x, position.y)
|
||||
local tile_name = tile.name
|
||||
local degrade_tile_name = config.degrade_order[tile_name]
|
||||
if not degrade_tile_name then return end
|
||||
@@ -33,8 +32,9 @@ local function degrade_entity(entity)
|
||||
|
||||
local tiles = {}
|
||||
local surface = entity.surface
|
||||
local left_top = entity.bounding_box.left_top
|
||||
local right_bottom = entity.bounding_box.right_bottom
|
||||
local bounding_box = entity.bounding_box
|
||||
local left_top = bounding_box.left_top
|
||||
local right_bottom = bounding_box.right_bottom
|
||||
for x = left_top.x, right_bottom.x do
|
||||
for y = left_top.y, right_bottom.y do
|
||||
local tile = surface.get_tile(x, y)
|
||||
@@ -58,11 +58,10 @@ end
|
||||
|
||||
--- Gets the average tile strengths around position
|
||||
--- @param surface LuaSurface
|
||||
--- @param position MapPosition
|
||||
--- @param position MapPosition.struct
|
||||
--- @return number?
|
||||
local function get_tile_strength(surface, position)
|
||||
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761
|
||||
local tile = surface.get_tile(position)
|
||||
local tile = surface.get_tile(position.x, position.y)
|
||||
local tile_name = tile.name
|
||||
local strength = config.strengths[tile_name]
|
||||
if not strength then return end
|
||||
|
||||
@@ -31,15 +31,15 @@ local function append_playtime(player_name)
|
||||
end
|
||||
|
||||
--- Get the player name from an event
|
||||
--- @param event { player_index: number, by_player_name: string? }
|
||||
--- @return string, string
|
||||
--- @param event { player_index: uint, by_player_name: string? }
|
||||
--- @return string, string?
|
||||
local function get_player_name(event)
|
||||
local player = game.players[event.player_index]
|
||||
return player.name, event.by_player_name
|
||||
end
|
||||
|
||||
--- Convert a colour value into hex
|
||||
--- @param color Color.0
|
||||
--- @param color Color.struct
|
||||
--- @return string
|
||||
local function to_hex(color)
|
||||
local hex_digits = "0123456789ABCDEF"
|
||||
@@ -53,7 +53,7 @@ local function to_hex(color)
|
||||
end
|
||||
|
||||
--- Emit the requires json to file for the given event arguments
|
||||
--- @param opts { title: string?, color: (Color.0 | string)?, description: string?, tick: number?, fields: { name: string, value: string, inline: boolean? }[] }
|
||||
--- @param opts { title: string?, color: (Color.struct | string)?, description: string?, tick: number?, fields: { name: string, value: string, inline: boolean? }[] }
|
||||
local function emit_event(opts)
|
||||
local admins_online = 0
|
||||
local players_online = 0
|
||||
|
||||
@@ -23,7 +23,7 @@ end
|
||||
--- @param event EventData.on_cargo_pod_finished_ascending
|
||||
local function on_cargo_pod_finished_ascending(event)
|
||||
if event.launched_by_rocket then
|
||||
local force = event.cargo_pod.force
|
||||
local force = event.cargo_pod.force --[[@as LuaForce]]
|
||||
if force.rockets_launched >= config.rocket_launch_display_rate and force.rockets_launched % config.rocket_launch_display_rate == 0 then
|
||||
add_log_line("[ROCKET]", force.rockets_launched, "rockets launched")
|
||||
elseif config.rocket_launch_display[force.rockets_launched] then
|
||||
@@ -38,7 +38,7 @@ local function on_pre_player_died(event)
|
||||
local cause = event.cause
|
||||
if cause then
|
||||
if cause.type == "character" then
|
||||
add_log_line("[DEATH]", player.name, "died because of", cause.player.name)
|
||||
add_log_line("[DEATH]", player.name, "died because of", assert(cause.player).name)
|
||||
else
|
||||
add_log_line("[DEATH]", player.name, "died because of", cause.name)
|
||||
end
|
||||
|
||||
@@ -22,7 +22,7 @@ local min = math.min
|
||||
--- @field trees LuaEntity[]
|
||||
--- @field tree_count number
|
||||
--- @field permission "fast" | "allow" | "disallow"
|
||||
--- @field task Async.AsyncReturn
|
||||
--- @field task Async.AsyncReturn<any>
|
||||
|
||||
local cache --- @type TreeDeconCache?
|
||||
|
||||
@@ -77,14 +77,15 @@ local function get_player_cache(player_index)
|
||||
|
||||
-- Create a new cache if the previous on is in use
|
||||
if not cache or cache.task and not cache.task.completed then
|
||||
cache = {} --[[@as any]]
|
||||
--- @diagnostic disable-next-line: missing-fields
|
||||
cache = {} --[[@as TreeDeconCache]]
|
||||
end
|
||||
|
||||
local player = assert(game.get_player(player_index))
|
||||
cache.tick = game.tick
|
||||
cache.player_index = player_index
|
||||
cache.player = player
|
||||
cache.force = player.force --[[ @as LuaForce ]]
|
||||
cache.force = player.force --[[@as LuaForce]]
|
||||
cache.tree_count = 0
|
||||
cache.trees = {}
|
||||
cache.permission = get_permission(player)
|
||||
|
||||
@@ -6,7 +6,7 @@ local Async = require("modules/exp_util/async")
|
||||
local Storage = require("modules/exp_util/storage")
|
||||
local config = require("modules.exp_legacy.config.compilatron")
|
||||
|
||||
--- @type table<string, Async.AsyncReturn>
|
||||
--- @type table<string, Async.AsyncReturn<any>>
|
||||
local persistent_locations = {}
|
||||
Storage.register(persistent_locations, function(tbl)
|
||||
persistent_locations = tbl
|
||||
@@ -55,7 +55,7 @@ local speech_bubble_task =
|
||||
--- @param entity LuaEntity the entity which will have messages spawn from it
|
||||
--- @param messages LocalisedString[] the messages which should be shown
|
||||
--- @param starting_index number? the message index to start at, default 1
|
||||
--- @return Async.AsyncReturn
|
||||
--- @return Async.AsyncReturn<any>
|
||||
local function register_entity(entity, messages, starting_index)
|
||||
return speech_bubble_task{
|
||||
entity = entity,
|
||||
|
||||
@@ -68,12 +68,13 @@ local function try_deconstruct_output_chest(entity)
|
||||
end
|
||||
|
||||
-- Get all adjacent mining drills and inserters
|
||||
local target_position = target.position
|
||||
local entities = target.surface.find_entities_filtered{
|
||||
type = { "mining-drill", "inserter" },
|
||||
to_be_deconstructed = false,
|
||||
area = {
|
||||
{ target.position.x - 1, target.position.y - 1 },
|
||||
{ target.position.x + 1, target.position.y + 1 }
|
||||
left_top = { x = target_position.x - 1, y = target_position.y - 1 },
|
||||
right_bottom = { x = target_position.x + 1, y = target_position.y + 1 },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -250,16 +251,17 @@ local function on_resource_depleted(event)
|
||||
local drills = resource.surface.find_entities_filtered{
|
||||
type = "mining-drill",
|
||||
area = {
|
||||
{ position.x - max_mining_radius, position.y - max_mining_radius },
|
||||
{ position.x + max_mining_radius, position.y + max_mining_radius },
|
||||
left_top = { x = position.x - max_mining_radius, y = position.y - max_mining_radius },
|
||||
right_bottom = { x = position.x + max_mining_radius, y = position.y + max_mining_radius },
|
||||
},
|
||||
}
|
||||
|
||||
-- Check which could have reached this resource
|
||||
for _, drill in pairs(drills) do
|
||||
local radius = drill.prototype.mining_drill_radius
|
||||
local dx = math.abs(drill.position.x - position.x)
|
||||
local dy = math.abs(drill.position.y - position.y)
|
||||
local drill_position = drill.position
|
||||
local dx = math.abs(drill_position.x - position.x)
|
||||
local dy = math.abs(drill_position.y - position.y)
|
||||
if dx <= radius and dy <= radius then
|
||||
try_deconstruct_miner(drill)
|
||||
end
|
||||
|
||||
@@ -7,11 +7,11 @@ local config = require("modules.exp_legacy.config.spawn_area")
|
||||
--- Apply an offset to a LuaPosition
|
||||
--- @param position MapPosition
|
||||
--- @param offset MapPosition
|
||||
--- @return MapPosition.0
|
||||
--- @return MapPosition.struct
|
||||
local function apply_offset(position, offset)
|
||||
return {
|
||||
x = (position.x or position[1]) + (offset.x or offset[1]),
|
||||
y = (position.y or position[2]) + (offset.y or offset[2])
|
||||
x = position.x + offset.x,
|
||||
y = position.y + offset.y,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -21,8 +21,8 @@ end
|
||||
--- @param x_index number
|
||||
--- @param y_index number
|
||||
local function apply_offset_to_array(positions, offset, x_index, y_index)
|
||||
local x = (offset.x or offset[1])
|
||||
local y = (offset.y or offset[2])
|
||||
local x = offset.x
|
||||
local y = offset.y
|
||||
for _, position in ipairs(positions) do
|
||||
position[x_index] = position[x_index] + x
|
||||
position[y_index] = position[y_index] + y
|
||||
@@ -149,11 +149,13 @@ local function create_entities(surface, offset)
|
||||
local pos = apply_offset({ entity_details[2], entity_details[3] }, offset)
|
||||
local entity = surface.create_entity{ name = entity_details[1], position = pos, force = "neutral" }
|
||||
|
||||
if entity and config.entities.protected then
|
||||
protect_entity(entity)
|
||||
end
|
||||
if entity then
|
||||
if config.entities.protected then
|
||||
protect_entity(entity)
|
||||
end
|
||||
|
||||
entity.operable = config.entities.operable
|
||||
entity.operable = config.entities.operable
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -164,8 +166,7 @@ local function clear_spawn_area(surface, offset)
|
||||
local get_tile = surface.get_tile
|
||||
|
||||
-- Make sure a non water tile is used for filling
|
||||
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761
|
||||
local starting_tile = get_tile(offset)
|
||||
local starting_tile = get_tile(offset.x, offset.y)
|
||||
local fill_tile = starting_tile.collides_with("player") and "landfill" or starting_tile.name
|
||||
local fill_radius = config.spawn_area.landfill_radius
|
||||
local fill_radius_sqr = fill_radius ^ 2
|
||||
@@ -185,8 +186,7 @@ local function clear_spawn_area(surface, offset)
|
||||
if dst < tile_radius_sqr then
|
||||
-- If it is inside the decon radius always set the tile
|
||||
tiles_to_make[#tiles_to_make + 1] = { name = decon_tile, position = pos }
|
||||
--- @diagnostic disable-next-line Incorrect Api Type: https://forums.factorio.com/viewtopic.php?f=233&t=109145&p=593761&hilit=get_tile#p593761
|
||||
elseif dst < fill_radius_sqr and get_tile(pos).collides_with("player") then
|
||||
elseif dst < fill_radius_sqr and get_tile(pos.x, pos.y).collides_with("player") then
|
||||
-- If it is inside the fill radius only set the tile if it is water
|
||||
tiles_to_make[#tiles_to_make + 1] = { name = fill_tile, position = pos }
|
||||
end
|
||||
@@ -278,7 +278,8 @@ local function on_player_created(event)
|
||||
if config.resource_patches.enabled then create_resource_patches(surface, offset) end
|
||||
if config.turrets.enabled then update_turrets() end
|
||||
|
||||
player.force.set_spawn_position(offset, surface)
|
||||
local force = player.force --[[@as LuaForce]]
|
||||
force.set_spawn_position(offset, surface)
|
||||
player.teleport(offset, surface)
|
||||
end
|
||||
|
||||
|
||||
@@ -66,8 +66,9 @@ local function rename_station(event)
|
||||
|
||||
-- Check which recourse is closest
|
||||
for _, resource in ipairs(resources) do
|
||||
local dx = px - resource.bounding_box.left_top.x
|
||||
local dy = py - resource.bounding_box.left_top.y
|
||||
local resource_box = resource.bounding_box
|
||||
local dx = px - resource_box.left_top.x
|
||||
local dy = py - resource_box.left_top.y
|
||||
local distance = (dx * dx) + (dy * dy)
|
||||
if distance < closest_distance then
|
||||
closest_distance = distance
|
||||
@@ -78,7 +79,8 @@ local function rename_station(event)
|
||||
-- Set the item name and icon
|
||||
if closest_recourse then
|
||||
item_name = closest_recourse.name:gsub("^%l", string.upper):gsub("-", " ") -- remove dashes and making first letter capital
|
||||
local product = closest_recourse.prototype.mineable_properties.products[1]
|
||||
local products = assert(closest_recourse.prototype.mineable_properties.products)
|
||||
local product = assert(products[1])
|
||||
icon = string.format("[img=%s.%s]", product.type, product.name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -49,7 +49,7 @@ Elements.toggle_section_button = Gui.define("autofill/toggle_section_button")
|
||||
element.sprite = "utility/expand"
|
||||
element.tooltip = { "exp-gui_autofill.tooltip-toggle-section-expand" }
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Toggle if an entity will be autofilled when played
|
||||
--- @class ExpGui_Autofill.elements.toggle_entity_button: ExpElement
|
||||
@@ -88,7 +88,7 @@ Elements.toggle_entity_button = Gui.define("autofill/toggle_entity_button")
|
||||
style.padding = 0
|
||||
style.height = 22
|
||||
style.width = 22
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Toggle if an item will be inserted into an entity
|
||||
--- @class ExpGui_Autofill.elements.toggle_item_button: ExpElement
|
||||
@@ -127,7 +127,7 @@ Elements.toggle_item_button = Gui.define("autofill/toggle_item_button")
|
||||
style.padding = -2
|
||||
style.height = 32
|
||||
style.width = 32
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- The amount of an item to insert
|
||||
--- @class ExpGui_Autofill.elements.amount_textfield: ExpElement
|
||||
@@ -165,7 +165,7 @@ Elements.amount_textfield = Gui.define("autofill/amount_textfield")
|
||||
element.text = tostring(clamped)
|
||||
player.print{ "exp-gui_autofill.invalid", clamped, rich_img("item", item_settings.name), rich_img("entity", item_settings.entity) }
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- A disabled version of the autofill settings used as a filler
|
||||
Elements.disabled_autofill_setting = Gui.define("autofill/empty_autofill_setting")
|
||||
@@ -221,9 +221,9 @@ Elements.section = Gui.define("autofill/section")
|
||||
end)
|
||||
:on_click(function(def, player, element, event)
|
||||
--- @cast def ExpGui_Autofill.elements.section
|
||||
event.element = def.data[element] --[[ @as LuaGuiElement ]]
|
||||
event.element = def.data[element] --[[@as LuaGuiElement]]
|
||||
Elements.toggle_section_button:raise_event(event)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Add an item category to a section, at most three can exist
|
||||
--- @param section LuaGuiElement
|
||||
@@ -238,7 +238,7 @@ function Elements.section.add_category(section, category_name)
|
||||
category.style.vertical_spacing = 1
|
||||
|
||||
local ctn = 0
|
||||
local entity_settings = Elements.section.data[section] --[[ @as ExpGui_Autofill.entity_settings ]]
|
||||
local entity_settings = Elements.section.data[section] --[[@as ExpGui_Autofill.entity_settings]]
|
||||
for _, item_data in pairs(entity_settings.items) do
|
||||
if item_data.category == category_name then
|
||||
Elements.toggle_item_button(category, item_data)
|
||||
@@ -265,7 +265,7 @@ end
|
||||
|
||||
--- Container added to the left gui flow
|
||||
--- @class ExpGui_Autofill.elements.container: ExpElement
|
||||
--- @field data table<string, ExpGui_Autofill.entity_settings>
|
||||
--- @field data table<LuaPlayer, table<string, ExpGui_Autofill.entity_settings>>
|
||||
Elements.container = Gui.define("autofill/container")
|
||||
:draw(function(def, parent)
|
||||
--- @cast def ExpGui_Autofill.elements.container
|
||||
@@ -312,7 +312,7 @@ Elements.container = Gui.define("autofill/container")
|
||||
end
|
||||
|
||||
return container.parent
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Get the autofill settings for a player
|
||||
--- @param player LuaPlayer
|
||||
|
||||
@@ -27,7 +27,7 @@ function Public.show(container)
|
||||
local left_panel_style = left_panel.style
|
||||
left_panel_style.width = 300
|
||||
|
||||
--- @diagnostic disable-next-line invisible
|
||||
--- @diagnostic disable-next-line: access-invisible
|
||||
for element_name in pairs(ExpElement._elements) do
|
||||
local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = element_name }
|
||||
Gui.set_data(header, element_name)
|
||||
@@ -92,18 +92,18 @@ Gui.on_click(
|
||||
input_text_box.text = concat{ "ExpElement._elements[\"", element_name, "\"]" }
|
||||
input_text_box.style.font_color = Color.black
|
||||
|
||||
--- @diagnostic disable-next-line invisible
|
||||
--- @diagnostic disable-next-line: access-invisible
|
||||
local define = ExpElement._elements[element_name]
|
||||
local content = dump({
|
||||
--- @diagnostic disable-next-line invisible
|
||||
--- @diagnostic disable-next-line: access-invisible
|
||||
debug = define._debug,
|
||||
--- @diagnostic disable-next-line invisible
|
||||
--- @diagnostic disable-next-line: access-invisible
|
||||
has_handlers = define._has_handlers,
|
||||
--- @diagnostic disable-next-line invisible
|
||||
--- @diagnostic disable-next-line: access-invisible
|
||||
track_elements = define._track_elements,
|
||||
--- @diagnostic disable-next-line invisible
|
||||
--- @diagnostic disable-next-line: access-invisible
|
||||
elements = ExpIter._scopes[element_name],
|
||||
--- @diagnostic disable-next-line invisible
|
||||
--- @diagnostic disable-next-line: access-invisible
|
||||
data = ExpData._scopes[element_name]._raw,
|
||||
}) or "nil"
|
||||
right_panel.text = content
|
||||
|
||||
@@ -4,7 +4,7 @@ local ExpUtil = require("modules/exp_util")
|
||||
local concat = table.concat
|
||||
local inspect = table.inspect
|
||||
local pcall = pcall
|
||||
local loadstring = loadstring --- @diagnostic disable-line
|
||||
local loadstring = load
|
||||
local rawset = rawset
|
||||
|
||||
local Public = {}
|
||||
|
||||
@@ -24,7 +24,7 @@ function Public.show(container)
|
||||
local left_panel_style = left_panel.style
|
||||
left_panel_style.width = 300
|
||||
|
||||
--- @diagnostic disable-next-line invisible
|
||||
--- @diagnostic disable-next-line: access-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 }
|
||||
Gui.set_data(header, token_id)
|
||||
|
||||
@@ -22,11 +22,10 @@ Elements.online_player_dropdown = Gui.define("player_dropdown")
|
||||
end)
|
||||
:style{
|
||||
height = 24,
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- To help with caching and avoid context changes the player list from the previous update is remembered
|
||||
--- @type (string?)[]
|
||||
do local _player_names = {}
|
||||
do local _player_names = {} --- @type (string?)[]
|
||||
--- Updates the player name list after a join or leave
|
||||
--- @return (string?)[]
|
||||
function Elements.online_player_dropdown._update_player_names()
|
||||
|
||||
@@ -78,7 +78,7 @@ Elements.create_selection_planner = Gui.define("module_inserter/create_selection
|
||||
:on_click(function(def, player, element)
|
||||
--- @cast def ExpGui_ModuleInserter.elements.create_selection_planner
|
||||
SelectArea:start(player, def.data[element])
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Used to select the machine to apply modules to
|
||||
--- @class ExpGui_ModuleInserter.elements.machine_selector: ExpElement
|
||||
@@ -98,7 +98,7 @@ Elements.machine_selector = Gui.define("module_inserter/machine_selector")
|
||||
:on_elem_changed(function(def, player, element, event)
|
||||
--- @cast def ExpGui_ModuleInserter.elements.machine_selector
|
||||
local element_data = def.data[element]
|
||||
local machine_name = element.elem_value --[[ @as string? ]]
|
||||
local machine_name = element.elem_value --[[@as string?]]
|
||||
if not machine_name then
|
||||
if element_data.on_last_row then
|
||||
Elements.module_table.reset_row(element_data.module_table, element)
|
||||
@@ -112,7 +112,7 @@ Elements.machine_selector = Gui.define("module_inserter/machine_selector")
|
||||
Elements.module_table.add_row(element_data.module_table)
|
||||
end
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Used to select the modules to be applied
|
||||
Elements.module_selector = Gui.define("module_inserter/module_selector")
|
||||
@@ -140,7 +140,7 @@ Elements.module_table = Gui.define("module_inserter/module_table")
|
||||
local slots_per_row = config.module_slots_per_row + 1
|
||||
return Gui.elements.scroll_table(parent, 280, slots_per_row)
|
||||
end)
|
||||
:element_data{} --[[ @as any ]]
|
||||
:element_data{} --[[@as any]]
|
||||
|
||||
--- Get all the rows in a module table
|
||||
--- @param module_table LuaGuiElement
|
||||
@@ -177,7 +177,7 @@ end
|
||||
--- @param machine_selector LuaGuiElement
|
||||
function Elements.module_table.remove_row(module_table, machine_selector)
|
||||
local rows = Elements.module_table.data[module_table]
|
||||
local row = rows[machine_selector.index]
|
||||
local row = assert(rows[machine_selector.index])
|
||||
rows[machine_selector.index] = nil
|
||||
Gui.destroy_if_valid(machine_selector)
|
||||
for _, separator in pairs(row.row_separators) do
|
||||
@@ -193,7 +193,7 @@ end
|
||||
--- @param machine_selector LuaGuiElement
|
||||
function Elements.module_table.reset_row(module_table, machine_selector)
|
||||
local rows = Elements.module_table.data[module_table]
|
||||
local row = rows[machine_selector.index]
|
||||
local row = assert(rows[machine_selector.index])
|
||||
|
||||
for _, separator in pairs(row.row_separators) do
|
||||
separator.visible = false
|
||||
@@ -211,9 +211,9 @@ end
|
||||
--- @param machine_name string
|
||||
function Elements.module_table.refresh_row(module_table, machine_selector, machine_name)
|
||||
local rows = Elements.module_table.data[module_table]
|
||||
local row = rows[machine_selector.index]
|
||||
local row = assert(rows[machine_selector.index])
|
||||
|
||||
local active_module_count = prototypes.entity[machine_name].module_inventory_size
|
||||
local active_module_count = assert(prototypes.entity[machine_name].module_inventory_size)
|
||||
local visible_row_count = math.ceil(active_module_count / config.module_slots_per_row)
|
||||
local visible_module_count = visible_row_count * config.module_slots_per_row
|
||||
local module_elem_value = { name = config.machines[machine_name].module }
|
||||
@@ -277,8 +277,8 @@ local function apply_planners_in_area(player, area, machine_name, planner_with_p
|
||||
-- Bounding box table to be reused in the loop below
|
||||
--- @type BoundingBox
|
||||
local param_area = {
|
||||
left_top = {},
|
||||
right_bottom = {}
|
||||
left_top = { x = 0, y = 0 },
|
||||
right_bottom = { x = 0, y = 0 },
|
||||
}
|
||||
|
||||
-- Update area param table to be reused in the loop below
|
||||
@@ -334,7 +334,7 @@ SelectArea:on_selection(function(event, module_table)
|
||||
}
|
||||
|
||||
for _, row in pairs(Elements.module_table.get_rows(module_table)) do
|
||||
local machine_name = row.machine_selector.elem_value --[[ @as string? ]]
|
||||
local machine_name = row.machine_selector.elem_value --[[@as string?]]
|
||||
if not machine_name then
|
||||
goto continue
|
||||
end
|
||||
@@ -348,8 +348,8 @@ SelectArea:on_selection(function(event, module_table)
|
||||
|
||||
-- Get all the modules selected
|
||||
for i = 1, entity_prototype.module_inventory_size do
|
||||
local module_selector = module_selectors[i]
|
||||
local module = module_selector.elem_value --[[ @as { name: string, quality: string }? ]]
|
||||
local module_selector = assert(module_selectors[i])
|
||||
local module = module_selector.elem_value --[[@as { name: string, quality: string }?]]
|
||||
if module then
|
||||
-- Module selected, add it the module arrays
|
||||
local no_prod_name = module.name:gsub("productivity", "efficiency")
|
||||
|
||||
@@ -22,13 +22,16 @@ local Elements = {}
|
||||
--- @field _cost_scale number
|
||||
|
||||
--- For perf calculate the division of scale against cost ahead of time
|
||||
for _, bonus_data in pairs(config.player_bonus) do
|
||||
--- @type table<string, ExpGui_PlayerBonus.bonus_data>
|
||||
local player_bonus = config.player_bonus
|
||||
|
||||
for _, bonus_data in pairs(player_bonus) do
|
||||
bonus_data._cost_scale = bonus_data.cost / bonus_data.scale
|
||||
end
|
||||
|
||||
--- Progress bar which displays how much of a bonus has been used
|
||||
--- @class ExpGui_PlayerBonus.elements.bonus_used: ExpElement
|
||||
--- @field data number
|
||||
--- @field data table<LuaGuiElement, number>
|
||||
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
|
||||
Elements.bonus_used = Gui.define("player_bonus/bonus_used")
|
||||
:track_all_elements()
|
||||
@@ -44,11 +47,10 @@ Elements.bonus_used = Gui.define("player_bonus/bonus_used")
|
||||
font = "heading-2",
|
||||
color = { 1, 0, 0 },
|
||||
}
|
||||
:element_data(0) --[[ @as any ]]
|
||||
:element_data(0) --[[@as any]]
|
||||
|
||||
--- Value is cached to save perf
|
||||
--- @type table<number, number>
|
||||
do local _points_limit = {}
|
||||
do local _points_limit = {} --- @type table<number, number>
|
||||
--- Clear the cache for points limit
|
||||
--- @param player LuaPlayer
|
||||
function Elements.bonus_used._clear_points_limit_cache(player)
|
||||
@@ -145,7 +147,7 @@ Elements.reset_button = Gui.define("player_bonus/reset_button")
|
||||
Elements.bonus_table.reset_sliders(element_data.bonus_table)
|
||||
local bonus_cost = Elements.bonus_table.calculate_cost(element_data.bonus_table)
|
||||
Elements.bonus_used.refresh(element_data.bonus_used, bonus_cost)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Link an apply button to this reset button so that it will be disabled after being pressed
|
||||
--- @param reset_button LuaGuiElement
|
||||
@@ -186,7 +188,7 @@ Elements.apply_button = Gui.define("player_bonus/apply_button")
|
||||
Elements.bonus_table.save_sliders(element_data.bonus_table)
|
||||
Elements.container.apply_player_bonus(player)
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Link an apply button to this reset button so that it will be disabled after being pressed
|
||||
--- @param apply_button LuaGuiElement
|
||||
@@ -207,7 +209,7 @@ Elements.bonus_table_label = Gui.define("player_bonus/table_label")
|
||||
}
|
||||
:style{
|
||||
width = Gui.from_argument(3, 70),
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- @class ExpGui_PlayerBonus.elements.bonus_slider.elements
|
||||
--- @field bonus_used LuaGuiElement
|
||||
@@ -265,7 +267,7 @@ Elements.bonus_slider = Gui.define("player_bonus/bonus_slider")
|
||||
element_data.label.caption = Elements.bonus_slider.calculate_slider_caption(bonus_data, value)
|
||||
element_data.apply_button.enabled = Elements.bonus_used.update(element_data.bonus_used, value_change * bonus_data._cost_scale)
|
||||
element_data.reset_button.enabled = true
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Get the caption of the slider label
|
||||
--- @param bonus_data ExpGui_PlayerBonus.bonus_data
|
||||
@@ -311,7 +313,7 @@ Elements.bonus_table = Gui.define("player_bonus/bonus_table")
|
||||
:draw(function(_, parent)
|
||||
return Gui.elements.scroll_table(parent, 300, 3)
|
||||
end)
|
||||
:element_data{} --[[ @as any ]]
|
||||
:element_data{} --[[@as any]]
|
||||
|
||||
--- Adds a row to the milestone table
|
||||
--- @param bonus_table LuaGuiElement
|
||||
@@ -378,7 +380,7 @@ Elements.container = Gui.define("player_bonus/container")
|
||||
Elements.bonus_used.refresh(elements.bonus_used, bonus_cost)
|
||||
|
||||
return Gui.elements.container.get_root_element(container)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Set the bonus value for a player
|
||||
--- @param player LuaPlayer
|
||||
@@ -442,7 +444,7 @@ end
|
||||
function Elements.container.calculate_cost(player)
|
||||
local cost = 0
|
||||
local player_data = Elements.container.data[player]
|
||||
for _, bonus_data in pairs(config.player_bonus) do
|
||||
for _, bonus_data in pairs(player_bonus) do
|
||||
cost = cost + (player_data[bonus_data.name] or 0) * bonus_data._cost_scale
|
||||
end
|
||||
return cost
|
||||
|
||||
@@ -48,14 +48,14 @@ Elements.open_action_bar = Gui.define("player_list/open_action_bar")
|
||||
--- @cast def ExpGui_PlayerList.elements.open_action_bar
|
||||
Elements.container.toggle_selected_player(player, def.data[element])
|
||||
Elements.player_table.refresh_player(player)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Set whether an open action bar button shows as highlighted
|
||||
--- @param open_button LuaGuiElement
|
||||
--- @param highlighted boolean
|
||||
function Elements.open_action_bar.set_highlight(open_button, highlighted)
|
||||
open_button.style = highlighted and "tool_button" or "frame_button"
|
||||
local style = open_button.style
|
||||
local style = open_button.style --[[@as LuaStyle]]
|
||||
style.padding = -2
|
||||
style.width = 8
|
||||
style.height = 14
|
||||
@@ -80,7 +80,7 @@ Elements.close_action_bar = Gui.define("player_list/close_action_bar")
|
||||
:on_click(function(_, player)
|
||||
Elements.container.set_selected_player(player, nil)
|
||||
Elements.player_table.refresh_player(player)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Button used to confirm a reason
|
||||
--- @class ExpGui_PlayerList.elements.reason_confirm: ExpElement
|
||||
@@ -102,14 +102,14 @@ Elements.reason_confirm = Gui.define("player_list/reason_confirm")
|
||||
local action_name = Elements.container.get_selected_action(player)
|
||||
local button_data = action_name and config.buttons[action_name]
|
||||
if button_data and button_data.reason_callback then
|
||||
local reason = element.parent.entry.text
|
||||
local reason = assert(element.parent).entry.text --[[@as string?]]
|
||||
if reason == nil or not reason:find("%S") then reason = "no reason given" end
|
||||
button_data.reason_callback(player, reason)
|
||||
end
|
||||
element.parent.entry.text = ""
|
||||
assert(element.parent).entry.text = ""
|
||||
Elements.container.set_selected_player(player, nil)
|
||||
Elements.player_table.refresh_player(player)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Clickable player name label, left click opens the map and right click toggles the action bar
|
||||
--- @class ExpGui_PlayerList.elements.player_name_label: ExpElement
|
||||
@@ -142,7 +142,7 @@ Elements.player_name_label = Gui.define("player_list/player_name_label")
|
||||
Elements.container.toggle_selected_player(player, selected_player)
|
||||
Elements.player_table.refresh_player(player)
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- @class ExpGui_PlayerList.elements.player_table.row
|
||||
--- @field open_button LuaGuiElement
|
||||
@@ -165,7 +165,7 @@ Elements.player_table = Gui.define("player_list/player_table")
|
||||
end)
|
||||
:style{
|
||||
padding = { 1, 0, 1, 2 },
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- Store the action and reason bars associated with a player table
|
||||
--- @param player_table LuaGuiElement
|
||||
@@ -342,7 +342,7 @@ Elements.action_bar = Gui.define("player_list/action_bar")
|
||||
:style{
|
||||
height = 35,
|
||||
padding = { 1, 3 },
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- Update the action bar buttons to match the selection for a player, hidden when nothing is selected
|
||||
--- @param action_bar LuaGuiElement
|
||||
@@ -390,7 +390,7 @@ Elements.reason_bar = Gui.define("player_list/reason_bar")
|
||||
:style{
|
||||
height = 35,
|
||||
padding = { -1, 3 },
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- Update the reason bar visibility to match the selection, shown only while an action awaits a reason
|
||||
--- @param reason_bar LuaGuiElement
|
||||
@@ -420,7 +420,7 @@ Elements.container = Gui.define("player_list/container")
|
||||
Elements.player_table.rebuild(player_table, row_data)
|
||||
|
||||
return Gui.elements.container.get_root_element(container)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Get or create the selection state for a player
|
||||
--- @param player LuaPlayer
|
||||
|
||||
@@ -93,7 +93,7 @@ Elements.table_label = Gui.define("player_stats/table_label")
|
||||
}
|
||||
:style{
|
||||
width = Gui.from_argument("width"),
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- Data table that shows all data for a player
|
||||
--- @class ExpGui_PlayerStats.elements.player_stats_table: ExpElement
|
||||
@@ -139,7 +139,7 @@ Elements.player_stats_table = Gui.define("player_stats/data_table")
|
||||
|
||||
def.data[data_table] = labels
|
||||
return data_table
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh a data table with the most recent stats for a player
|
||||
--- @param data_table LuaGuiElement
|
||||
@@ -185,7 +185,7 @@ Elements.player_dropdown = Gui.define("player_stats/player_dropdown")
|
||||
local data_table = def.data[element]
|
||||
local target_player = ElementsExtra.online_player_dropdown.get_selected(element)
|
||||
Elements.player_stats_table.refresh(data_table, target_player)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh all stats tables associated with a player dropdown
|
||||
function Elements.player_dropdown.refresh_online()
|
||||
|
||||
@@ -9,6 +9,7 @@ local Roles = require("modules/exp_legacy/expcore/roles")
|
||||
local Elements = {}
|
||||
|
||||
--- The flow precision values in the same order as production_precision_dropdown.items
|
||||
--- @type defines.flow_precision_index[]
|
||||
local precision_indexes = {
|
||||
defines.flow_precision_index.five_seconds,
|
||||
defines.flow_precision_index.one_minute,
|
||||
@@ -94,7 +95,7 @@ Elements.item_selector = Gui.define("production_stats/item_selector")
|
||||
element_data.on_last_row = false
|
||||
Elements.production_table.add_row(element_data.production_table)
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Label used for every element in the production table
|
||||
Elements.table_label = Gui.define("production_stats/table_label")
|
||||
@@ -129,7 +130,7 @@ Elements.production_table = Gui.define("production_stats/production_table")
|
||||
:track_all_elements()
|
||||
:draw(function(def, parent)
|
||||
local scroll_table = Gui.elements.scroll_table(parent, 304, 4)
|
||||
local display_alignments = scroll_table.style.column_alignments
|
||||
local display_alignments = assert(scroll_table.style.column_alignments)
|
||||
for i = 2, 4 do
|
||||
display_alignments[i] = "right"
|
||||
end
|
||||
@@ -144,7 +145,7 @@ Elements.production_table = Gui.define("production_stats/production_table")
|
||||
Elements.table_label(scroll_table, { "exp-gui_production-stats.caption-net" }, { "exp-gui_production-stats.tooltip-per-second" }, "heading_2_label")
|
||||
|
||||
return scroll_table
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Calculate the row data for a production table
|
||||
--- @param force LuaForce
|
||||
@@ -183,7 +184,7 @@ end
|
||||
--- @param item_selector LuaGuiElement
|
||||
function Elements.production_table.remove_row(production_table, item_selector)
|
||||
local rows = Elements.production_table.data[production_table].rows
|
||||
local row = rows[item_selector.index]
|
||||
local row = assert(rows[item_selector.index])
|
||||
rows[item_selector.index] = nil
|
||||
Gui.destroy_if_valid(item_selector)
|
||||
for _, element in pairs(row) do
|
||||
@@ -196,7 +197,7 @@ end
|
||||
--- @param item_selector LuaGuiElement
|
||||
function Elements.production_table.reset_row(production_table, item_selector)
|
||||
local rows = Elements.production_table.data[production_table].rows
|
||||
local row = rows[item_selector.index]
|
||||
local row = assert(rows[item_selector.index])
|
||||
row.production.caption = "0.00"
|
||||
row.consumption.caption = "0.00"
|
||||
row.net.caption = "0.00"
|
||||
@@ -209,7 +210,7 @@ end
|
||||
--- @param row_data ExpGui_ProductionStats.elements.production_table.row_data
|
||||
function Elements.production_table.refresh_row(production_table, item_selector, row_data)
|
||||
local rows = Elements.production_table.data[production_table].rows
|
||||
local row = rows[item_selector.index]
|
||||
local row = assert(rows[item_selector.index])
|
||||
row.production.caption = row_data.production
|
||||
row.consumption.caption = row_data.consumption
|
||||
row.net.caption = row_data.net
|
||||
@@ -223,9 +224,9 @@ function Elements.production_table.refresh_online()
|
||||
local precision_index = precision_indexes[element_data.precision_dropdown.selected_index]
|
||||
for _, row in pairs(element_data.rows) do
|
||||
local item_selector = row.item_selector
|
||||
local item_name = item_selector.elem_value --[[ @as string? ]]
|
||||
local item_name = item_selector.elem_value --[[@as string?]]
|
||||
if item_name then
|
||||
local row_data = Elements.production_table.calculate_row_data(player.force --[[ @as LuaForce ]], player.surface, item_name, precision_index)
|
||||
local row_data = Elements.production_table.calculate_row_data(player.force --[[@as LuaForce]], player.surface, item_name, precision_index)
|
||||
Elements.production_table.refresh_row(production_table, item_selector, row_data)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -43,13 +43,13 @@ local function new_quick_action(command, on_click)
|
||||
:style{
|
||||
width = 160,
|
||||
}
|
||||
:on_click(on_click or function(def, player, element, event)
|
||||
:on_click(on_click or function(_def, player, _element, _event)
|
||||
command(player)
|
||||
end)
|
||||
|
||||
Elements[command_name] = element
|
||||
Actions[command_name] = {
|
||||
command = command --[[ @as ExpCommand ]],
|
||||
command = command --[[@as ExpCommand]],
|
||||
element = element,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -47,7 +47,7 @@ Elements.title_table = Gui.define("readme/title_table")
|
||||
cell_padding = 0,
|
||||
vertical_align = "center",
|
||||
horizontally_stretchable = true,
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- Scroll pane used for title tables
|
||||
--- @class ExpGui_Readme.elements.title_table_scroll: ExpElement
|
||||
@@ -64,7 +64,7 @@ Elements.title_table_scroll = Gui.define("readme/title_table_scroll")
|
||||
padding = { 1, 3 },
|
||||
maximal_height = scroll_height,
|
||||
horizontally_stretchable = true,
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- Sub content frame
|
||||
--- @class ExpGui_Readme.elements.sub_content: ExpElement
|
||||
@@ -80,7 +80,7 @@ Elements.sub_content = Gui.define("readme/sub_content")
|
||||
horizontal_align = "center",
|
||||
padding = { 2, 2 },
|
||||
top_margin = 2,
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- @class ExpGui_Readme.elements.join_server.elements
|
||||
--- @field server_id string
|
||||
@@ -119,7 +119,7 @@ Elements.join_server = Gui.define("readme/join_server")
|
||||
--- @cast def ExpGui_Readme.elements.join_server
|
||||
local server_id = def.data[button].server_id
|
||||
External.request_connection(player, server_id, true)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh join server button
|
||||
--- @param button LuaGuiElement
|
||||
@@ -244,7 +244,7 @@ define_tab(
|
||||
)
|
||||
|
||||
return container
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
)
|
||||
|
||||
--- Rules tab
|
||||
@@ -261,14 +261,15 @@ define_tab(
|
||||
|
||||
local rules = Gui.elements.scroll_table(container, scroll_height, 1)
|
||||
rules.style = "bordered_table"
|
||||
rules.style.cell_padding = 4
|
||||
local rules_style = rules.style --[[@as LuaStyle]]
|
||||
rules_style.cell_padding = 4
|
||||
|
||||
for i = 1, 15 do
|
||||
Gui.elements.centered_label(rules, frame_width - 30, { "exp-gui_readme.rules-" .. i })
|
||||
end
|
||||
|
||||
return container
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
)
|
||||
|
||||
--- Commands tab
|
||||
@@ -287,7 +288,8 @@ define_tab(
|
||||
|
||||
local commands = Gui.elements.scroll_table(container, scroll_height, 2)
|
||||
commands.style = "bordered_table"
|
||||
commands.style.cell_padding = 0
|
||||
local commands_style = commands.style --[[@as LuaStyle]]
|
||||
commands_style.cell_padding = 0
|
||||
|
||||
for name, command in pairs(Commands.list_for_player(player)) do
|
||||
Gui.elements.centered_label(commands, 120, name)
|
||||
@@ -295,7 +297,7 @@ define_tab(
|
||||
end
|
||||
|
||||
return container
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
)
|
||||
|
||||
--- Servers tab
|
||||
@@ -338,7 +340,7 @@ define_tab(
|
||||
end
|
||||
|
||||
return container
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
)
|
||||
|
||||
--- Backers tab
|
||||
@@ -359,32 +361,32 @@ define_tab(
|
||||
roles = { "Senior Administrator", "Administrator" },
|
||||
title = { "exp-gui_readme.backers-management" },
|
||||
width = 230,
|
||||
players = {},
|
||||
players = {}, --- @type string[]
|
||||
},
|
||||
{
|
||||
roles = { "Board Member", "Senior Backer" },
|
||||
title = { "exp-gui_readme.backers-board" },
|
||||
width = 145,
|
||||
players = {},
|
||||
players = {}, --- @type string[]
|
||||
},
|
||||
{
|
||||
roles = { "Sponsor", "Supporter" },
|
||||
title = { "exp-gui_readme.backers-backers" },
|
||||
width = 196,
|
||||
players = {},
|
||||
players = {}, --- @type string[]
|
||||
},
|
||||
{
|
||||
roles = { "Moderator", "Trainee" },
|
||||
title = { "exp-gui_readme.backers-staff" },
|
||||
width = 235,
|
||||
players = {},
|
||||
players = {}, --- @type string[]
|
||||
},
|
||||
{
|
||||
roles = {},
|
||||
time = 3 * 3600 * 60,
|
||||
title = { "exp-gui_readme.backers-active" },
|
||||
width = 235,
|
||||
players = {},
|
||||
players = {}, --- @type string[]
|
||||
},
|
||||
}
|
||||
|
||||
@@ -433,7 +435,7 @@ define_tab(
|
||||
end
|
||||
|
||||
return container
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
)
|
||||
|
||||
--- @class (exact) ExpGui_Readme.elements.readme_data.param table
|
||||
@@ -599,7 +601,7 @@ define_tab(
|
||||
end
|
||||
|
||||
return container
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
)
|
||||
|
||||
--- @class ExpGui_Readme.elements.container.elements
|
||||
@@ -608,6 +610,7 @@ define_tab(
|
||||
--- Main readme container
|
||||
--- @class ExpGui_Readme.elements.container: ExpElement
|
||||
--- @field data table<LuaGuiElement, ExpGui_Readme.elements.container.elements>
|
||||
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
|
||||
Elements.container = Gui.define("readme/container")
|
||||
:track_all_elements()
|
||||
:draw(function(def, parent)
|
||||
|
||||
@@ -72,7 +72,7 @@ Elements.clock_label = Gui.define("research_milestones/clock_label")
|
||||
type = "label",
|
||||
caption = research_time_format_nil,
|
||||
style = "heading_2_label",
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- Update the clock label for all online players
|
||||
function Elements.clock_label.refresh_online()
|
||||
@@ -95,7 +95,7 @@ Elements.milestone_table_label = Gui.define("research_milestones/table_label")
|
||||
minimal_width = Gui.from_argument(2, 70),
|
||||
horizontal_align = Gui.from_argument(3, "right"),
|
||||
font_color = font_color.neutral,
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- @class ExpGui_ResearchMilestones.elements.milestone_table.row_elements
|
||||
--- @field name LuaGuiElement
|
||||
@@ -124,10 +124,11 @@ Elements.milestone_table = Gui.define("research_milestones/milestone_table")
|
||||
Elements.milestone_table_label(milestone_table, { "exp-gui_research-milestones.caption-difference" })
|
||||
return milestone_table
|
||||
end)
|
||||
:element_data{} --[[ @as any ]]
|
||||
:element_data{} --[[@as any]]
|
||||
|
||||
do local _row_data = {}
|
||||
--- @type ExpGui_ResearchMilestones.elements.milestone_table.row_data
|
||||
--- @diagnostic disable-next-line: missing-fields
|
||||
local empty_row_data = { color = font_color.positive }
|
||||
|
||||
--- Get the row data for a force and research
|
||||
@@ -203,7 +204,7 @@ end
|
||||
--- @param row_index number
|
||||
--- @param row_data ExpGui_ResearchMilestones.elements.milestone_table.row_data
|
||||
function Elements.milestone_table.refresh_row(milestone_table, row_index, row_data)
|
||||
local row = Elements.milestone_table.data[milestone_table][row_index]
|
||||
local row = assert(Elements.milestone_table.data[milestone_table][row_index])
|
||||
row.name.caption = row_data.name
|
||||
row.target.caption = row_data.target
|
||||
row.achieved.caption = row_data.achieved
|
||||
@@ -224,7 +225,7 @@ end
|
||||
--- Refresh all the labels on the table
|
||||
--- @param milestone_table LuaGuiElement
|
||||
function Elements.milestone_table.refresh(milestone_table)
|
||||
local force = Gui.get_player(milestone_table).force --[[ @as LuaForce ]]
|
||||
local force = Gui.get_player(milestone_table).force --[[@as LuaForce]]
|
||||
local start_index = Elements.container.calculate_starting_research_index(force)
|
||||
for row_index = 1, display_size do
|
||||
local row_data = Elements.milestone_table.calculate_row_data(force, start_index + row_index - 1)
|
||||
@@ -234,7 +235,7 @@ end
|
||||
|
||||
--- Refresh all tables for a player
|
||||
function Elements.milestone_table.refresh_player(player)
|
||||
local force = player.force --[[ @as LuaForce ]]
|
||||
local force = player.force --[[@as LuaForce]]
|
||||
local start_index = Elements.container.calculate_starting_research_index(force)
|
||||
for _, milestone_table in Elements.milestone_table:online_elements(player) do
|
||||
for row_index = 1, display_size do
|
||||
@@ -269,10 +270,9 @@ Elements.container = Gui.define("research_milestones/container")
|
||||
local milestone_table = Elements.milestone_table(container)
|
||||
Elements.clock_label(header)
|
||||
|
||||
local force = Gui.get_player(parent).force
|
||||
local force = Gui.get_player(parent).force --[[@as LuaForce]]
|
||||
def.data[force] = def.data[force] or {} -- used by start index and row data
|
||||
|
||||
local force = Gui.get_player(parent).force --[[ @as LuaForce ]]
|
||||
local start_index = Elements.container.calculate_starting_research_index(force)
|
||||
for research_index = start_index, start_index + display_size - 1 do
|
||||
local row_data = Elements.milestone_table.calculate_row_data(force, research_index)
|
||||
@@ -296,7 +296,7 @@ end
|
||||
--- @param research_index number
|
||||
--- @return number
|
||||
function Elements.container.get_achieved_time(force, research_index)
|
||||
return Elements.container.data[force][research_index]
|
||||
return assert(Elements.container.data[force][research_index])
|
||||
end
|
||||
|
||||
--- Calculate the starting research index for a force
|
||||
|
||||
@@ -90,7 +90,7 @@ Elements.toggle_section_button = Gui.define("rocket_info/toggle_section_button")
|
||||
element.sprite = "utility/expand"
|
||||
element.tooltip = { "exp-gui_rocket-info.tooltip-toggle-section-expand" }
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- A clickable coordinate label which opens the silo location on the map when pressed
|
||||
--- @class ExpGui_RocketInfo.elements.position_label: ExpElement
|
||||
@@ -114,7 +114,7 @@ Elements.position_label = Gui.define("rocket_info/position_label")
|
||||
local entity = def.data[element]
|
||||
if not entity or not entity.valid then return end
|
||||
player.set_controller{ type = defines.controllers.remote, position = entity.position, surface = entity.surface }
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Data table showing the launch statistics for a force
|
||||
--- @class ExpGui_RocketInfo.elements.stats_table: ExpElement
|
||||
@@ -125,7 +125,7 @@ Elements.stats_table = Gui.define("rocket_info/stats_table")
|
||||
:element_data{}
|
||||
:draw(function(def, parent)
|
||||
return Gui.elements.scroll_table(parent, 215, 2)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- @class ExpGui_RocketInfo.elements.stats_table.row_data
|
||||
--- @field key string Unique key used to look up the value label
|
||||
@@ -218,7 +218,7 @@ end
|
||||
--- Refresh the stats table for a player, adding any rows that do not yet exist
|
||||
--- @param player LuaPlayer
|
||||
function Elements.stats_table.refresh_player(player)
|
||||
local force = player.force --[[ @as LuaForce ]]
|
||||
local force = player.force --[[@as LuaForce]]
|
||||
local row_data = Elements.stats_table.calculate_row_data(force)
|
||||
for _, stats_table in Elements.stats_table:online_elements(player) do
|
||||
Elements.stats_table.refresh(stats_table, row_data)
|
||||
@@ -243,7 +243,7 @@ Elements.milestones_table = Gui.define("rocket_info/milestones_table")
|
||||
:element_data{}
|
||||
:draw(function(def, parent)
|
||||
return Gui.elements.scroll_table(parent, 215, 2)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- @class ExpGui_RocketInfo.elements.milestones_table.row_data
|
||||
--- @field milestone number The milestone this row represents
|
||||
@@ -315,7 +315,7 @@ end
|
||||
--- Refresh the milestones table for a player, adding rows as new milestones become visible
|
||||
--- @param player LuaPlayer
|
||||
function Elements.milestones_table.refresh_player(player)
|
||||
local force = player.force --[[ @as LuaForce ]]
|
||||
local force = player.force --[[@as LuaForce]]
|
||||
local row_data = Elements.stats_table.calculate_row_data(force)
|
||||
for _, stats_table in Elements.stats_table:online_elements(player) do
|
||||
Elements.stats_table.refresh(stats_table, row_data)
|
||||
@@ -359,7 +359,7 @@ Elements.progress_table = Gui.define("rocket_info/progress_table")
|
||||
|
||||
def.data[progress_table] = { rows = {}, no_silos = no_silos }
|
||||
return progress_table
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- @class ExpGui_RocketInfo.elements.progress_table.row_data
|
||||
--- @field entity LuaEntity
|
||||
@@ -404,9 +404,9 @@ end
|
||||
--- @return ExpGui_RocketInfo.elements.progress_table.row_data[]
|
||||
function Elements.progress_table.calculate_row_data_all(silo_data)
|
||||
local row_data = {}
|
||||
for unit_number, silo_data in pairs(silo_data) do
|
||||
if silo_data.entity.valid then
|
||||
row_data[unit_number] = Elements.progress_table.calculate_row_data(silo_data)
|
||||
for unit_number, silo in pairs(silo_data) do
|
||||
if silo.entity.valid then
|
||||
row_data[unit_number] = Elements.progress_table.calculate_row_data(silo)
|
||||
else
|
||||
-- Prune silos that are no longer valid
|
||||
silo_data[unit_number] = nil
|
||||
@@ -433,7 +433,8 @@ function Elements.progress_table.add_row(progress_table, row_data)
|
||||
progress.style.padding = { 0, 2 }
|
||||
progress.style.font_color = row_data.color
|
||||
|
||||
rows[row_data.entity.unit_number] = { x = x, y = y, progress = progress }
|
||||
local unit_number = row_data.entity.unit_number --[[@as uint]]
|
||||
rows[unit_number] = { x = x, y = y, progress = progress }
|
||||
end
|
||||
|
||||
--- Remove a silo row from the progress table
|
||||
@@ -455,7 +456,8 @@ end
|
||||
--- @param row_data ExpGui_RocketInfo.elements.progress_table.row_data
|
||||
function Elements.progress_table.refresh_row(progress_table, row_data)
|
||||
local element_data = Elements.progress_table.data[progress_table]
|
||||
local row = element_data.rows[row_data.entity.unit_number]
|
||||
local unit_number = row_data.entity.unit_number --[[@as uint]]
|
||||
local row = element_data.rows[unit_number]
|
||||
row.x.caption = row_data.x
|
||||
row.y.caption = row_data.y
|
||||
row.progress.caption = row_data.caption
|
||||
@@ -496,7 +498,7 @@ end
|
||||
--- Refresh the progress table for a player, reconciling rows with the current set of silos
|
||||
--- @param player LuaPlayer
|
||||
function Elements.progress_table.refresh_player(player)
|
||||
local force = player.force --[[ @as LuaForce ]]
|
||||
local force = player.force --[[@as LuaForce]]
|
||||
local silos = Elements.container.get_silos(force)
|
||||
local row_data = Elements.progress_table.calculate_row_data_all(silos)
|
||||
for _, progress_table in Elements.progress_table:online_elements(player) do
|
||||
@@ -539,7 +541,7 @@ Elements.container = Gui.define("rocket_info/container")
|
||||
container.style.padding = 0
|
||||
|
||||
local player = Gui.get_player(parent)
|
||||
local force = player.force --[[ @as LuaForce ]]
|
||||
local force = player.force --[[@as LuaForce]]
|
||||
local force_data = def._get_force_data(force)
|
||||
|
||||
if config.stats.show_stats then
|
||||
@@ -618,9 +620,10 @@ end
|
||||
--- Add a silo to the list of current silos for a force
|
||||
--- @param entity LuaEntity
|
||||
function Elements.container.add_silo(entity)
|
||||
local force = entity.force --[[ @as LuaForce ]]
|
||||
local force = entity.force --[[@as LuaForce]]
|
||||
local silos = Elements.container._get_force_data(force).silos
|
||||
silos[entity.unit_number] = {
|
||||
local unit_number = entity.unit_number --[[@as uint]]
|
||||
silos[unit_number] = {
|
||||
entity = entity,
|
||||
launched = 0,
|
||||
awaiting_reset = false,
|
||||
@@ -630,9 +633,11 @@ end
|
||||
--- Increment the launch count for a silo
|
||||
--- @param entity LuaEntity
|
||||
function Elements.container.increment_silo(entity)
|
||||
local force = entity.force --[[ @as LuaForce ]]
|
||||
local force = entity.force --[[@as LuaForce]]
|
||||
local silos = Elements.container._get_force_data(force).silos
|
||||
local silo_data = silos[entity.unit_number]
|
||||
local unit_number = entity.unit_number
|
||||
--- @cast unit_number uint
|
||||
local silo_data = silos[unit_number]
|
||||
if not silo_data then return end
|
||||
silo_data.launched = silo_data.launched + 1
|
||||
silo_data.awaiting_reset = true
|
||||
@@ -653,8 +658,8 @@ Gui.toolbar.create_button{
|
||||
--- Record the launch and update the stats when a cargo pod finishes ascending
|
||||
--- @param event EventData.on_cargo_pod_finished_ascending
|
||||
local function on_cargo_pod_finished_ascending(event)
|
||||
local force = event.cargo_pod.force --[[ @as LuaForce ]]
|
||||
local rockets_launched = force.rockets_launched
|
||||
local force = event.cargo_pod.force --[[@as LuaForce]]
|
||||
local rockets_launched = force.rockets_launched --[[@as number]]
|
||||
|
||||
-- Update the launch stats for the force
|
||||
local stats = Elements.container.get_stats(force)
|
||||
@@ -686,7 +691,7 @@ end
|
||||
--- @param event EventData.on_rocket_launch_ordered
|
||||
local function on_rocket_launch_ordered(event)
|
||||
Elements.container.increment_silo(event.rocket_silo)
|
||||
Elements.progress_table.refresh_force(event.rocket_silo.force --[[ @as LuaForce ]])
|
||||
Elements.progress_table.refresh_force(event.rocket_silo.force --[[@as LuaForce]])
|
||||
end
|
||||
|
||||
--- Refresh the gui when a player joins the game as it may be outdated
|
||||
@@ -704,7 +709,7 @@ local function on_built(event)
|
||||
local entity = event.entity
|
||||
if not entity.valid or entity.name ~= "rocket-silo" then return end
|
||||
Elements.container.add_silo(entity)
|
||||
Elements.progress_table.refresh_force(entity.force --[[ @as LuaForce ]])
|
||||
Elements.progress_table.refresh_force(entity.force --[[@as LuaForce]])
|
||||
end
|
||||
|
||||
--- Refresh the progress for all forces that own at least one silo
|
||||
|
||||
@@ -79,7 +79,7 @@ Elements.production_label = Gui.define("science_production/production_label")
|
||||
|
||||
def.data[label] = suffix
|
||||
return label
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- @class Elements.production_label.display_data
|
||||
--- @field caption LocalisedString
|
||||
@@ -109,7 +109,7 @@ function Elements.production_label.calculate_display_data(tooltip, value, cutoff
|
||||
end
|
||||
|
||||
local suffix, caption = format_number(value)
|
||||
display_data = display_data or {}
|
||||
display_data = display_data or {} --[[@as Elements.production_label.display_data]]
|
||||
display_data.caption = caption
|
||||
display_data.suffix = suffix
|
||||
display_data.tooltip = tooltip
|
||||
@@ -144,12 +144,12 @@ Elements.no_production_label = Gui.define("science_production/no_production_labe
|
||||
padding = { 2, 4 },
|
||||
single_line = false,
|
||||
width = 200,
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- Refresh a no production label
|
||||
--- @param no_production_label LuaGuiElement
|
||||
function Elements.no_production_label.refresh(no_production_label)
|
||||
local force = Gui.get_player(no_production_label).force --[[ @as LuaForce ]]
|
||||
local force = Gui.get_player(no_production_label).force --[[@as LuaForce]]
|
||||
no_production_label.visible = not Elements.container.has_production(force)
|
||||
end
|
||||
|
||||
@@ -157,7 +157,7 @@ end
|
||||
function Elements.no_production_label.refresh_online()
|
||||
local force_data = {}
|
||||
for player, no_production_label in Elements.no_production_label:online_elements() do
|
||||
local force = player.force --[[ @as LuaForce ]]
|
||||
local force = player.force --[[@as LuaForce]]
|
||||
local visible = force_data[force.name]
|
||||
if visible == nil then
|
||||
visible = not Elements.container.has_production(force)
|
||||
@@ -193,10 +193,11 @@ Elements.science_table = Gui.define("science_production/science_table")
|
||||
local science_table = Gui.elements.scroll_table(parent, 190, 4)
|
||||
local no_production_label = Elements.no_production_label(science_table)
|
||||
Elements.no_production_label.refresh(no_production_label)
|
||||
science_table.style.column_alignments[3] = "right"
|
||||
local science_table_style = science_table.style --[[@as LuaStyle]]
|
||||
science_table_style.column_alignments[3] = "right"
|
||||
return science_table
|
||||
end)
|
||||
:element_data{} --[[ @as any ]]
|
||||
:element_data{} --[[@as any]]
|
||||
|
||||
--- Calculate the data needed to add or refresh a row
|
||||
--- @param force LuaForce
|
||||
@@ -220,7 +221,7 @@ function Elements.science_table.calculate_row_data(force, science_pack, row_data
|
||||
end
|
||||
|
||||
-- Return the pack data
|
||||
row_data = row_data or {}
|
||||
row_data = row_data or {} --[[@as ExpGui_ScienceProduction.elements.science_table.row_data]]
|
||||
row_data.visible = production.total.made > 0
|
||||
row_data.science_pack = science_pack
|
||||
row_data.icon_style = icon_style
|
||||
@@ -280,7 +281,8 @@ function Elements.science_table.add_row(science_table, row_data)
|
||||
column_count = 2,
|
||||
}
|
||||
delta_table.style.padding = 0
|
||||
delta_table.style.column_alignments[1] = "right"
|
||||
local delta_table_style = delta_table.style --[[@as LuaStyle]]
|
||||
delta_table_style.column_alignments[1] = "right"
|
||||
|
||||
-- Draw the net production label
|
||||
local net = Elements.production_label(science_table, row_data.net)
|
||||
@@ -312,7 +314,8 @@ function Elements.science_table.refresh_row(science_table, row_data)
|
||||
-- Update the icon
|
||||
local icon = row.icon
|
||||
icon.style = row_data.icon_style
|
||||
icon.style.height = 55
|
||||
local icon_style = icon.style --[[@as LuaStyle]]
|
||||
icon_style.height = 55
|
||||
|
||||
-- Update the element visibility
|
||||
row.net_suffix.visible = true
|
||||
@@ -326,8 +329,7 @@ function Elements.science_table.refresh_row(science_table, row_data)
|
||||
Elements.production_label.refresh(row.used, row_data.used)
|
||||
end
|
||||
|
||||
--- @type table<string, { [string]: ExpGui_ScienceProduction.elements.science_table.row_data }>
|
||||
do local _row_data = {}
|
||||
do local _row_data = {} --- @type table<string, table<number, ExpGui_ScienceProduction.elements.science_table.row_data>>
|
||||
--- Refresh the production tables for all online players
|
||||
function Elements.science_table.refresh_online()
|
||||
-- Refresh the row data for online forces
|
||||
@@ -361,7 +363,7 @@ Elements.eta_label = Gui.define("science_production/eta_label")
|
||||
caption = clock_time_format_nil,
|
||||
tooltip = long_time_format_nil,
|
||||
style = "frame_title",
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- @class Elements.eta_label.display_data
|
||||
--- @field caption LocalisedString
|
||||
@@ -410,14 +412,13 @@ end
|
||||
--- Refresh an eta label
|
||||
--- @param eta_label LuaGuiElement
|
||||
function Elements.eta_label.refresh(eta_label)
|
||||
local force = Gui.get_player(eta_label).force --[[ @as LuaForce ]]
|
||||
local force = Gui.get_player(eta_label).force --[[@as LuaForce]]
|
||||
local display_data = Elements.eta_label.calculate_display_data(force)
|
||||
eta_label.caption = display_data.caption
|
||||
eta_label.tooltip = display_data.tooltip
|
||||
end
|
||||
|
||||
--- @type Elements.eta_label.display_data
|
||||
do local _display_data = {}
|
||||
do local _display_data = {} --- @type table<string, Elements.eta_label.display_data>
|
||||
--- Refresh the eta label for all online players
|
||||
function Elements.eta_label.refresh_online()
|
||||
-- Refresh the row data for online forces
|
||||
@@ -430,8 +431,10 @@ do local _display_data = {}
|
||||
-- Update the eta labels
|
||||
for player, eta_label in Elements.eta_label:online_elements() do
|
||||
local display_data = _display_data[player.force.name]
|
||||
eta_label.caption = display_data.caption
|
||||
eta_label.tooltip = display_data.tooltip
|
||||
if display_data then
|
||||
eta_label.caption = display_data.caption
|
||||
eta_label.tooltip = display_data.tooltip
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -443,7 +446,7 @@ Elements.container = Gui.define("science_production/container")
|
||||
local container = Gui.elements.container(parent)
|
||||
Gui.elements.header(container, { caption = { "exp-gui_science-production.caption-main" } })
|
||||
|
||||
local force = Gui.get_player(parent).force --[[ @as LuaForce ]]
|
||||
local force = Gui.get_player(parent).force --[[@as LuaForce]]
|
||||
local science_table = Elements.science_table(container)
|
||||
for _, science_pack in ipairs(config) do
|
||||
--- @cast science_pack any
|
||||
@@ -462,7 +465,7 @@ Elements.container = Gui.define("science_production/container")
|
||||
end
|
||||
|
||||
return Gui.elements.container.get_root_element(container)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Cached mostly because they are long names
|
||||
local _fp_one_minute = defines.flow_precision_index.one_minute
|
||||
@@ -477,8 +480,7 @@ local _fp_one_hour = defines.flow_precision_index.one_hour
|
||||
--- @field ten_minutes ExpGui_ScienceProduction._item_data
|
||||
--- @field one_hour ExpGui_ScienceProduction._item_data
|
||||
|
||||
--- @type table<string, { [string]: ExpGui_ScienceProduction.item_production_data }>
|
||||
do local _production_data = {}
|
||||
do local _production_data = {} --- @type table<string, { [string]: ExpGui_ScienceProduction.item_production_data }>
|
||||
|
||||
--- Get the production stats for a force
|
||||
--- @param flow_stats any
|
||||
|
||||
@@ -25,7 +25,7 @@ Elements.player_dropdown = Gui.define("surveillance/player_dropdown")
|
||||
local camera = def.data[element]
|
||||
local target_player = assert(ElementsExtra.online_player_dropdown.get_selected(element))
|
||||
Elements.camera.set_target_player(camera, target_player)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Button which sets the target of a camera to the current location
|
||||
--- @class ExpGui_Surveillance.elements.set_location_button: ExpElement
|
||||
@@ -48,7 +48,7 @@ Elements.set_location_button = Gui.define("surveillance/set_location_button")
|
||||
--- @cast def ExpGui_Surveillance.elements.set_location_button
|
||||
local camera = def.data[element]
|
||||
Elements.camera.set_target_position(camera, player.physical_surface_index, player.physical_position)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- @class ExpGui_Surveillance.elements.type_dropdown.data
|
||||
--- @field player_dropdown LuaGuiElement
|
||||
@@ -87,7 +87,7 @@ Elements.type_dropdown = Gui.define("surveillance/type_dropdown")
|
||||
local target_player = ElementsExtra.online_player_dropdown.get_selected(element_data.player_dropdown)
|
||||
Elements.camera.set_target_player(element_data.camera, target_player)
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh all online type dropdowns by cycling the associated player dropdown
|
||||
function Elements.type_dropdown.refresh_online()
|
||||
@@ -131,7 +131,7 @@ Elements.zoom_out_button = Gui.define("surveillance/zoom_out_button")
|
||||
if camera.zoom > 0.2 then
|
||||
camera.zoom = camera.zoom - 0.05
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Buttons which increases zoom by 5%
|
||||
--- @class ExpGui_Surveillance.elements.zoom_in_button: ExpElement
|
||||
@@ -156,7 +156,7 @@ Elements.zoom_in_button = Gui.define("surveillance/zoom_in_button")
|
||||
if camera.zoom < 2.0 then
|
||||
camera.zoom = camera.zoom + 0.05
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Camera which tracks a target with a physical_position and surface_index
|
||||
--- @class ExpGui_Surveillance.elements.camera: ExpElement
|
||||
@@ -176,7 +176,7 @@ Elements.camera = Gui.define("surveillance/camera")
|
||||
}
|
||||
:element_data(
|
||||
Gui.from_argument(1)
|
||||
) --[[ @as any ]]
|
||||
) --[[@as any]]
|
||||
|
||||
--- Set the target player for the camera
|
||||
--- @param camera LuaGuiElement
|
||||
|
||||
@@ -105,7 +105,7 @@ Elements.new_task_button = Gui.define("task_list/new_task_button")
|
||||
body = "",
|
||||
new = true,
|
||||
})
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh the visibility based on player permissions
|
||||
--- @param new_task_button LuaGuiElement
|
||||
@@ -154,7 +154,7 @@ Elements.view_task_button = Gui.define("task_list/view_task_button")
|
||||
--- @cast def ExpGui_TaskList.element.view_task_button
|
||||
local elements = def.data[view_task_button]
|
||||
Elements.container.open_view_task(elements.container, elements.task)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh the title and tooltip of the view task button
|
||||
--- @param view_task_button LuaGuiElement
|
||||
@@ -187,19 +187,19 @@ Elements.no_tasks_header = Gui.define("task_list/no_tasks_header")
|
||||
:style{
|
||||
padding = { 2, 0 },
|
||||
bottom_margin = 0,
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- Refresh the visibility of the no tasks label
|
||||
--- @param no_tasks_header LuaGuiElement
|
||||
function Elements.no_tasks_header.refresh(no_tasks_header)
|
||||
local force = Gui.get_player(no_tasks_header).force --[[ @as LuaForce ]]
|
||||
local force = Gui.get_player(no_tasks_header).force --[[@as LuaForce]]
|
||||
no_tasks_header.visible = not Elements.container.has_tasks(force)
|
||||
end
|
||||
|
||||
--- Refresh the visibility of the no tasks label
|
||||
--- @param player LuaPlayer
|
||||
function Elements.no_tasks_header.refresh_player(player)
|
||||
local visible = not Elements.container.has_tasks(player.force --[[ @as LuaForce ]])
|
||||
local visible = not Elements.container.has_tasks(player.force --[[@as LuaForce]])
|
||||
for _, no_tasks_header in Elements.no_tasks_header:tracked_elements(player) do
|
||||
no_tasks_header.visible = visible
|
||||
end
|
||||
@@ -246,13 +246,13 @@ Elements.task_list = Gui.define("task_list/task_list")
|
||||
|
||||
return task_list
|
||||
end)
|
||||
:element_data{} --[[ @as any ]]
|
||||
:element_data{} --[[@as any]]
|
||||
|
||||
--- Adds a task to the task list
|
||||
--- @param task_list LuaGuiElement
|
||||
--- @param task ExpGui_TaskList.Task
|
||||
function Elements.task_list.add_task(task_list, task)
|
||||
local container = assert(task_list.parent.parent.parent)
|
||||
local container = assert(assert(assert(task_list.parent).parent).parent)
|
||||
local view_task_buttons = Elements.task_list.data[task_list]
|
||||
view_task_buttons[task.id] = Elements.view_task_button(task_list, task, container)
|
||||
end
|
||||
@@ -330,7 +330,7 @@ Elements.task_footer = Gui.define("task_list/task_footer")
|
||||
height = 0,
|
||||
padding = 5,
|
||||
use_header_filler = false,
|
||||
} --[[ @as any ]]
|
||||
} --[[@as any]]
|
||||
|
||||
--- @class ExpGui_TaskList.elements.close_task_button.elements
|
||||
--- @field container LuaGuiElement
|
||||
@@ -354,7 +354,7 @@ Elements.close_task_button = Gui.define("task_list/close_task_button")
|
||||
--- @cast def ExpGui_TaskList.element.close_task_button
|
||||
local elements = def.data[close_task_button]
|
||||
Elements.container.close_footers(elements.container)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- @class ExpGui_TaskList.elements.task_button.elements
|
||||
--- @field task ExpGui_TaskList.Task?
|
||||
@@ -379,7 +379,7 @@ Elements.edit_task_button = Gui.define("task_list/edit_task_button")
|
||||
--- @cast def ExpGui_TaskList.element.edit_task_button
|
||||
local elements = def.data[edit_task_button]
|
||||
Elements.container.open_edit_task(elements.container, assert(elements.task))
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh the edit button
|
||||
--- @param edit_task_button LuaGuiElement
|
||||
@@ -415,9 +415,9 @@ Elements.delete_task_button = Gui.define("task_list/delete_task_button")
|
||||
:on_click(function(def, player, delete_task_button)
|
||||
--- @cast def ExpGui_TaskList.element.delete_task_button
|
||||
local elements = def.data[delete_task_button]
|
||||
Elements.container.remove_task(player.force --[[ @as LuaForce ]], elements.task)
|
||||
Elements.container.remove_task(player.force --[[@as LuaForce]], elements.task)
|
||||
Elements.container.close_footers(elements.container)
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh the delete button
|
||||
--- @param delete_task_button LuaGuiElement
|
||||
@@ -477,7 +477,7 @@ Elements.view_task_footer = Gui.define("task_list/view_task_footer")
|
||||
}
|
||||
|
||||
return view_task_footer
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh the view task with new task details
|
||||
--- @param view_task_footer LuaGuiElement
|
||||
@@ -532,9 +532,9 @@ Elements.task_message_textfield = Gui.define("task_list/task_message_textfield")
|
||||
}
|
||||
:on_text_changed(function(def, player, task_message_textfield)
|
||||
--- @cast def ExpGui_TaskList.elements.task_message_textfield
|
||||
local confirm_task_button = def.data[task_message_textfield].confirm_task_button
|
||||
local confirm_task_button = assert(def.data[task_message_textfield].confirm_task_button)
|
||||
confirm_task_button.enabled = string.len(task_message_textfield.text) > 5
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Set the confirm task button to update on text changed
|
||||
--- @param task_message_textfield LuaGuiElement
|
||||
@@ -549,7 +549,7 @@ end
|
||||
function Elements.task_message_textfield.refresh(task_message_textfield, task)
|
||||
local elements = Elements.task_message_textfield.data[task_message_textfield]
|
||||
local message = task.new and "" or task.title .. "\n" .. task.body
|
||||
elements.confirm_task_button.enabled = string.len(message) > 5
|
||||
assert(elements.confirm_task_button).enabled = string.len(message) > 5
|
||||
task_message_textfield.text = message
|
||||
task_message_textfield.focus()
|
||||
end
|
||||
@@ -590,13 +590,13 @@ Elements.confirm_task_button = Gui.define("task_list/confirm_task_button")
|
||||
|
||||
Elements.container.close_footers(elements.container)
|
||||
|
||||
local force = player.force --[[ @as LuaForce ]]
|
||||
local force = player.force --[[@as LuaForce]]
|
||||
if task.new then
|
||||
Elements.container.add_task(force, task)
|
||||
else
|
||||
Elements.container.refresh_force_online(force, task)
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh the confirm task button
|
||||
--- @param confirm_task_button LuaGuiElement
|
||||
@@ -612,7 +612,7 @@ function Elements.confirm_task_button.parse(message)
|
||||
-- Trim the spaces of the string
|
||||
local trimmed = string.gsub(message, "^%s*(.-)%s*$", "%1")
|
||||
local title, body = string.match(trimmed, "(.-)\n(.*)")
|
||||
local parsed = { title = title, body = body }
|
||||
local parsed = { title = title, body = body } --[[@as { title: string, body: string }]]
|
||||
if not title then
|
||||
-- If it doesn't match the pattern return the str as a title
|
||||
parsed.title = trimmed
|
||||
@@ -649,7 +649,7 @@ Elements.discard_task_button = Gui.define("task_list/discard_task_button")
|
||||
else
|
||||
Elements.container.open_view_task(elements.container, task)
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh the discard task button
|
||||
--- @param discard_task_button LuaGuiElement
|
||||
@@ -696,7 +696,7 @@ Elements.edit_task_footer = Gui.define("task_list/edit_task_footer")
|
||||
}
|
||||
|
||||
return edit_task_footer
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh the view task with new task details
|
||||
--- @param edit_task_footer LuaGuiElement
|
||||
@@ -755,9 +755,14 @@ end
|
||||
--- @field view_task_footer LuaGuiElement
|
||||
--- @field edit_task_footer LuaGuiElement
|
||||
|
||||
--- @class ExpGui_TaskList.elements.container.data
|
||||
--- @field global_data { next_task_id: number }
|
||||
--- @field [LuaGuiElement] ExpGui_TaskList.elements.container.elements
|
||||
--- @field [LuaForce] ExpGui_TaskList.Task[]
|
||||
|
||||
--- Container added to the left gui flow
|
||||
--- @class ExpGui_TaskList.elements.container: ExpElement
|
||||
--- @field data table<LuaForce, ExpGui_TaskList.Task[]> | table<LuaGuiElement, ExpGui_TaskList.elements.container.elements> | table<"global_data", { next_task_id: number }>
|
||||
--- @field data ExpGui_TaskList.elements.container.data
|
||||
Elements.container = Gui.define("task_list/container")
|
||||
:track_all_elements()
|
||||
:draw(function(def, parent)
|
||||
@@ -781,7 +786,7 @@ Elements.container = Gui.define("task_list/container")
|
||||
|
||||
-- Add tasks to the list if there are any
|
||||
local player = Gui.get_player(parent)
|
||||
local force = player.force --[[ @as LuaForce ]]
|
||||
local force = player.force --[[@as LuaForce]]
|
||||
local tasks = def.data[force]
|
||||
if tasks then
|
||||
for _, task in ipairs(tasks) do
|
||||
@@ -796,11 +801,11 @@ Elements.container = Gui.define("task_list/container")
|
||||
elements.edit_task_footer.visible = false
|
||||
|
||||
-- Set the data and return
|
||||
def.data[root] = elements --[[ @as any ]]
|
||||
def.data[root] = elements --[[@as any]]
|
||||
return root
|
||||
end)
|
||||
:global_data{ next_task_id = 1 }
|
||||
:force_data{} --[[ @as any ]]
|
||||
:force_data{} --[[@as any]]
|
||||
|
||||
--- Check if a force has tasks
|
||||
--- @param force LuaForce
|
||||
@@ -885,7 +890,7 @@ end
|
||||
--- Refresh all tasks for a player
|
||||
--- @param player LuaPlayer
|
||||
function Elements.container.refresh_player(player)
|
||||
local tasks = Elements.container.data[ player.force --[[ @as LuaForce ]] ]
|
||||
local tasks = Elements.container.data[ player.force --[[@as LuaForce]] ]
|
||||
for _, container in Elements.container:tracked_elements(player) do
|
||||
local elements = Elements.container.data[container]
|
||||
Elements.task_list.refresh_tasks(elements.task_list, tasks)
|
||||
@@ -908,7 +913,7 @@ end
|
||||
|
||||
--- Add the element to the left flow with a toolbar button
|
||||
Gui.add_left_element(Elements.container, function(player)
|
||||
return Elements.container.has_tasks(player.force --[[ @as LuaForce ]])
|
||||
return Elements.container.has_tasks(player.force --[[@as LuaForce]])
|
||||
end)
|
||||
|
||||
Gui.toolbar.create_button{
|
||||
|
||||
@@ -42,7 +42,7 @@ Elements.server_ups = Gui.define("server_ups")
|
||||
if not existing or not existing.valid then
|
||||
def.data[player] = element -- Only set if previous is invalid
|
||||
end
|
||||
end) --[[ @as any ]]
|
||||
end) --[[@as any]]
|
||||
|
||||
--- Refresh the caption for all online players
|
||||
--- @param ups number The UPS to be displayed
|
||||
|
||||
+18
-18
@@ -11,22 +11,22 @@ local max = math.max
|
||||
local AABB = {}
|
||||
|
||||
--- Check if an area is valid
|
||||
--- @param aabb BoundingBox
|
||||
--- @param aabb BoundingBox.struct
|
||||
--- @return boolean # True if the area is valid
|
||||
function AABB.valid(aabb)
|
||||
return aabb.left_top.x < aabb.right_bottom.x and aabb.left_top.y < aabb.right_bottom.y
|
||||
end
|
||||
|
||||
--- Returns the size of the area contained within an AABB
|
||||
--- @param aabb BoundingBox
|
||||
--- @param aabb BoundingBox.struct
|
||||
--- @return number
|
||||
function AABB.size(aabb)
|
||||
return (aabb.right_bottom.x - aabb.left_top.x) * (aabb.right_bottom.y - aabb.left_top.y)
|
||||
end
|
||||
|
||||
--- Clone an area, allows for safe mutation of an input value
|
||||
--- @param aabb BoundingBox
|
||||
--- @return BoundingBox
|
||||
--- @param aabb BoundingBox.struct
|
||||
--- @return BoundingBox.struct
|
||||
function AABB.clone(aabb)
|
||||
return {
|
||||
left_top = { x = aabb.left_top.x, y = aabb.left_top.y },
|
||||
@@ -35,8 +35,8 @@ function AABB.clone(aabb)
|
||||
end
|
||||
|
||||
--- Expand an area to be integer aligned, expanding away from 0
|
||||
--- @param aabb BoundingBox
|
||||
--- @return BoundingBox
|
||||
--- @param aabb BoundingBox.struct
|
||||
--- @return BoundingBox.struct
|
||||
function AABB.expand(aabb)
|
||||
return {
|
||||
left_top = { x = floor(aabb.left_top.x), y = floor(aabb.left_top.y) },
|
||||
@@ -45,8 +45,8 @@ function AABB.expand(aabb)
|
||||
end
|
||||
|
||||
--- Contract an area to be integer aligned, contracting towards 0
|
||||
--- @param aabb BoundingBox
|
||||
--- @return BoundingBox
|
||||
--- @param aabb BoundingBox.struct
|
||||
--- @return BoundingBox.struct
|
||||
function AABB.contract(aabb)
|
||||
return {
|
||||
left_top = { x = ceil(aabb.left_top.x), y = ceil(aabb.left_top.y) },
|
||||
@@ -55,9 +55,9 @@ function AABB.contract(aabb)
|
||||
end
|
||||
|
||||
--- Expand an area to include all other areas
|
||||
--- @param aabb BoundingBox
|
||||
--- @param ... BoundingBox
|
||||
--- @return BoundingBox
|
||||
--- @param aabb BoundingBox.struct
|
||||
--- @param ... BoundingBox.struct
|
||||
--- @return BoundingBox.struct
|
||||
function AABB.union(aabb, ...)
|
||||
local rtn = AABB.clone(aabb)
|
||||
for _, next_aabb in ipairs{ ... } do
|
||||
@@ -70,9 +70,9 @@ function AABB.union(aabb, ...)
|
||||
end
|
||||
|
||||
--- Contract an area to include to the overlap of all areas
|
||||
--- @param aabb BoundingBox
|
||||
--- @param ... BoundingBox
|
||||
--- @return BoundingBox? # Nil if there is no intersection
|
||||
--- @param aabb BoundingBox.struct
|
||||
--- @param ... BoundingBox.struct
|
||||
--- @return BoundingBox.struct? # Nil if there is no intersection
|
||||
function AABB.intersect(aabb, ...)
|
||||
local rtn = AABB.clone(aabb)
|
||||
for _, next_aabb in ipairs{ ... } do
|
||||
@@ -88,8 +88,8 @@ function AABB.intersect(aabb, ...)
|
||||
end
|
||||
|
||||
--- Check if a point is contained within an area
|
||||
--- @param aabb BoundingBox
|
||||
--- @param point MapPosition
|
||||
--- @param aabb BoundingBox.struct
|
||||
--- @param point MapPosition.struct
|
||||
--- @return boolean # True if the point is within or on the edge of the bounding box
|
||||
function AABB.contains_point(aabb, point)
|
||||
return point.x >= aabb.left_top.x and point.y >= aabb.left_top.y
|
||||
@@ -97,8 +97,8 @@ function AABB.contains_point(aabb, point)
|
||||
end
|
||||
|
||||
--- Check if an area is fulling contained within another area
|
||||
--- @param aabb BoundingBox
|
||||
--- @param other BoundingBox
|
||||
--- @param aabb BoundingBox.struct
|
||||
--- @param other BoundingBox.struct
|
||||
--- @return boolean # True if the point is within or on the edge of the bounding box
|
||||
function AABB.contains_area(aabb, other)
|
||||
return AABB.contains_point(aabb, other.left_top) and AABB.contains_point(aabb, other.right_bottom)
|
||||
|
||||
+18
-21
@@ -93,8 +93,8 @@ local Async = {
|
||||
Async.status = {}
|
||||
|
||||
--- @class Async.AsyncFunction
|
||||
--- @field id number The id of this async function
|
||||
--- @operator call: Async.AsyncReturn
|
||||
--- @field id string The id of this async function
|
||||
--- @overload fun(...: any): Async.AsyncReturn<any>
|
||||
Async._function_prototype = {}
|
||||
|
||||
Async._function_metatable = {
|
||||
@@ -104,10 +104,10 @@ Async._function_metatable = {
|
||||
}
|
||||
|
||||
--- @class Async.AsyncReturn<F>
|
||||
--- @field func_id number The id of the async function to be called
|
||||
--- @field func_id string The id of the async function to be called
|
||||
--- @field args any[] The arguments to call the function with
|
||||
--- @field tick number? If present, the function will be called on this game tick
|
||||
--- @field next_id number? The id of the async function to be called with the return value
|
||||
--- @field next_id string? The id of the async function to be called with the return value
|
||||
--- @field canceled boolean? True if the call has been canceled
|
||||
--- @field completed boolean? True if the call has completed
|
||||
--- @field return_values any? The return values of the function call
|
||||
@@ -123,20 +123,20 @@ script.register_metatable("AsyncReturn", Async._return_metatable)
|
||||
|
||||
--- Storage Variables
|
||||
|
||||
local resolve_next --- @type Async.AsyncReturn[] Stores a queue of async functions to be executed on the next tick
|
||||
local resolve_queue --- @type Async.AsyncReturn[] Stores a queue of async functions to be executed on a later tick
|
||||
local resolve_next --- @type Async.AsyncReturn<any>[] Stores a queue of async functions to be executed on the next tick
|
||||
local resolve_queue --- @type Async.AsyncReturn<any>[] Stores a queue of async functions to be executed on a later tick
|
||||
|
||||
--- Insert an item into the priority queue
|
||||
--- @param pending Async.AsyncReturn
|
||||
--- @return Async.AsyncReturn
|
||||
--- @param pending Async.AsyncReturn<any>
|
||||
--- @return Async.AsyncReturn<any>
|
||||
local function add_to_next_tick(pending)
|
||||
resolve_next[#resolve_next + 1] = pending
|
||||
return pending
|
||||
end
|
||||
|
||||
--- Insert an item into the priority queue
|
||||
--- @param pending Async.AsyncReturn
|
||||
--- @return Async.AsyncReturn
|
||||
--- @param pending Async.AsyncReturn<any>
|
||||
--- @return Async.AsyncReturn<any>
|
||||
local function add_to_resolve_queue(pending)
|
||||
local tick = pending.tick
|
||||
for index = #resolve_queue, 1, -1 do
|
||||
@@ -191,7 +191,7 @@ end
|
||||
|
||||
--- Run an async function on the next tick, this is the default and can be used to bypass permission groups
|
||||
--- @param ... any The arguments to call the function with
|
||||
--- @return Async.AsyncReturn
|
||||
--- @return Async.AsyncReturn<any>
|
||||
function Async._function_prototype:start_soon(...)
|
||||
assert(Async._registered[self.id], "Async function is not registered")
|
||||
Async._queue_pressure[self.id] = Async._queue_pressure[self.id] + 1
|
||||
@@ -204,7 +204,7 @@ end
|
||||
--- Run an async function after the given number of ticks
|
||||
--- @param ticks number The number of ticks to call the function after
|
||||
--- @param ... any The arguments to call the function with
|
||||
--- @return Async.AsyncReturn
|
||||
--- @return Async.AsyncReturn<any>
|
||||
function Async._function_prototype:start_after(ticks, ...)
|
||||
ExpUtil.assert_argument_type(ticks, "number", 1, "ticks")
|
||||
assert(ticks > 0, "Ticks must be a positive number")
|
||||
@@ -219,7 +219,7 @@ end
|
||||
|
||||
--- Run an async function on the next tick if the function is not already queued, allows singleton task/thread behaviour
|
||||
--- @param ... any The arguments to call the function with
|
||||
--- @return Async.AsyncReturn | nil
|
||||
--- @return Async.AsyncReturn<any> | nil
|
||||
function Async._function_prototype:start_task(...)
|
||||
assert(Async._registered[self.id], "Async function is not registered")
|
||||
if Async._queue_pressure[self.id] > 0 then return end
|
||||
@@ -228,7 +228,7 @@ end
|
||||
|
||||
--- Run an async function on this tick, then queue it based on its return value
|
||||
--- @param ... any The arguments to call the function with
|
||||
--- @return Async.AsyncReturn
|
||||
--- @return Async.AsyncReturn<any>
|
||||
function Async._function_prototype:start_now(...)
|
||||
assert(Async._registered[self.id], "Async function is not registered")
|
||||
local status, rtn1, rtn2 = Async._registered[self.id](...)
|
||||
@@ -261,7 +261,6 @@ local empty_table = setmetatable({}, {
|
||||
--- Default status, will raise on_function_complete
|
||||
--- @param ... any The return value of the async call
|
||||
--- @return Async.Status, any[]
|
||||
--- @type Async.Status
|
||||
function Async.status.complete(...)
|
||||
if ... == nil then
|
||||
return Async.status.complete, empty_table
|
||||
@@ -272,7 +271,6 @@ end
|
||||
--- Will queue the function to be called again on the next tick using the new arguments
|
||||
--- @param ... any The arguments to call the function with
|
||||
--- @return Async.Status, any[]
|
||||
--- @type Async.Status
|
||||
function Async.status.continue(...)
|
||||
if ... == nil then
|
||||
return Async.status.continue, empty_table
|
||||
@@ -284,7 +282,6 @@ end
|
||||
--- @param ticks number The number of ticks to delay for
|
||||
--- @param ... any The arguments to call the function with
|
||||
--- @return Async.Status, number, any[]
|
||||
--- @type Async.Status
|
||||
function Async.status.delay(ticks, ...)
|
||||
ExpUtil.assert_argument_type(ticks, "number", 1, "ticks")
|
||||
assert(ticks > 0, "Ticks must be a positive number")
|
||||
@@ -296,11 +293,11 @@ end
|
||||
|
||||
--- Status Returns.
|
||||
|
||||
--- @type Async.AsyncReturn[], Async.AsyncReturn[]
|
||||
--- @type Async.AsyncReturn<any>[], Async.AsyncReturn<any>[]
|
||||
local new_next, new_queue = {}, {} -- File scope to allow for reuse
|
||||
|
||||
--- Executes an async function and processes the return value
|
||||
--- @param pending Async.AsyncReturn
|
||||
--- @param pending Async.AsyncReturn<any>
|
||||
--- @param tick number
|
||||
local function exec(pending, tick)
|
||||
local async_func = Async._registered[pending.func_id]
|
||||
@@ -400,9 +397,9 @@ end
|
||||
--- @package
|
||||
function Async.on_init()
|
||||
if storage.exp_async_next == nil then
|
||||
--- @type Async.AsyncReturn[]
|
||||
--- @type Async.AsyncReturn<any>[]
|
||||
storage.exp_async_next = {}
|
||||
--- @type Async.AsyncReturn[]
|
||||
--- @type Async.AsyncReturn<any>[]
|
||||
storage.exp_async_queue = {}
|
||||
end
|
||||
Async.on_load()
|
||||
|
||||
@@ -42,12 +42,14 @@ end
|
||||
--- @param options FlyingText.create_above_entity_param
|
||||
function FlyingText.create_above_entity(options)
|
||||
local entity = assert(options.target_entity, "A target entity is required")
|
||||
local size_y = entity.bounding_box.left_top.y - entity.bounding_box.right_bottom.y
|
||||
local bounding_box = entity.bounding_box
|
||||
local size_y = bounding_box.left_top.y - bounding_box.right_bottom.y
|
||||
local position = entity.position
|
||||
local offset = options.offset or { x = 0, y = 0 }
|
||||
|
||||
options.position = {
|
||||
x = offset.x + entity.position.x,
|
||||
y = offset.y + entity.position.y + size_y * 0.25,
|
||||
x = offset.x + position.x,
|
||||
y = offset.y + position.y + size_y * 0.25,
|
||||
}
|
||||
|
||||
FlyingText.create(options)
|
||||
@@ -62,12 +64,14 @@ end
|
||||
function FlyingText.create_above_player(options)
|
||||
local player = assert(options.target_player, "A target player is required")
|
||||
local entity = player.character; if not entity then return end
|
||||
local size_y = entity.bounding_box.left_top.y - entity.bounding_box.right_bottom.y
|
||||
local bounding_box = entity.bounding_box
|
||||
local size_y = bounding_box.left_top.y - bounding_box.right_bottom.y
|
||||
local position = entity.position
|
||||
local offset = options.offset or { x = 0, y = 0 }
|
||||
|
||||
options.position = {
|
||||
x = offset.x + entity.position.x,
|
||||
y = offset.y + entity.position.y + size_y * 0.25,
|
||||
x = offset.x + position.x,
|
||||
y = offset.y + position.y + size_y * 0.25,
|
||||
}
|
||||
|
||||
FlyingText.create(options)
|
||||
@@ -82,13 +86,15 @@ end
|
||||
function FlyingText.create_as_player(options)
|
||||
local player = assert(options.target_player, "A target player is required")
|
||||
local entity = player.character; if not entity then return end
|
||||
local size_y = entity.bounding_box.left_top.y - entity.bounding_box.right_bottom.y
|
||||
local bounding_box = entity.bounding_box
|
||||
local size_y = bounding_box.left_top.y - bounding_box.right_bottom.y
|
||||
local position = entity.position
|
||||
local offset = options.offset or { x = 0, y = 0 }
|
||||
|
||||
options.color = player.chat_color
|
||||
options.position = {
|
||||
x = offset.x + entity.position.x,
|
||||
y = offset.y + entity.position.y + size_y * 0.25,
|
||||
x = offset.x + position.x,
|
||||
y = offset.y + position.y + size_y * 0.25,
|
||||
}
|
||||
|
||||
FlyingText.create(options)
|
||||
|
||||
@@ -92,7 +92,7 @@ local assert_argument_fmt = "Bad argument #%d to %s; %s expected to be of type %
|
||||
function ExpUtil.assert_argument_type(arg_value, type_name, arg_index, arg_name)
|
||||
local failed, actual_type = check_type(arg_value, type_name)
|
||||
if failed then
|
||||
local func_name = getinfo(2, "n").name or "<anonymous>"
|
||||
local func_name = assert(getinfo(2, "n")).name or "<anonymous>"
|
||||
error(assert_argument_fmt:format(arg_index, func_name, arg_name or "Argument", type_name, actual_type), 2)
|
||||
end
|
||||
end
|
||||
@@ -136,7 +136,7 @@ end
|
||||
--- @param level number? The level of the stack to get the file of, a value of 1 is the caller of this function
|
||||
--- @return string # The relative filepath of the given stack frame
|
||||
function ExpUtil.safe_file_path(level)
|
||||
local debug_info = getinfo((level or 1) + 1, "Sn")
|
||||
local debug_info = assert(getinfo((level or 1) + 1, "Sn"))
|
||||
local safe_source = debug_info.source:find("@__level__")
|
||||
return safe_source == 1 and debug_info.short_src:sub(10, -5) or debug_info.source
|
||||
end
|
||||
@@ -145,7 +145,7 @@ end
|
||||
--- @param level number? The level of the stack to get the module of, a value of 1 is the caller of this function
|
||||
--- @return string # The name of the module at the given stack frame
|
||||
function ExpUtil.get_module_name(level)
|
||||
local file_within_module = getinfo((level or 1) + 1, "S").short_src:sub(19, -5)
|
||||
local file_within_module = assert(getinfo((level or 1) + 1, "S")).short_src:sub(19, -5)
|
||||
local next_slash = file_within_module:find("/")
|
||||
if next_slash then
|
||||
return file_within_module:sub(1, next_slash - 1)
|
||||
@@ -159,7 +159,7 @@ end
|
||||
--- @param raw boolean? When true there will not be any < > around the name
|
||||
--- @return string # The name of the function at the given stack frame or provided as an argument
|
||||
function ExpUtil.get_function_name(func, raw)
|
||||
local debug_info = getinfo(func, "Sn")
|
||||
local debug_info = assert(getinfo(func, "Sn"))
|
||||
local safe_source = debug_info.source:find("@__level__")
|
||||
local file_name = safe_source == 1 and debug_info.source:sub(12, -5) or debug_info.source
|
||||
local func_name = debug_info.name or debug_info.linedefined
|
||||
@@ -172,7 +172,7 @@ end
|
||||
--- @param raw boolean? When true there will not be any < > around the name
|
||||
--- @return string # The relative filepath of the given stack frame
|
||||
function ExpUtil.get_current_line(level, raw)
|
||||
local debug_info = getinfo((level or 1) + 1, "Snl")
|
||||
local debug_info = assert(getinfo((level or 1) + 1, "Snl"))
|
||||
local safe_source = debug_info.source:find("@__level__")
|
||||
local file_path = safe_source == 1 and debug_info.short_src:sub(10, -5) or debug_info.source
|
||||
if raw then return file_path .. ":" .. debug_info.currentline end
|
||||
@@ -207,7 +207,7 @@ end
|
||||
function ExpUtil.auto_complete(options, input, use_key, rtn_key, use_pattern)
|
||||
input = input:lower()
|
||||
local plain = use_pattern ~= true
|
||||
local found = {} --- @type { length: number, index: number, start: boolean, value: any }
|
||||
local found = {} --- @type { length: number?, index: number?, start: boolean?, value: any }
|
||||
for k, v in pairs(options) do
|
||||
local str = use_key and k or v
|
||||
local index = str:lower():find(input, nil, plain)
|
||||
@@ -284,7 +284,7 @@ function ExpUtil.format_any(value, options)
|
||||
end
|
||||
return inspect(value, { depth = options.depth or 5, indent = "", newline = "", process = ExpUtil.safe_value })
|
||||
end
|
||||
return formatted
|
||||
return formatted --[[@as LocalisedString]]
|
||||
end
|
||||
|
||||
--- @alias Common.format_time_param_format "short" | "long" | "clock"
|
||||
@@ -319,15 +319,15 @@ function ExpUtil.extract_time_units(ticks, units)
|
||||
|
||||
-- Remove units that are not requested
|
||||
if not units.days then
|
||||
rtn.hours = rtn.hours + rtn.days * 24
|
||||
rtn.hours = assert(rtn.hours) + assert(rtn.days) * 24
|
||||
rtn.days = nil
|
||||
end
|
||||
if not units.hours then
|
||||
rtn.minutes = rtn.minutes + rtn.hours * 60
|
||||
rtn.minutes = assert(rtn.minutes) + assert(rtn.hours) * 60
|
||||
rtn.hours = nil
|
||||
end
|
||||
if not units.minutes then
|
||||
rtn.seconds = rtn.seconds + rtn.minutes * 60
|
||||
rtn.seconds = assert(rtn.seconds) + assert(rtn.minutes) * 60
|
||||
rtn.minutes = nil
|
||||
end
|
||||
if not units.seconds then
|
||||
@@ -487,7 +487,7 @@ function ExpUtil.get_storage_for_stack(options)
|
||||
-- Find a valid entity from the search results
|
||||
local current, count, entities = cache.current, cache.count, cache.entities
|
||||
for i = 1, cache.count do
|
||||
local entity = entities[((current + i - 1) % count) + 1]
|
||||
local entity = assert(entities[((current + i - 1) % count) + 1])
|
||||
if entity.can_insert(item) then
|
||||
cache.current = current + 1
|
||||
return entity
|
||||
@@ -522,7 +522,7 @@ end
|
||||
|
||||
--- Insert a copy of the given items into the found entities. If no entities are found then they will be created if possible.
|
||||
--- @param options Common.copy_items_to_surface_param
|
||||
--- @return LuaEntity # The last entity inserted into
|
||||
--- @return LuaEntity? # The last entity inserted into, nil if there were no items
|
||||
function ExpUtil.copy_items_to_surface(options)
|
||||
local entity
|
||||
for item_index = 1, #options.items do
|
||||
@@ -542,7 +542,7 @@ end
|
||||
|
||||
--- Insert a copy of the given items into the found entities. If no entities are found then they will be created if possible.
|
||||
--- @param options Common.move_items_to_surface_param
|
||||
--- @return LuaEntity # The last entity inserted into
|
||||
--- @return LuaEntity? # The last entity inserted into, nil if there were no items
|
||||
function ExpUtil.move_items_to_surface(options)
|
||||
local entity
|
||||
for item_index = 1, #options.items do
|
||||
@@ -551,7 +551,8 @@ function ExpUtil.move_items_to_surface(options)
|
||||
options.item = item
|
||||
entity = ExpUtil.get_storage_for_stack(options)
|
||||
entity.insert(options.item)
|
||||
options.item.clear()
|
||||
local item_stack = options.item --[[@as LuaItemStack]]
|
||||
item_stack.clear()
|
||||
end
|
||||
end
|
||||
return entity
|
||||
@@ -563,7 +564,7 @@ end
|
||||
|
||||
--- Move the given inventory into the found entities. If no entities are found then they will be created if possible.
|
||||
--- @param options Common.transfer_inventory_to_surface_param
|
||||
--- @return LuaEntity # The last entity inserted into
|
||||
--- @return LuaEntity? # The last entity inserted into, nil if there were no items
|
||||
function ExpUtil.transfer_inventory_to_surface(options)
|
||||
options.items = options.inventory
|
||||
local entity = ExpUtil.copy_items_to_surface(options)
|
||||
@@ -604,6 +605,7 @@ end
|
||||
--- @return string
|
||||
function ExpUtil.comma_value(n) -- credit http://richard.warburton.it
|
||||
local left, num, right = string.match(n, "^([^%d]*%d)(%d*)(.-)$")
|
||||
assert(left and num and right)
|
||||
return left .. (num:reverse():gsub("(%d%d%d)", "%1, "):reverse()) .. right
|
||||
end
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ local Selection = {
|
||||
--- @field player_index number
|
||||
--- @field selection Selection.Active
|
||||
|
||||
--- @type table<string, { [defines.events]: Selection.event_handler[] }>
|
||||
--- @type table<string, { [defines.events]: Selection.event_handler<any>[] }>
|
||||
_registered = {},
|
||||
|
||||
--- @package
|
||||
@@ -54,7 +54,7 @@ local selection_tool = { name = "selection-tool" }
|
||||
--- @param player LuaPlayer
|
||||
--- @return boolean?
|
||||
local function has_selection_tool_in_hand(player)
|
||||
return player.cursor_stack and player.cursor_stack.valid_for_read and player.cursor_stack.name == "selection-tool"
|
||||
return assert(player.cursor_stack) and assert(player.cursor_stack).valid_for_read and assert(player.cursor_stack).name == "selection-tool"
|
||||
end
|
||||
|
||||
--- Give a selection tool to a player if they don't have one
|
||||
@@ -62,7 +62,7 @@ end
|
||||
local function give_selection_tool(player)
|
||||
if has_selection_tool_in_hand(player) then return end
|
||||
player.clear_cursor()
|
||||
player.cursor_stack.set_stack(selection_tool)
|
||||
assert(player.cursor_stack).set_stack(selection_tool)
|
||||
|
||||
-- This does not work for selection planners, will make a feature request for it
|
||||
--player.cursor_stack_temporary = true
|
||||
@@ -84,7 +84,7 @@ end
|
||||
local function remove_selection_tool(player, old_character)
|
||||
-- Remove the selection tool
|
||||
if has_selection_tool_in_hand(player) then
|
||||
player.cursor_stack.clear()
|
||||
assert(player.cursor_stack).clear()
|
||||
else
|
||||
player.remove_item(selection_tool)
|
||||
end
|
||||
|
||||
+6
-37
@@ -1,39 +1,8 @@
|
||||
---@meta
|
||||
|
||||
---@class script
|
||||
script = {
|
||||
---Raise an event. Only events generated with [LuaBootstrap::generate\_event\_name](https://lua-api.factorio.com/latest/classes/LuaBootstrap.html#generate_event_name) and the following can be raised:
|
||||
---
|
||||
---Events that can be raised manually:
|
||||
---
|
||||
---* [on\_console\_chat](https://lua-api.factorio.com/latest/events.html#on_console_chat)
|
||||
---* [on\_player\_crafted\_item](https://lua-api.factorio.com/latest/events.html#on_player_crafted_item)
|
||||
---* [on\_player\_fast\_transferred](https://lua-api.factorio.com/latest/events.html#on_player_fast_transferred)
|
||||
---* [on\_biter\_base\_built](https://lua-api.factorio.com/latest/events.html#on_biter_base_built)
|
||||
---* [on\_market\_item\_purchased](https://lua-api.factorio.com/latest/events.html#on_market_item_purchased)
|
||||
---* [script\_raised\_built](https://lua-api.factorio.com/latest/events.html#script_raised_built)
|
||||
---* [script\_raised\_destroy](https://lua-api.factorio.com/latest/events.html#script_raised_destroy)
|
||||
---* [script\_raised\_revive](https://lua-api.factorio.com/latest/events.html#script_raised_revive)
|
||||
---* [script\_raised\_teleported](https://lua-api.factorio.com/latest/events.html#script_raised_teleported)
|
||||
---* [script\_raised\_set\_tiles](https://lua-api.factorio.com/latest/events.html#script_raised_set_tiles)
|
||||
---
|
||||
---### Example
|
||||
---
|
||||
---```
|
||||
----- Raise the on_console_chat event with the desired message 'from' the first player
|
||||
---local data = {player_index = 1, message = "Hello friends!"}
|
||||
---script.raise_event(defines.events.on_console_chat, data)
|
||||
---```
|
||||
---
|
||||
---[View Documentation](https://lua-api.factorio.com/latest/classes/LuaBootstrap.html#raise_event)
|
||||
---
|
||||
--- Type patched in 2.0.28: [Bug Report](https://forums.factorio.com/viewtopic.php?f=233&t=125062)
|
||||
--- Changed "event" from "string | integer" to "LuaEventType"
|
||||
--- Resolved in 2.0.29, this patch will be removed was version is stable
|
||||
---@param event LuaEventType ID or name of the event to raise.
|
||||
---@param data table Table with extra data that will be passed to the event handler. Any invalid LuaObjects will silently stop the event from being raised.
|
||||
raise_event = function(event, data) end;
|
||||
}
|
||||
|
||||
---@class LuaObject:userdata
|
||||
--https://github.com/justarandomgeek/vscode-factoriomod-debug/issues/165
|
||||
--- The api documents MapPosition and BoundingBox as a union of the named form
|
||||
--- and a positional array, because both are accepted as input. Everything read
|
||||
--- back from the game uses the named form, and we always write it that way too,
|
||||
--- so the positional variant is removed here.
|
||||
---@alias MapPosition MapPosition.struct
|
||||
---@alias BoundingBox BoundingBox.struct
|
||||
|
||||
Reference in New Issue
Block a user