mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-09-21 17:04:00 +00:00
Merge branch 'explosivegaming:main' into aperx2
This commit is contained in:
@@ -5,7 +5,6 @@ return {
|
|||||||
show_playtime = true,
|
show_playtime = true,
|
||||||
entity_protection = true,
|
entity_protection = true,
|
||||||
player_reports = true,
|
player_reports = true,
|
||||||
player_warnings = true,
|
|
||||||
player_bans = true,
|
player_bans = true,
|
||||||
player_mutes = true,
|
player_mutes = true,
|
||||||
player_kicks = true,
|
player_kicks = true,
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ local ExpUtil = require("modules/exp_util")
|
|||||||
local Gui = require("modules/exp_gui")
|
local Gui = require("modules/exp_gui")
|
||||||
local Roles = require("modules/exp_roles")
|
local Roles = require("modules/exp_roles")
|
||||||
local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports
|
local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports
|
||||||
local Warnings = require("modules.exp_legacy.modules.control.warnings") --- @dep modules.control.warnings
|
local Jail = require("modules/exp_scenario/control/jail")
|
||||||
local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail
|
|
||||||
local Colors = require("modules/exp_util/include/color")
|
local Colors = require("modules/exp_util/include/color")
|
||||||
local format_player_name = ExpUtil.format_player_name_locale
|
local format_player_name = ExpUtil.format_player_name_locale
|
||||||
|
|
||||||
@@ -100,26 +99,12 @@ local function report_player_callback(player, reason)
|
|||||||
Reports.report_player(selected_player.name, player.name, reason)
|
Reports.report_player(selected_player.name, player.name, reason)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Gives the action player a warning, requires a reason
|
|
||||||
-- @element warn_player
|
|
||||||
local warn_player = new_button("utility/spawn_flag", { "exp-gui_player-list.warn-player" })
|
|
||||||
:on_click(function(def, player, element)
|
|
||||||
set_selected_action(player, "exp_scenario.command.create_warning")
|
|
||||||
end)
|
|
||||||
|
|
||||||
local function warn_player_callback(player, reason)
|
|
||||||
local selected_player, selected_player_color = get_action_player(player)
|
|
||||||
local by_player_name_color = format_player_name(player)
|
|
||||||
game.print{ "exp-commands_warnings.create", selected_player_color, by_player_name_color, reason }
|
|
||||||
Warnings.add_warning(selected_player.name, player.name, reason)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Jails the action player, requires a reason
|
--- Jails the action player, requires a reason
|
||||||
-- @element jail_player
|
-- @element jail_player
|
||||||
local jail_player = new_button("utility/multiplayer_waiting_icon", { "exp-gui_player-list.jail-player" })
|
local jail_player = new_button("utility/multiplayer_waiting_icon", { "exp-gui_player-list.jail-player" })
|
||||||
:on_click(function(def, player, element)
|
:on_click(function(def, player, element)
|
||||||
local selected_player, selected_player_color = get_action_player(player)
|
local selected_player, selected_player_color = get_action_player(player)
|
||||||
if Jail.is_jailed(selected_player.name) then
|
if Jail.is_jailed(selected_player) then
|
||||||
player.print({ "exp-commands_jail.already-jailed", selected_player_color }, Colors.orange_red)
|
player.print({ "exp-commands_jail.already-jailed", selected_player_color }, Colors.orange_red)
|
||||||
else
|
else
|
||||||
set_selected_action(player, "exp_scenario.command.jail")
|
set_selected_action(player, "exp_scenario.command.jail")
|
||||||
@@ -130,7 +115,7 @@ local function jail_player_callback(player, reason)
|
|||||||
local selected_player, selected_player_color = get_action_player(player)
|
local selected_player, selected_player_color = get_action_player(player)
|
||||||
local by_player_name_color = format_player_name(player)
|
local by_player_name_color = format_player_name(player)
|
||||||
game.print{ "exp-commands_jail.jailed", selected_player_color, by_player_name_color, reason }
|
game.print{ "exp-commands_jail.jailed", selected_player_color, by_player_name_color, reason }
|
||||||
Jail.jail_player(selected_player.name, player.name, reason)
|
Jail.jail_player(selected_player, player.name, reason)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Kicks the action player, requires a reason
|
--- Kicks the action player, requires a reason
|
||||||
@@ -170,18 +155,11 @@ return {
|
|||||||
["exp_scenario.command.create_report"] = {
|
["exp_scenario.command.create_report"] = {
|
||||||
auth = function(player, selected_player)
|
auth = function(player, selected_player)
|
||||||
if player == selected_player then return false end
|
if player == selected_player then return false end
|
||||||
if not Roles.player_has_permission(player, "exp_scenario.command.create_warning") then
|
|
||||||
return not Roles.player_has_permission(selected_player, "exp_scenario.bypass.reports")
|
return not Roles.player_has_permission(selected_player, "exp_scenario.bypass.reports")
|
||||||
end
|
end, -- can report any player that isn't immune
|
||||||
end, -- can report any player that isn't immune and you aren't able to give warnings
|
|
||||||
reason_callback = report_player_callback,
|
reason_callback = report_player_callback,
|
||||||
report_player,
|
report_player,
|
||||||
},
|
},
|
||||||
["exp_scenario.command.create_warning"] = {
|
|
||||||
auth = Roles.player_outranks, -- warn a lower user, replaces report
|
|
||||||
reason_callback = warn_player_callback,
|
|
||||||
warn_player,
|
|
||||||
},
|
|
||||||
["exp_scenario.command.jail"] = {
|
["exp_scenario.command.jail"] = {
|
||||||
auth = Roles.player_outranks,
|
auth = Roles.player_outranks,
|
||||||
reason_callback = jail_player_callback,
|
reason_callback = jail_player_callback,
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
--- Config file for the warning system, this is very similar to reports but is for the use of moderators rather than normal users.
|
|
||||||
-- @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", "" },
|
|
||||||
{ "warnings.received", "" },
|
|
||||||
{ "warnings.received", { "warnings.pre-kick" } },
|
|
||||||
function(player, by_player_name, number_of_warnings)
|
|
||||||
local str = {
|
|
||||||
"You received a warning from ",
|
|
||||||
by_player_name,
|
|
||||||
". You have ",
|
|
||||||
number_of_warnings,
|
|
||||||
" warnings. You were kicked for having too many warnings; you may rejoin if you wish.",
|
|
||||||
}
|
|
||||||
game.kick_player(player, table.concat(str, "")) -- Does not support locale strings
|
|
||||||
-- game.kick_player(player, { "warnings.received", by_player_name, number_of_warnings, { "warnings.kick" } })
|
|
||||||
end,
|
|
||||||
{ "warnings.received", { "warnings.pre-pre-ban" } },
|
|
||||||
{ "warnings.received", { "warnings.pre-ban" } },
|
|
||||||
function(player, by_player_name, number_of_warnings)
|
|
||||||
local str = {
|
|
||||||
"You received a warning from ",
|
|
||||||
by_player_name,
|
|
||||||
". You have ",
|
|
||||||
number_of_warnings,
|
|
||||||
" warnings. You were banned for having too many warnings; visit https://www.explosivegaming.nl to request a ban appeal.",
|
|
||||||
}
|
|
||||||
game.kick_player(player, table.concat(str, "")) -- Does not support locale strings
|
|
||||||
-- game.ban_player(player, { "warnings.received", by_player_name, number_of_warnings, { "warnings.ban", { "links.website" } } })
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
script_warning_cool_down = 30, --- @setting script_warning_cool_down time for a script warning (given by script) to be removed (in minutes)
|
|
||||||
script_warning_limit = 5, --- @setting script_warning_limit the number of script warnings (given by script) that are allowed before full warnings are given
|
|
||||||
}
|
|
||||||
@@ -18,14 +18,3 @@ read-readme=Make sure you have read the information gui (It can be found through
|
|||||||
softmod=We run a softmod on our servers. A softmod is a custom scenario that runs on this server, an example is the player list.
|
softmod=We run a softmod on our servers. A softmod is a custom scenario that runs on this server, an example is the player list.
|
||||||
redmew=We don't talk about redmew here; they beat us to 1000 members ;-;
|
redmew=We don't talk about redmew here; they beat us to 1000 members ;-;
|
||||||
lhd=All trains must be LHD! This is a long standing rule on our servers, please respect this.
|
lhd=All trains must be LHD! This is a long standing rule on our servers, please respect this.
|
||||||
|
|
||||||
[warnings]
|
|
||||||
received=You received a warning from __1__. You have __2__ warnings. __3__
|
|
||||||
pre-kick=This is your last warning before you are kicked.
|
|
||||||
kick=You were kicked for having too many warnings; you may rejoin if you wish.
|
|
||||||
pre-pre-ban=You are close to receiving a ban; successful ban appeals are unlikely.
|
|
||||||
pre-ban=This your LAST warning before you are BANNED! Successful ban appeals are unlikely.
|
|
||||||
ban=You were banned for having too many warnings; visit __1__ to request a ban appeal.
|
|
||||||
script-warning=You are receiving script warnings; if you recive too many you will receive a permanent warning (__1__/__2__)
|
|
||||||
script-warning-removed=A script warning has expired (__1__/__2__)
|
|
||||||
script-warning-limit=__1__ has received a permanent warning from the script.
|
|
||||||
|
|||||||
@@ -10,11 +10,6 @@ message-cleared=Your join message has been cleared.
|
|||||||
[quickbar]
|
[quickbar]
|
||||||
saved=Your quickbar filters have been saved.
|
saved=Your quickbar filters have been saved.
|
||||||
|
|
||||||
[exp-required]
|
|
||||||
Warnings=Warnings
|
|
||||||
Warnings-tooltip=The total number of warnings you have received from staff
|
|
||||||
Warnings-value-tooltip=The total number of warnings you have received from staff
|
|
||||||
|
|
||||||
[exp-settings]
|
[exp-settings]
|
||||||
Colour=Colour
|
Colour=Colour
|
||||||
Colour-tooltip=Your player colour
|
Colour-tooltip=Your player colour
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ reason-entry=Enter Reason
|
|||||||
goto-player=Goto player
|
goto-player=Goto player
|
||||||
bring-player=Bring player
|
bring-player=Bring player
|
||||||
report-player=Report player
|
report-player=Report player
|
||||||
warn-player=Warn player
|
|
||||||
jail-player=Jail player
|
jail-player=Jail player
|
||||||
kick-player=Kick player
|
kick-player=Kick player
|
||||||
ban-player=Ban player
|
ban-player=Ban player
|
||||||
|
|||||||
@@ -18,14 +18,3 @@ read-readme=確保你已閱讀相關資訊。按左上 i 圖標可再次查看
|
|||||||
softmod=這裹用了自設情境,是一種軟裝模組。
|
softmod=這裹用了自設情境,是一種軟裝模組。
|
||||||
redmew=
|
redmew=
|
||||||
lhd=列車必須是左則通行。這是本服務器長久以來的規則。
|
lhd=列車必須是左則通行。這是本服務器長久以來的規則。
|
||||||
|
|
||||||
[warnings]
|
|
||||||
received=你已被 __1__ 警告了,現在共有 __2__ 個警告。 __3__
|
|
||||||
pre-kick=這是在被踢離之前的最後警告。
|
|
||||||
kick=你已因為被警告太多次而被請離,不過你之後還是可以回來的。
|
|
||||||
pre-pre-ban=按照你的行為,你有可能會被封禁。
|
|
||||||
pre-ban=這是在被封禁之前的最後警告。
|
|
||||||
ban=你已因為被警告太多次而被封禁; 可以到 __1__ 申訴.
|
|
||||||
script-warning=這是系統發出的自動警告 (__1__/__2__)
|
|
||||||
script-warning-removed=系統發出的自動警告已失效 (__1__/__2__)
|
|
||||||
script-warning-limit=__1__ 已被系統發出了一則自動警告。
|
|
||||||
|
|||||||
@@ -10,11 +10,6 @@ message-cleared=你的加入信息已清除。
|
|||||||
[quickbar]
|
[quickbar]
|
||||||
saved=你的工具列已儲存。
|
saved=你的工具列已儲存。
|
||||||
|
|
||||||
[exp-required]
|
|
||||||
Warnings=警告
|
|
||||||
Warnings-tooltip=你所有收到的警告
|
|
||||||
Warnings-value-tooltip=你所有收到的警告
|
|
||||||
|
|
||||||
[exp-settings]
|
[exp-settings]
|
||||||
Colour=顏色
|
Colour=顏色
|
||||||
Colour-tooltip=你的人物顏色
|
Colour-tooltip=你的人物顏色
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ reason-entry=輸入原因
|
|||||||
goto-player=傳送到用戶
|
goto-player=傳送到用戶
|
||||||
bring-player=傳送用戶到自己
|
bring-player=傳送用戶到自己
|
||||||
report-player=舉報用戶
|
report-player=舉報用戶
|
||||||
warn-player=警告用戶
|
|
||||||
jail-player=監禁用戶
|
jail-player=監禁用戶
|
||||||
kick-player=踢除用戶
|
kick-player=踢除用戶
|
||||||
ban-player=封禁用戶
|
ban-player=封禁用戶
|
||||||
|
|||||||
@@ -18,14 +18,3 @@ read-readme=確保你已閱讀相關資訊。按左上 i 圖標可再次查看
|
|||||||
softmod=這裹用了自設情境,是一種軟裝模組。
|
softmod=這裹用了自設情境,是一種軟裝模組。
|
||||||
redmew=
|
redmew=
|
||||||
lhd=列車必須是左則通行。這是本服務器長久以來的規則。
|
lhd=列車必須是左則通行。這是本服務器長久以來的規則。
|
||||||
|
|
||||||
[warnings]
|
|
||||||
received=你已被 __1__ 警告了,現在共有 __2__ 個警告。 __3__
|
|
||||||
pre-kick=這是在被踢離之前的最後警告。
|
|
||||||
kick=你已因為被警告太多次而被請離,不過你之後還是可以回來的。
|
|
||||||
pre-pre-ban=按照你的行為,你有可能會被封禁。
|
|
||||||
pre-ban=這是在被封禁之前的最後警告。
|
|
||||||
ban=你已因為被警告太多次而被封禁; 可以到 __1__ 申訴.
|
|
||||||
script-warning=這是系統發出的自動警告 (__1__/__2__)
|
|
||||||
script-warning-removed=系統發出的自動警告已失效 (__1__/__2__)
|
|
||||||
script-warning-limit=__1__ 已被系統發出了一則自動警告。
|
|
||||||
|
|||||||
@@ -10,11 +10,6 @@ message-cleared=你的加入信息已清除。
|
|||||||
[quickbar]
|
[quickbar]
|
||||||
saved=你的工具列已儲存。
|
saved=你的工具列已儲存。
|
||||||
|
|
||||||
[exp-required]
|
|
||||||
Warnings=警告
|
|
||||||
Warnings-tooltip=你所有收到的警告
|
|
||||||
Warnings-value-tooltip=你所有收到的警告
|
|
||||||
|
|
||||||
[exp-settings]
|
[exp-settings]
|
||||||
Colour=顏色
|
Colour=顏色
|
||||||
Colour-tooltip=你的人物顏色
|
Colour-tooltip=你的人物顏色
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ reason-entry=輸入原因
|
|||||||
goto-player=傳送到用戶
|
goto-player=傳送到用戶
|
||||||
bring-player=傳送用戶到自己
|
bring-player=傳送用戶到自己
|
||||||
report-player=舉報用戶
|
report-player=舉報用戶
|
||||||
warn-player=警告用戶
|
|
||||||
jail-player=監禁用戶
|
jail-player=監禁用戶
|
||||||
kick-player=踢除用戶
|
kick-player=踢除用戶
|
||||||
ban-player=封禁用戶
|
ban-player=封禁用戶
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
--[[-- Control Module - Jail
|
|
||||||
- Adds a way to jail players.
|
|
||||||
@control Jail
|
|
||||||
@alias Jail
|
|
||||||
|
|
||||||
@usage
|
|
||||||
-- import the module from the control modules
|
|
||||||
local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail
|
|
||||||
|
|
||||||
-- This will give 'MrBiter' the jail role, which suppresses all of their other roles
|
|
||||||
-- the player name and reason are only so they can be included in the event for user feedback
|
|
||||||
Jail.jail_player('MrBiter', 'Cooldude2606', 'Likes biters too much')
|
|
||||||
|
|
||||||
-- This will remove the jail role from 'MrBiter', restoring their other roles
|
|
||||||
-- again as above the player name is only used in the event for user feedback
|
|
||||||
Jail.unjail_player('MrBiter', 'Cooldude2606')
|
|
||||||
]]
|
|
||||||
|
|
||||||
local Roles = require("modules/exp_roles")
|
|
||||||
|
|
||||||
local valid_player = function(p) return type(p) == "userdata" and p or game.get_player(p) end
|
|
||||||
|
|
||||||
--- The role given to jailed players, it has a higher priority than every other role
|
|
||||||
local function jail_role()
|
|
||||||
return assert(Roles.get_role_by_name("Jail"), "The Jail role does not exist")
|
|
||||||
end
|
|
||||||
|
|
||||||
local Jail = {
|
|
||||||
events = {
|
|
||||||
--- When a player is assigned to jail
|
|
||||||
-- @event on_player_jailed
|
|
||||||
-- @tparam number player_index the index of the player who was jailed
|
|
||||||
-- @tparam string by_player_name the name of the player who jailed the other player
|
|
||||||
-- @tparam string reason the reason that the player was jailed
|
|
||||||
on_player_jailed = script.generate_event_name(),
|
|
||||||
--- When a player is unassigned from jail
|
|
||||||
-- @event on_player_unjailed
|
|
||||||
-- @tparam number player_index the index of the player who was unjailed
|
|
||||||
-- @tparam string by_player_name the name of the player who unjailed the other player
|
|
||||||
on_player_unjailed = script.generate_event_name(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
--- Used to emit the jail related events
|
|
||||||
-- @tparam number event the name of the event that will be emited
|
|
||||||
-- @tparam LuaPlayer player the player who is being acted on
|
|
||||||
-- @tparam string by_player_name the player who is doing the action
|
|
||||||
-- @tparam string reason the reason for the action (jail)
|
|
||||||
local function event_emit(event, player, by_player_name, reason)
|
|
||||||
script.raise_event(event, {
|
|
||||||
name = event,
|
|
||||||
tick = game.tick,
|
|
||||||
player_index = player.index,
|
|
||||||
by_player_name = by_player_name,
|
|
||||||
reason = reason,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Jail.
|
|
||||||
-- Functions related to jail
|
|
||||||
-- @section jail-functions
|
|
||||||
|
|
||||||
--- Checks if the player is currently in jail
|
|
||||||
-- @tparam LuaPlayer player the player to check if they are in jail
|
|
||||||
-- @treturn boolean whether the player is currently in jail
|
|
||||||
function Jail.is_jailed(player)
|
|
||||||
local valid = valid_player(player)
|
|
||||||
return valid ~= nil and jail_role():has_player(valid)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Moves a player to jail, which suppresses all of their other roles
|
|
||||||
-- @tparam LuaPlayer player the player who will be jailed
|
|
||||||
-- @tparam string by_player_name the name of the player who is doing the jailing
|
|
||||||
-- @tparam[opt='Non given.'] string reason the reason that the player is being jailed
|
|
||||||
-- @treturn boolean wheather the user was jailed successfully
|
|
||||||
function Jail.jail_player(player, by_player_name, reason)
|
|
||||||
player = valid_player(player)
|
|
||||||
if not player then return end
|
|
||||||
if not by_player_name then return end
|
|
||||||
|
|
||||||
reason = reason or "Non given."
|
|
||||||
|
|
||||||
local role = jail_role()
|
|
||||||
if role:has_player(player) then return end
|
|
||||||
|
|
||||||
player.walking_state = { walking = false, direction = player.walking_state.direction }
|
|
||||||
player.riding_state = { acceleration = defines.riding.acceleration.nothing, direction = player.riding_state.direction }
|
|
||||||
player.mining_state = { mining = false }
|
|
||||||
player.shooting_state = { state = defines.shooting.not_shooting, position = player.shooting_state.position }
|
|
||||||
player.picking_state = false
|
|
||||||
player.repair_state = { repairing = false, position = player.repair_state.position }
|
|
||||||
|
|
||||||
role:assign(player, { by_player_name = by_player_name, silent = true })
|
|
||||||
|
|
||||||
event_emit(Jail.events.on_player_jailed, player, by_player_name, reason)
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Moves a player out of jail, which restores all of their other roles
|
|
||||||
-- @tparam LuaPlayer player the player that will be unjailed
|
|
||||||
-- @tparam string by_player_name the name of the player that is doing the unjail
|
|
||||||
-- @treturn boolean whether the player was unjailed successfully
|
|
||||||
function Jail.unjail_player(player, by_player_name)
|
|
||||||
player = valid_player(player)
|
|
||||||
if not player then return end
|
|
||||||
if not by_player_name then return end
|
|
||||||
|
|
||||||
local role = jail_role()
|
|
||||||
if not role:has_player(player) then return end
|
|
||||||
|
|
||||||
role:unassign(player, { by_player_name = by_player_name, silent = true })
|
|
||||||
|
|
||||||
event_emit(Jail.events.on_player_unjailed, player, by_player_name)
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
return Jail
|
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
--[[-- Control Module - Protection
|
|
||||||
- Controls protected entities
|
|
||||||
@control Protection
|
|
||||||
@alias Protection
|
|
||||||
]]
|
|
||||||
|
|
||||||
local Storage = require("modules/exp_util/storage")
|
|
||||||
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
|
|
||||||
local config = require("modules.exp_legacy.config.protection") --- @dep config.protection
|
|
||||||
local EntityProtection = {
|
|
||||||
protected_entity_names = table.deep_copy(config.always_protected_names),
|
|
||||||
protected_entity_types = table.deep_copy(config.always_protected_types),
|
|
||||||
events = {
|
|
||||||
--- When a player mines a protected entity
|
|
||||||
-- @event on_player_mined_protected
|
|
||||||
-- @tparam number player_index the player index of the player who got mined the entity
|
|
||||||
-- @tparam LuaEntity entity the entity which was mined
|
|
||||||
on_player_mined_protected = script.generate_event_name(),
|
|
||||||
--- When a player repeatedly mines protected entities
|
|
||||||
-- @event on_repeat_violation
|
|
||||||
-- @tparam number player_index the player index of the player who got mined the entities
|
|
||||||
-- @tparam LuaEntity entity the last entity which was mined
|
|
||||||
on_repeat_violation = script.generate_event_name(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Convert config tables into lookup tables
|
|
||||||
for _, config_key in ipairs{ "always_protected_names", "always_protected_types", "always_trigger_repeat_names", "always_trigger_repeat_types" } do
|
|
||||||
local tbl = config[config_key]
|
|
||||||
for key, value in ipairs(tbl) do
|
|
||||||
tbl[key] = nil
|
|
||||||
tbl[value] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local Roles = require("modules/exp_roles")
|
|
||||||
|
|
||||||
----- Storage Variables -----
|
|
||||||
--- Variables stored in the global table
|
|
||||||
|
|
||||||
local protected_entities = {} -- All entities which are protected
|
|
||||||
local protected_areas = {} -- All areas which are protected
|
|
||||||
local repeats = {} -- Stores repeat removals by players
|
|
||||||
|
|
||||||
Storage.register({
|
|
||||||
protected_entities = protected_entities,
|
|
||||||
protected_areas = protected_areas,
|
|
||||||
repeats = repeats,
|
|
||||||
}, function(tbl)
|
|
||||||
protected_entities = tbl.protected_entities
|
|
||||||
protected_areas = tbl.protected_areas
|
|
||||||
repeats = tbl.repeats
|
|
||||||
end)
|
|
||||||
|
|
||||||
----- Local Functions -----
|
|
||||||
--- Functions used internally to search and add to the protected array
|
|
||||||
|
|
||||||
--- Get the key used in protected_entities
|
|
||||||
local function get_entity_key(entity)
|
|
||||||
return string.format("%i,%i", math.floor(entity.position.x), math.floor(entity.position.y))
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get the key used in protected_areas
|
|
||||||
local function get_area_key(area)
|
|
||||||
return string.format("%i,%i", math.floor(area.left_top.x), math.floor(area.left_top.y))
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Check if an entity is always protected
|
|
||||||
local function check_always_protected(entity)
|
|
||||||
return config.always_protected_names[entity.name] or config.always_protected_types[entity.type] or false
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Check if an entity always triggers repeat protection
|
|
||||||
local function check_always_trigger_repeat(entity)
|
|
||||||
return config.always_trigger_repeat_names[entity.name] or config.always_trigger_repeat_types[entity.type] or false
|
|
||||||
end
|
|
||||||
|
|
||||||
----- Public Functions -----
|
|
||||||
--- Functions used to add and remove protected entities
|
|
||||||
|
|
||||||
--- Add an entity to the protected list
|
|
||||||
function EntityProtection.add_entity(entity)
|
|
||||||
local entities = protected_entities[entity.surface.index]
|
|
||||||
if not entities then
|
|
||||||
entities = {}
|
|
||||||
protected_entities[entity.surface.index] = entities
|
|
||||||
end
|
|
||||||
entities[get_entity_key(entity)] = entity
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Remove an entity from the protected list
|
|
||||||
function EntityProtection.remove_entity(entity)
|
|
||||||
local entities = protected_entities[entity.surface.index]
|
|
||||||
if not entities then return end
|
|
||||||
entities[get_entity_key(entity)] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get all protected entities on a surface
|
|
||||||
function EntityProtection.get_entities(surface)
|
|
||||||
return protected_entities[surface.index] or {}
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Check if an entity is protected
|
|
||||||
function EntityProtection.is_entity_protected(entity)
|
|
||||||
if check_always_protected(entity) then return true end
|
|
||||||
local entities = protected_entities[entity.surface.index]
|
|
||||||
if not entities then return false end
|
|
||||||
return entities[get_entity_key(entity)] == entity
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Add an area to the protected list
|
|
||||||
function EntityProtection.add_area(surface, area)
|
|
||||||
local areas = protected_areas[surface.index]
|
|
||||||
if not areas then
|
|
||||||
areas = {}
|
|
||||||
protected_areas[surface.index] = areas
|
|
||||||
end
|
|
||||||
areas[get_area_key(area)] = area
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Remove an area from the protected list
|
|
||||||
function EntityProtection.remove_area(surface, area)
|
|
||||||
local areas = protected_areas[surface.index]
|
|
||||||
if not areas then return end
|
|
||||||
areas[get_area_key(area)] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get all protected areas on a surface
|
|
||||||
function EntityProtection.get_areas(surface)
|
|
||||||
return protected_areas[surface.index] or {}
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Check if an entity is protected
|
|
||||||
function EntityProtection.is_position_protected(surface, position)
|
|
||||||
local areas = protected_areas[surface.index]
|
|
||||||
if not areas then return false end
|
|
||||||
for _, area in pairs(areas) do
|
|
||||||
if area.left_top.x <= position.x and area.left_top.y <= position.y
|
|
||||||
and area.right_bottom.x >= position.x and area.right_bottom.y >= position.y
|
|
||||||
then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
----- Events -----
|
|
||||||
--- All events registered by this module
|
|
||||||
|
|
||||||
--- Raise events for protected entities
|
|
||||||
Event.add(defines.events.on_pre_player_mined_item, function(event)
|
|
||||||
local entity = event.entity
|
|
||||||
local player = game.players[event.player_index]
|
|
||||||
-- Check if the player should be ignored
|
|
||||||
if config.ignore_admins and player.admin then return end
|
|
||||||
if entity.last_user == nil or entity.last_user.index == player.index then return end
|
|
||||||
if config.ignore_permission and Roles.player_has_permission(player, config.ignore_permission) then return end
|
|
||||||
|
|
||||||
-- Check if the entity is protected
|
|
||||||
if EntityProtection.is_entity_protected(entity)
|
|
||||||
or EntityProtection.is_position_protected(entity.surface, entity.position)
|
|
||||||
then
|
|
||||||
-- Update repeats
|
|
||||||
local player_repeats = repeats[player.name]
|
|
||||||
if not player_repeats then
|
|
||||||
player_repeats = { last = game.tick, count = 0 }
|
|
||||||
repeats[player.name] = player_repeats
|
|
||||||
end
|
|
||||||
player_repeats.last = game.tick
|
|
||||||
player_repeats.count = player_repeats.count + 1
|
|
||||||
-- Send events
|
|
||||||
event.name = EntityProtection.events.on_player_mined_protected
|
|
||||||
script.raise_event(EntityProtection.events.on_player_mined_protected, event)
|
|
||||||
if check_always_trigger_repeat(entity) or player_repeats.count >= config.repeat_count then
|
|
||||||
player_repeats.count = 0 -- Reset to avoid spamming of events
|
|
||||||
event.name = EntityProtection.events.on_repeat_violation
|
|
||||||
script.raise_event(EntityProtection.events.on_repeat_violation, event)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Remove old repeats
|
|
||||||
Event.on_nth_tick(config.refresh_rate, function()
|
|
||||||
local old = game.tick - config.repeat_lifetime
|
|
||||||
for player_name, player_repeats in pairs(repeats) do
|
|
||||||
if player_repeats.last <= old then
|
|
||||||
repeats[player_name] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- When an entity is removed remove it from the protection list
|
|
||||||
local function event_remove_entity(event)
|
|
||||||
EntityProtection.remove_entity(event.entity)
|
|
||||||
end
|
|
||||||
|
|
||||||
Event.add(defines.events.on_space_platform_pre_mined, event_remove_entity)
|
|
||||||
Event.add(defines.events.on_pre_player_mined_item, event_remove_entity)
|
|
||||||
Event.add(defines.events.on_robot_pre_mined, event_remove_entity)
|
|
||||||
Event.add(defines.events.on_entity_died, event_remove_entity)
|
|
||||||
Event.add(defines.events.script_raised_destroy, event_remove_entity)
|
|
||||||
|
|
||||||
return EntityProtection
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
local Storage = require("modules/exp_util/storage")
|
|
||||||
local Gui = require("modules/exp_gui")
|
|
||||||
|
|
||||||
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
|
|
||||||
|
|
||||||
----- Locals -----
|
|
||||||
local follow_label --- @type ExpElement Gui constructor
|
|
||||||
local following = {}
|
|
||||||
local spectating = {}
|
|
||||||
local Public = {}
|
|
||||||
|
|
||||||
----- Storage data -----
|
|
||||||
Storage.register({
|
|
||||||
following = following,
|
|
||||||
spectating = spectating,
|
|
||||||
}, function(tbl)
|
|
||||||
following = tbl.following
|
|
||||||
spectating = tbl.spectating
|
|
||||||
end)
|
|
||||||
|
|
||||||
----- Public Functions -----
|
|
||||||
|
|
||||||
--- Test if a player is in spectator mode
|
|
||||||
-- @tparam LuaPlayer player The player to test the controller type of
|
|
||||||
-- @treturn boolean Returns true if the player is in spectator mode
|
|
||||||
function Public.is_spectating(player)
|
|
||||||
assert(player and player.valid, "Invalid player given to follower")
|
|
||||||
return player.controller_type == defines.controllers.spectator
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Puts a player into spectator mode while maintaining an association to their character
|
|
||||||
-- @tparam LuaPlayer player The player that will be placed into spectator mode
|
|
||||||
-- @treturn boolean Returns false if the player was already in spectator mode
|
|
||||||
function Public.start_spectate(player)
|
|
||||||
assert(player and player.valid, "Invalid player given to follower")
|
|
||||||
if spectating[player.index] or not player.character then return false end
|
|
||||||
local character = player.character
|
|
||||||
local opened = player.opened
|
|
||||||
player.set_controller{ type = defines.controllers.spectator }
|
|
||||||
player.associate_character(character)
|
|
||||||
spectating[player.index] = character
|
|
||||||
if opened then player.opened = opened end -- Maintain opened after controller change
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Return a player from spectator mode back to their character, if their character was killed then respawn them
|
|
||||||
-- @tparam LuaPlayer player The player that will leave spectator mode
|
|
||||||
function Public.stop_spectate(player)
|
|
||||||
assert(player and player.valid, "Invalid player given to follower")
|
|
||||||
local character = spectating[player.index]
|
|
||||||
spectating[player.index] = nil
|
|
||||||
if character and character.valid then
|
|
||||||
local opened = player.opened
|
|
||||||
player.teleport(character.position, character.surface)
|
|
||||||
player.set_controller{ type = defines.controllers.character, character = character }
|
|
||||||
if opened then player.opened = opened end -- Maintain opened after controller change
|
|
||||||
else
|
|
||||||
player.ticks_to_respawn = 300
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Test if a player is in follow mode
|
|
||||||
-- @tparam LuaPlayer player The player to test the follow mode of
|
|
||||||
-- @treturn boolean Returns true if the player is in follow mode
|
|
||||||
function Public.is_following(player)
|
|
||||||
assert(player and player.valid, "Invalid player given to follower")
|
|
||||||
return following[player.index] ~= nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Puts a player into spectator mode and follows an entity as it moves
|
|
||||||
-- @tparam LuaPlayer player The player that will follow the entity
|
|
||||||
-- @tparam ?LuaPlayer|LuaEntity entity The player or entity that will be followed
|
|
||||||
function Public.start_follow(player, entity)
|
|
||||||
assert(player and player.valid, "Invalid player given to follower")
|
|
||||||
assert(entity and entity.valid, "Invalid entity given to follower")
|
|
||||||
local spectate = Public.start_spectate(player)
|
|
||||||
|
|
||||||
player.close_map()
|
|
||||||
follow_label(player.gui.screen, entity)
|
|
||||||
player.teleport(entity.position, entity.surface)
|
|
||||||
following[player.index] = { player, entity, entity.position, spectate }
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Returns camera control to the player, will return a player to their character if start_follow placed them into spectator mode
|
|
||||||
-- @tparam LuaPlayer player The player that will regain control of their camera
|
|
||||||
function Public.stop_follow(player)
|
|
||||||
assert(player and player.valid, "Invalid player given to follower")
|
|
||||||
if following[player.index] and following[player.index][4] and Public.is_spectating(player) then
|
|
||||||
Public.stop_spectate(player)
|
|
||||||
end
|
|
||||||
|
|
||||||
Gui.destroy_if_valid(player.gui.screen.follow_label)
|
|
||||||
following[player.index] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Returns camera control to all players, will return a player to their character if start_follow placed them into spectator mode
|
|
||||||
function Public.stop_all()
|
|
||||||
for key, data in pairs(following) do
|
|
||||||
Public.stop_follow(data[1])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
----- Gui -----
|
|
||||||
|
|
||||||
--- Label used to show that the player is following, also used to allow esc to stop following
|
|
||||||
follow_label = Gui.define("follow-label")
|
|
||||||
:draw(function(def, parent, target)
|
|
||||||
Gui.destroy_if_valid(parent.follow_label)
|
|
||||||
|
|
||||||
local label = parent.add{
|
|
||||||
type = "label",
|
|
||||||
name = "follow_label",
|
|
||||||
style = "frame_title",
|
|
||||||
caption = "Following " .. target.name .. ".\nClick here or press esc to stop following.",
|
|
||||||
}
|
|
||||||
|
|
||||||
local player = Gui.get_player(parent)
|
|
||||||
local res = player.display_resolution
|
|
||||||
label.location = { 0, res.height - 150 }
|
|
||||||
label.style.width = res.width
|
|
||||||
label.style.horizontal_align = "center"
|
|
||||||
player.opened = label
|
|
||||||
|
|
||||||
return label
|
|
||||||
end)
|
|
||||||
:on_click(function(def, player, element)
|
|
||||||
Public.stop_follow(player)
|
|
||||||
end)
|
|
||||||
:on_closed(function(def, player, element)
|
|
||||||
-- Don't call set_controller during on_close as it invalidates the controller
|
|
||||||
-- Setting an invalid position (as to not equal their current) will call stop_follow on the next tick
|
|
||||||
following[player.index][3] = {}
|
|
||||||
end)
|
|
||||||
|
|
||||||
----- Events -----
|
|
||||||
|
|
||||||
--- Updates the location of the player as well as doing some sanity checks
|
|
||||||
-- @tparam LuaPlayer player The player to update the position of
|
|
||||||
-- @tparam ?LuaPlayer|LuaEntity entity The player or entity being followed
|
|
||||||
local function update_player_location(player, entity, old_position)
|
|
||||||
if player.character or not entity.valid then
|
|
||||||
Public.stop_follow(player)
|
|
||||||
elseif player.position.x ~= old_position.x or player.position.y ~= old_position.y then
|
|
||||||
Public.stop_follow(player)
|
|
||||||
else
|
|
||||||
player.teleport(entity.position, entity.surface)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Updates the locations of all players currently following something
|
|
||||||
local function update_all()
|
|
||||||
for _, data in pairs(following) do
|
|
||||||
update_player_location(data[1], data[2], data[3])
|
|
||||||
data[3] = data[1].position
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Update the location of all players each tick
|
|
||||||
Event.add(defines.events.on_tick, update_all)
|
|
||||||
|
|
||||||
-- Check for player leaving
|
|
||||||
Event.add(defines.events.on_pre_player_left_game, function(event)
|
|
||||||
local player = game.players[event.player_index]
|
|
||||||
Public.stop_follow(player)
|
|
||||||
for _, data in pairs(following) do
|
|
||||||
if data[2] == player then
|
|
||||||
Public.stop_follow(data[1])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
----- Module Return -----
|
|
||||||
return Public
|
|
||||||
@@ -1,331 +0,0 @@
|
|||||||
--[[-- Control Module - Warnings
|
|
||||||
- Adds a way to give and remove warnings to players.
|
|
||||||
@control Warnings
|
|
||||||
@alias Warnings
|
|
||||||
|
|
||||||
@usage
|
|
||||||
-- import the module from the control modules
|
|
||||||
local Warnings = require("modules.exp_legacy.modules.control.warnings") --- @dep modules.control.warnings
|
|
||||||
|
|
||||||
-- This will add a warning to the player
|
|
||||||
Warnings.add_warning('MrBiter', 'Cooldude2606', 'Killed too many biters')
|
|
||||||
|
|
||||||
-- This will remove a warning from a player, second name is just who is doing the action
|
|
||||||
Warnings.remove_warning('MrBiter', 'Cooldude2606')
|
|
||||||
|
|
||||||
-- Script warning as similar to normal warning but are designed to have no effect for a short amount of time
|
|
||||||
-- this is so it can be used for greifer protection without being too agressive
|
|
||||||
Warnings.add_script_warning('MrBiter', 'Killed too many biters')
|
|
||||||
|
|
||||||
-- Both normal and script warnings can also be cleared, this will remove all warnings
|
|
||||||
Warnings.clear_warnings('MrBiter', 'Cooldude2606')
|
|
||||||
]]
|
|
||||||
|
|
||||||
local Event = require("modules/exp_legacy/utils/event")
|
|
||||||
local Storage = require("modules/exp_util/storage")
|
|
||||||
local config = require("modules.exp_legacy.config.warnings")
|
|
||||||
|
|
||||||
local valid_player = function(p) return type(p) == "userdata" and p or game.get_player(p) end
|
|
||||||
|
|
||||||
--- Stores the quickbar filters for a player
|
|
||||||
local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data
|
|
||||||
local PlayerWarnings = PlayerData.Required:combine("Warnings")
|
|
||||||
PlayerWarnings:set_metadata{
|
|
||||||
stringify = function(value)
|
|
||||||
if not value then return "You have no warnings" end
|
|
||||||
local count = 0
|
|
||||||
for _ in pairs(value) do count = count + 1 end
|
|
||||||
|
|
||||||
return "You have " .. count .. " warnings"
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
|
|
||||||
local Warnings = {
|
|
||||||
user_warnings = PlayerWarnings,
|
|
||||||
user_script_warnings = {},
|
|
||||||
events = {
|
|
||||||
--- When a warning is added to a player
|
|
||||||
-- @event on_warning_added
|
|
||||||
-- @tparam number player_index the index of the player who recived the warning
|
|
||||||
-- @tparam string by_player_name the name of the player who gave the warning
|
|
||||||
-- @tparam string reason the reason that the player was given a warning
|
|
||||||
-- @tparam number warning_count the new number of warnings that the player has
|
|
||||||
on_warning_added = script.generate_event_name(),
|
|
||||||
--- When a warning is removed from a player
|
|
||||||
-- @event on_warning_removed
|
|
||||||
-- @tparam number player_index the index of the player who is having the warning removed
|
|
||||||
-- @tparam string warning_by_name the name of the player who gave the warning
|
|
||||||
-- @tparam string removed_by_name the name of the player who is removing the warning
|
|
||||||
-- @tparam number warning_count the new number of warnings that the player has
|
|
||||||
-- @tparam number batch_count the number of warnings removed in this batch, always one when not a batch
|
|
||||||
-- @tparam number batch the index of this event in a batch, always one when not a batch
|
|
||||||
on_warning_removed = script.generate_event_name(),
|
|
||||||
--- When a warning is added to a player, by the script
|
|
||||||
-- @event on_script_warning_added
|
|
||||||
-- @tparam number player_index the index of the player who recived the warning
|
|
||||||
-- @tparam string reason the reason that the player was given a warning
|
|
||||||
-- @tparam number warning_count the new number of warnings that the player has
|
|
||||||
on_script_warning_added = script.generate_event_name(),
|
|
||||||
--- When a warning is removed from a player, by the script
|
|
||||||
-- @event on_script_warning_removed
|
|
||||||
-- @tparam number player_index the index of the player who is having the warning removed
|
|
||||||
-- @tparam number warning_count the new number of warnings that the player has
|
|
||||||
on_script_warning_removed = script.generate_event_name(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
local user_script_warnings = Warnings.user_script_warnings
|
|
||||||
Storage.register(user_script_warnings, function(tbl)
|
|
||||||
Warnings.user_script_warnings = tbl
|
|
||||||
user_script_warnings = tbl
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Gets an array of warnings that the player has, always returns a list even if empty
|
|
||||||
-- @tparam LuaPlayer player the player to get the warning for
|
|
||||||
-- @treturn table an array of all the warnings on this player, contains tick, by_player_name and reason
|
|
||||||
function Warnings.get_warnings(player)
|
|
||||||
return PlayerWarnings:get(player.name, {})
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets the number of warnings that a player has on them
|
|
||||||
-- @tparam LuaPlayer player the player to count the warnings for
|
|
||||||
-- @treturn number the number of warnings that the player has
|
|
||||||
function Warnings.count_warnings(player)
|
|
||||||
local warnings = PlayerWarnings:get(player.name, {})
|
|
||||||
return #warnings
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Adds a warning to a player, when a warning is added a set action is done based on the number of warnings and the config file
|
|
||||||
-- @tparam LuaPlayer player the player to add a warning to
|
|
||||||
-- @tparam string by_player_name the name of the player who is doing the action
|
|
||||||
-- @tparam[opt='Non given.'] string reason the reason that the player is being warned
|
|
||||||
-- @treturn number the number of warnings that the player has
|
|
||||||
function Warnings.add_warning(player, by_player_name, reason)
|
|
||||||
player = valid_player(player)
|
|
||||||
if not player then return end
|
|
||||||
if not by_player_name then return end
|
|
||||||
|
|
||||||
reason = reason or "None given."
|
|
||||||
|
|
||||||
local warning_count --- @type number
|
|
||||||
PlayerWarnings:update(player.name, function(_, warnings)
|
|
||||||
local warning = {
|
|
||||||
by_player_name = by_player_name,
|
|
||||||
reason = reason,
|
|
||||||
}
|
|
||||||
|
|
||||||
if not warnings then
|
|
||||||
warning_count = 1
|
|
||||||
return { warning }
|
|
||||||
else
|
|
||||||
table.insert(warnings, warning)
|
|
||||||
warning_count = #warnings
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
script.raise_event(Warnings.events.on_warning_added, {
|
|
||||||
name = Warnings.events.on_warning_added,
|
|
||||||
tick = game.tick,
|
|
||||||
player_index = player.index,
|
|
||||||
warning_count = warning_count,
|
|
||||||
by_player_name = by_player_name,
|
|
||||||
reason = reason,
|
|
||||||
})
|
|
||||||
|
|
||||||
local action = config.actions[warning_count]
|
|
||||||
if action then
|
|
||||||
local _type = type(action)
|
|
||||||
if _type == "function" then
|
|
||||||
action(player, by_player_name, warning_count)
|
|
||||||
elseif _type == "table" then
|
|
||||||
local current = table.deepcopy(action)
|
|
||||||
table.insert(current, 2, by_player_name)
|
|
||||||
table.insert(current, 3, warning_count)
|
|
||||||
player.print(current)
|
|
||||||
elseif type(action) == "string" then
|
|
||||||
player.print(action)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return warning_count
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Event trigger for removing a waring due to it being looped in clear warnings
|
|
||||||
-- @tparam LuaPlayer player the player who is having a warning removed
|
|
||||||
-- @tparam string warning_by_name the name of the player who made the warning
|
|
||||||
-- @tparam string removed_by_name the name of the player who is doing the action
|
|
||||||
-- @tparam number warning_count the number of warnings that the player how has
|
|
||||||
-- @tparam number batch the index of this event in a batch, always one when not a batch
|
|
||||||
-- @tparam number batch_count the number of reports removed in this batch, always one when not a batch
|
|
||||||
local function warning_removed_event(player, warning_by_name, removed_by_name, warning_count, batch, batch_count)
|
|
||||||
script.raise_event(Warnings.events.on_warning_removed, {
|
|
||||||
name = Warnings.events.on_warning_removed,
|
|
||||||
tick = game.tick,
|
|
||||||
player_index = player.index,
|
|
||||||
warning_count = warning_count,
|
|
||||||
warning_by_name = warning_by_name,
|
|
||||||
removed_by_name = removed_by_name,
|
|
||||||
batch_count = batch_count or 1,
|
|
||||||
batch = batch or 1,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Removes a warning from a player, always removes the earliest warning, fifo
|
|
||||||
-- @tparam LuaPlayer player the player to remove a warning from
|
|
||||||
-- @tparam string by_player_name the name of the player who is doing the action
|
|
||||||
-- @treturn number the number of warnings that the player has
|
|
||||||
function Warnings.remove_warning(player, by_player_name)
|
|
||||||
player = valid_player(player)
|
|
||||||
if not player then return end
|
|
||||||
if not by_player_name then return end
|
|
||||||
|
|
||||||
local warning, warning_count
|
|
||||||
PlayerWarnings:update(player.name, function(_, warnings)
|
|
||||||
if not warnings then return end
|
|
||||||
warning = table.remove(warnings, 1)
|
|
||||||
warning_count = #warnings
|
|
||||||
end)
|
|
||||||
|
|
||||||
if not warning then return end
|
|
||||||
warning_removed_event(player, warning.by_player_name, by_player_name, warning_count)
|
|
||||||
|
|
||||||
return warning_count
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Removes all warnings from a player, will trigger remove event for each warning
|
|
||||||
-- @tparam LuaPlayer player the player to clear the warnings from
|
|
||||||
-- @tparam string by_player_name the name of the player who is doing the action
|
|
||||||
-- @treturn boolean true when warnings were cleared succesfully
|
|
||||||
function Warnings.clear_warnings(player, by_player_name)
|
|
||||||
player = valid_player(player)
|
|
||||||
if not player then return end
|
|
||||||
if not by_player_name then return end
|
|
||||||
|
|
||||||
local warnings = PlayerWarnings:get(player)
|
|
||||||
if not warnings then return end
|
|
||||||
|
|
||||||
local warning_count = #warnings
|
|
||||||
for n, warning in pairs(warnings) do
|
|
||||||
warning_removed_event(player, warning.by_player_name, by_player_name, warning_count - n, n, warning_count)
|
|
||||||
end
|
|
||||||
|
|
||||||
PlayerWarnings:remove(player)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets an array of all the script warnings that a player has
|
|
||||||
-- @tparam LuaPlayer player the player to get the script warnings of
|
|
||||||
-- @treturn table a table of all the script warnings a player has, contains tick and reason
|
|
||||||
function Warnings.get_script_warnings(player)
|
|
||||||
return user_script_warnings[player.name] or {}
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Gets the number of script warnings that a player has on them
|
|
||||||
-- @tparam LuaPlayer player the player to count the script warnings of
|
|
||||||
-- @treturn number the number of script warnings that the player has
|
|
||||||
function Warnings.count_script_warnings(player)
|
|
||||||
local warnings = user_script_warnings[player.name] or {}
|
|
||||||
return #warnings
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Adds a script warning to a player, this may add a full warning if max script warnings is met
|
|
||||||
-- @tparam LuaPlayer player the player to add a script warning to
|
|
||||||
-- @tparam[opt='Non given.'] string reason the reason that the player is being warned
|
|
||||||
-- @treturn number the number of script warnings that the player has
|
|
||||||
function Warnings.add_script_warning(player, reason)
|
|
||||||
player = valid_player(player)
|
|
||||||
if not player then return end
|
|
||||||
|
|
||||||
reason = reason or "Non given."
|
|
||||||
|
|
||||||
local warnings = user_script_warnings[player.name]
|
|
||||||
if not warnings then
|
|
||||||
warnings = {}
|
|
||||||
user_script_warnings[player.name] = warnings
|
|
||||||
end
|
|
||||||
|
|
||||||
table.insert(warnings, {
|
|
||||||
tick = game.tick,
|
|
||||||
reason = reason,
|
|
||||||
})
|
|
||||||
|
|
||||||
local warning_count = #warnings
|
|
||||||
|
|
||||||
script.raise_event(Warnings.events.on_script_warning_added, {
|
|
||||||
name = Warnings.events.on_script_warning_added,
|
|
||||||
tick = game.tick,
|
|
||||||
player_index = player.index,
|
|
||||||
warning_count = warning_count,
|
|
||||||
reason = reason,
|
|
||||||
})
|
|
||||||
|
|
||||||
if warning_count > config.script_warning_limit then
|
|
||||||
Warnings.add_warning(player, "<server>", reason)
|
|
||||||
end
|
|
||||||
|
|
||||||
return warning_count
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Script warning removed event trigger due to it being looped in clear script warnings
|
|
||||||
-- @tparam LuaPlayer player the player who is having a script warning removed
|
|
||||||
-- @tparam number warning_count the number of warnings that the player has
|
|
||||||
local function script_warning_removed_event(player, warning_count)
|
|
||||||
script.raise_event(Warnings.events.on_script_warning_removed, {
|
|
||||||
name = Warnings.events.on_script_warning_removed,
|
|
||||||
tick = game.tick,
|
|
||||||
player_index = player.index,
|
|
||||||
warning_count = warning_count,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Removes a script warning from a player
|
|
||||||
-- @tparam LuaPlayer player the player to remove a script warning from
|
|
||||||
-- @treturn number the number of script warnings that the player has
|
|
||||||
function Warnings.remove_script_warning(player)
|
|
||||||
player = valid_player(player)
|
|
||||||
if not player then return end
|
|
||||||
|
|
||||||
local warnings = user_script_warnings[player.name]
|
|
||||||
if not warnings then return end
|
|
||||||
|
|
||||||
table.remove(warnings, 1)
|
|
||||||
|
|
||||||
script_warning_removed_event(player)
|
|
||||||
|
|
||||||
return #warnings
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Removes all script warnings from a player, emits event for each warning removed
|
|
||||||
-- @tparam LuaPlayer player the player to clear the script warnings from
|
|
||||||
function Warnings.clear_script_warnings(player)
|
|
||||||
player = valid_player(player)
|
|
||||||
if not player then return end
|
|
||||||
|
|
||||||
local warnings = user_script_warnings[player.name]
|
|
||||||
if not warnings then return end
|
|
||||||
|
|
||||||
local warning_count = #warnings
|
|
||||||
for n, _ in pairs(warnings) do
|
|
||||||
script_warning_removed_event(player, warning_count - n)
|
|
||||||
end
|
|
||||||
|
|
||||||
user_script_warnings[player.name] = nil
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- script warnings are removed after a certain amount of time to make them even more lienient
|
|
||||||
local script_warning_cool_down = config.script_warning_cool_down * 3600
|
|
||||||
Event.on_nth_tick(script_warning_cool_down / 4, function()
|
|
||||||
local cutoff = game.tick - script_warning_cool_down
|
|
||||||
for player_name, script_warnings in pairs(user_script_warnings) do
|
|
||||||
if #script_warnings > 0 then
|
|
||||||
for _, warning in pairs(script_warnings) do
|
|
||||||
if warning.tick < cutoff then
|
|
||||||
Warnings.remove_script_warning(player_name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
return Warnings
|
|
||||||
@@ -20,46 +20,38 @@ PlayerFilters:set_metadata{
|
|||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- Filters are stored by a single index across the ten pages of ten slots
|
||||||
|
local total_page_count = 10
|
||||||
|
local slots_per_page = 10
|
||||||
|
|
||||||
--- Loads your quickbar preset
|
--- Loads your quickbar preset
|
||||||
PlayerFilters:on_load(function(player_name, filters)
|
PlayerFilters:on_load(function(player_name, filters)
|
||||||
if not filters then filters = config[player_name] end
|
if not filters then filters = config[player_name] end
|
||||||
if not filters then return end
|
if not filters then return end
|
||||||
local player = game.players[player_name]
|
local player = game.players[player_name]
|
||||||
for i, item_name in pairs(filters) do
|
for index, item_name in pairs(filters) do
|
||||||
if item_name ~= nil and item_name ~= "" then
|
if item_name ~= nil and item_name ~= "" then
|
||||||
player.set_quick_bar_slot(i, item_name)
|
local page = math.ceil(index / slots_per_page)
|
||||||
|
local slot = (index - 1) % slots_per_page + 1
|
||||||
|
player.set_quick_bar_slot(page, slot, item_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local ignored_items = {
|
--- Saves your quickbar preset, only plain item filters can be saved
|
||||||
["blueprint"] = true,
|
|
||||||
["blueprint-book"] = true,
|
|
||||||
["deconstruction-planner"] = true,
|
|
||||||
["spidertron-remote"] = true,
|
|
||||||
["upgrade-planner"] = true,
|
|
||||||
}
|
|
||||||
|
|
||||||
--- Saves your quickbar preset to the script-output folder
|
|
||||||
Commands.new("save-quickbar", "Saves your Quickbar preset items to file")
|
Commands.new("save-quickbar", "Saves your Quickbar preset items to file")
|
||||||
:add_aliases{ "save-toolbar" }
|
:add_aliases{ "save-toolbar" }
|
||||||
:add_flags{ "disabled" }
|
|
||||||
:register(function(player)
|
:register(function(player)
|
||||||
local filters = {}
|
local filters = {}
|
||||||
|
|
||||||
error("2.1 changes to get_quick_bar_slot beak compatibility with 2.0; waiting for upstream")
|
for page = 1, total_page_count do
|
||||||
-- Upstream may add method to compat, or change inventory sync to have a quickbar only mode
|
for slot = 1, slots_per_page do
|
||||||
for i = 1, 100 do
|
-- Records, remotes and specific item instances hold data which can not be saved by name
|
||||||
--[[
|
local quick_bar_slot = player.get_quick_bar_slot(page, slot)
|
||||||
local slot = player.get_quick_bar_slot(i)
|
if quick_bar_slot and quick_bar_slot.type == "filter" then
|
||||||
-- Need to filter out blueprint and blueprint books because the slot is a LuaItemPrototype and does not contain a way to export blueprint data
|
filters[(page - 1) * slots_per_page + slot] = assert(quick_bar_slot.filter).name
|
||||||
if slot ~= nil then
|
|
||||||
local ignored = ignored_items[slot.name]
|
|
||||||
if ignored ~= true then
|
|
||||||
filters[i] = slot.name
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
]]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if next(filters) then
|
if next(filters) then
|
||||||
|
|||||||
@@ -113,16 +113,47 @@ if config.MachinesRemoved or config.TreesDestroyed or config.OreMined then
|
|||||||
Event.add(defines.events.on_player_mined_entity, on_event)
|
Event.add(defines.events.on_player_mined_entity, on_event)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Vehicles which credit their driver, or failing that their passenger, with what they hit
|
||||||
|
local crewed_vehicles = { car = true, ["spider-vehicle"] = true, locomotive = true }
|
||||||
|
|
||||||
|
--- Get the connected player behind the cause of damage or a death, nil for turrets, trains without a crew and the like
|
||||||
|
--- @param cause LuaEntity?
|
||||||
|
--- @return LuaPlayer?
|
||||||
|
local function get_cause_player(cause)
|
||||||
|
if not cause or not cause.valid then return nil end
|
||||||
|
|
||||||
|
local occupant = cause --- @type LuaEntity | LuaPlayer
|
||||||
|
if crewed_vehicles[cause.type] then
|
||||||
|
local crew = cause.get_driver() or cause.get_passenger()
|
||||||
|
if not crew then return nil end
|
||||||
|
occupant = crew
|
||||||
|
end
|
||||||
|
|
||||||
|
local player --- @type LuaPlayer?
|
||||||
|
if occupant.object_name == "LuaPlayer" then
|
||||||
|
player = occupant --[[@as LuaPlayer]]
|
||||||
|
elseif occupant.type == "character" then
|
||||||
|
player = occupant.player
|
||||||
|
end
|
||||||
|
|
||||||
|
if not player or not player.valid or not player.connected then return nil end
|
||||||
|
return player
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check that damage or a death counts against an entity, it must be hostile to the player
|
||||||
|
--- @param entity LuaEntity
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @return boolean
|
||||||
|
local function is_hostile(entity, player)
|
||||||
|
return entity.valid and entity.force ~= player.force and entity.force.name ~= "neutral"
|
||||||
|
end
|
||||||
|
|
||||||
--- Add DamageDealt if it is enabled
|
--- Add DamageDealt if it is enabled
|
||||||
if config.DamageDealt then
|
if config.DamageDealt then
|
||||||
local stat = Statistics:combine("DamageDealt")
|
local stat = Statistics:combine("DamageDealt")
|
||||||
Event.add(defines.events.on_entity_damaged, function(event)
|
Event.add(defines.events.on_entity_damaged, function(event)
|
||||||
local character = event.cause -- Check character is valid
|
local player = get_cause_player(event.cause)
|
||||||
if not character or not character.valid or character.type ~= "character" then return end
|
if not player or not is_hostile(event.entity, player) then return end
|
||||||
local player = character.player -- Check player is valid
|
|
||||||
if not player.valid or not player.connected then return end
|
|
||||||
local entity = event.entity -- Check entity is valid
|
|
||||||
if not entity.valid or entity.force == player.force or entity.force.name == "neutral" then return end
|
|
||||||
stat:increment(player, floor(event.final_damage_amount))
|
stat:increment(player, floor(event.final_damage_amount))
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
@@ -131,12 +162,8 @@ end
|
|||||||
if config.Kills then
|
if config.Kills then
|
||||||
local stat = Statistics:combine("Kills")
|
local stat = Statistics:combine("Kills")
|
||||||
Event.add(defines.events.on_entity_died, function(event)
|
Event.add(defines.events.on_entity_died, function(event)
|
||||||
local character = event.cause -- Check character is valid
|
local player = get_cause_player(event.cause)
|
||||||
if not character or not character.valid or character.type ~= "character" then return end
|
if not player or not is_hostile(event.entity, player) then return end
|
||||||
local player = character.player -- Check player is valid
|
|
||||||
if not player or not player.valid or not player.connected then return end
|
|
||||||
local entity = event.entity -- Check entity is valid
|
|
||||||
if not entity.valid or entity.force == player.force or entity.force.name == "neutral" then return end
|
|
||||||
stat:increment(player)
|
stat:increment(player)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -67,9 +67,6 @@ export const seedRoles: SeedRole[] = [
|
|||||||
"exp_scenario.command.tag_clear.always",
|
"exp_scenario.command.tag_clear.always",
|
||||||
"exp_scenario.command.spawn.always",
|
"exp_scenario.command.spawn.always",
|
||||||
"exp_scenario.command.clear_reports",
|
"exp_scenario.command.clear_reports",
|
||||||
"exp_scenario.command.clear_warnings",
|
|
||||||
"exp_scenario.command.clear_script_warnings",
|
|
||||||
"exp_scenario.command.clear_last_warnings",
|
|
||||||
"exp_scenario.command.clear_inventory",
|
"exp_scenario.command.clear_inventory",
|
||||||
"exp_scenario.command.kill_enemies",
|
"exp_scenario.command.kill_enemies",
|
||||||
"exp_scenario.command.remove_enemies",
|
"exp_scenario.command.remove_enemies",
|
||||||
@@ -103,8 +100,6 @@ export const seedRoles: SeedRole[] = [
|
|||||||
"exp_scenario.command.goto",
|
"exp_scenario.command.goto",
|
||||||
"exp_scenario.command.teleport",
|
"exp_scenario.command.teleport",
|
||||||
"exp_scenario.command.bring",
|
"exp_scenario.command.bring",
|
||||||
"exp_scenario.command.create_warning",
|
|
||||||
"exp_scenario.command.get_warnings",
|
|
||||||
"exp_scenario.command.get_reports",
|
"exp_scenario.command.get_reports",
|
||||||
"exp_scenario.command.protect_entity",
|
"exp_scenario.command.protect_entity",
|
||||||
"exp_scenario.command.protect_area",
|
"exp_scenario.command.protect_area",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Adds a commands that allow admins to jail and unjail
|
|||||||
local Commands = require("modules/exp_commands")
|
local Commands = require("modules/exp_commands")
|
||||||
local format_player_name = Commands.format_player_name_locale
|
local format_player_name = Commands.format_player_name_locale
|
||||||
|
|
||||||
local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail
|
local Jail = require("modules/exp_scenario/control/jail")
|
||||||
|
|
||||||
--- Puts a player into jail and removes all other roles.
|
--- Puts a player into jail and removes all other roles.
|
||||||
Commands.new("jail", { "exp-commands_jail.description" })
|
Commands.new("jail", { "exp-commands_jail.description" })
|
||||||
|
|||||||
@@ -12,10 +12,9 @@ local Commands = require("modules/exp_commands")
|
|||||||
local format_player_name = Commands.format_player_name_locale
|
local format_player_name = Commands.format_player_name_locale
|
||||||
|
|
||||||
local Roles = require("modules/exp_roles")
|
local Roles = require("modules/exp_roles")
|
||||||
local EntityProtection = require("modules.exp_legacy.modules.control.protection") --- @dep modules.control.protection
|
local EntityProtection = require("modules/exp_scenario/control/protection")
|
||||||
|
local get_entity_key = EntityProtection.get_entity_key
|
||||||
local format_string = string.format
|
local get_area_key = EntityProtection.get_area_key
|
||||||
local floor = math.floor
|
|
||||||
|
|
||||||
local Selection = require("modules/exp_util/selection")
|
local Selection = require("modules/exp_util/selection")
|
||||||
local SelectEntities = Selection.connect("ExpCommand_ProtectEntity")
|
local SelectEntities = Selection.connect("ExpCommand_ProtectEntity")
|
||||||
@@ -28,21 +27,6 @@ Storage.register({
|
|||||||
renders = tbl.renders
|
renders = tbl.renders
|
||||||
end)
|
end)
|
||||||
|
|
||||||
--- Get the key used in protected_entities
|
|
||||||
--- @param entity LuaEntity
|
|
||||||
--- @return string
|
|
||||||
local function get_entity_key(entity)
|
|
||||||
return format_string("%i,%i", floor(entity.position.x), floor(entity.position.y))
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get the key used in protected_areas
|
|
||||||
--- TODO expose this from EntityProtection
|
|
||||||
--- @param area BoundingBox.struct
|
|
||||||
--- @return string
|
|
||||||
local function get_area_key(area)
|
|
||||||
return format_string("%i,%i", floor(area.left_top.x), floor(area.left_top.y))
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Show a protected entity to a player
|
--- Show a protected entity to a player
|
||||||
--- @param player LuaPlayer
|
--- @param player LuaPlayer
|
||||||
--- @param entity LuaEntity
|
--- @param entity LuaEntity
|
||||||
@@ -232,6 +216,6 @@ end
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
events = {
|
events = {
|
||||||
[EntityProtection.events.on_repeat_violation] = on_repeat_violation,
|
[EntityProtection.on_repeat_violation] = on_repeat_violation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Adds commands relating to spectate and follow
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local Commands = require("modules/exp_commands")
|
local Commands = require("modules/exp_commands")
|
||||||
local Spectate = require("modules.exp_legacy.modules.control.spectate") --- @dep modules.control.spectate
|
local Spectate = require("modules/exp_scenario/control/spectate")
|
||||||
|
|
||||||
--- Toggles spectator mode for the caller
|
--- Toggles spectator mode for the caller
|
||||||
Commands.new("spectate", { "exp-commands_spectate.description-spectate" })
|
Commands.new("spectate", { "exp-commands_spectate.description-spectate" })
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
--[[-- Commands - Warnings
|
|
||||||
Adds a commands that allow admins to warn other players
|
|
||||||
]]
|
|
||||||
|
|
||||||
local Commands = require("modules/exp_commands")
|
|
||||||
local format_player_name = Commands.format_player_name_locale
|
|
||||||
|
|
||||||
local Warnings = require("modules.exp_legacy.modules.control.warnings") --- @dep modules.control.warnings
|
|
||||||
local config = require("modules.exp_legacy.config.warnings") --- @dep config.warnings
|
|
||||||
|
|
||||||
--- Gives a warning to a player; may lead to automatic script action.
|
|
||||||
Commands.new("create-warning", { "exp-commands_warnings.description-create" })
|
|
||||||
:argument("player", { "exp-commands_warnings.arg-player-create" }, Commands.types.lower_role_player)
|
|
||||||
:argument("reason", { "exp-commands_warnings.arg-reason" }, Commands.types.string)
|
|
||||||
:enable_auto_concatenation()
|
|
||||||
:add_aliases{ "warn" }
|
|
||||||
:add_flags{ "admin_only" }
|
|
||||||
:register(function(player, other_player, reason)
|
|
||||||
--- @cast other_player LuaPlayer
|
|
||||||
--- @cast reason string
|
|
||||||
Warnings.add_warning(other_player, player.name, reason)
|
|
||||||
local player_name = format_player_name(player)
|
|
||||||
local other_player_name = format_player_name(other_player)
|
|
||||||
game.print{ "exp-commands_warnings.create", other_player_name, player_name, reason }
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Gets a list of all warnings that a player has on them. If no player then lists all players and the number of warnings on them.
|
|
||||||
Commands.new("get-warnings", { "exp-commands_warnings.description-get" })
|
|
||||||
:optional("player", { "exp-commands_warnings.arg-player-get" }, Commands.types.player)
|
|
||||||
:add_aliases{ "warnings" }
|
|
||||||
:add_flags{ "admin_only" }
|
|
||||||
:register(function(player, other_player)
|
|
||||||
--- @cast other_player LuaPlayer?
|
|
||||||
if other_player then
|
|
||||||
local warnings = Warnings.get_warnings(player)
|
|
||||||
local script_warnings = Warnings.get_script_warnings(player)
|
|
||||||
local other_player_name = format_player_name(other_player)
|
|
||||||
Commands.print{ "exp-commands_warnings.player-title", other_player_name, #warnings, #script_warnings, config.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 }
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local warnings = Warnings.user_warnings:get_all()
|
|
||||||
local script_warnings = Warnings.user_script_warnings
|
|
||||||
Commands.print{ "exp-commands_warnings.warnings-title" }
|
|
||||||
for player_name, player_warnings in pairs(warnings) do
|
|
||||||
local player_name_formatted = format_player_name(player_name)
|
|
||||||
local script_warning_count = script_warnings[player_name] and #script_warnings[player_name] or 0
|
|
||||||
Commands.print{ "exp-commands_warnings.list-element", player_name_formatted, #player_warnings, script_warning_count, config.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.script_warning_limit }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Clears all warnings from a player
|
|
||||||
Commands.new("clear-warnings", { "exp-commands_warnings.description-clear" })
|
|
||||||
:argument("player", { "exp-commands_warnings.arg-player-clear" }, Commands.types.player)
|
|
||||||
:add_flags{ "admin_only" }
|
|
||||||
:register(function(player, other_player)
|
|
||||||
--- @cast other_player LuaPlayer
|
|
||||||
Warnings.clear_warnings(other_player, player.name)
|
|
||||||
Warnings.clear_script_warnings(other_player)
|
|
||||||
local player_name = format_player_name(player)
|
|
||||||
local other_player_name = format_player_name(other_player)
|
|
||||||
game.print{ "exp-commands_warnings.cleared", other_player_name, player_name }
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Clears all script warnings from a player
|
|
||||||
Commands.new("clear-script-warnings", { "exp-commands_warnings.description-clear-script" })
|
|
||||||
:argument("player", { "exp-commands_warnings.arg-player-clear" }, Commands.types.player)
|
|
||||||
:add_flags{ "admin_only" }
|
|
||||||
:register(function(player, other_player)
|
|
||||||
--- @cast other_player LuaPlayer
|
|
||||||
Warnings.clear_script_warnings(other_player)
|
|
||||||
local player_name = format_player_name(player)
|
|
||||||
local other_player_name = format_player_name(other_player)
|
|
||||||
game.print{ "exp-commands_warnings.cleared-script", other_player_name, player_name }
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- Clears the last warning that was given to a player
|
|
||||||
Commands.new("clear-last-warnings", { "exp-commands_warnings.description-clear-last" })
|
|
||||||
:argument("player", { "exp-commands_warnings.arg-player-clear" }, Commands.types.player)
|
|
||||||
:add_flags{ "admin_only" }
|
|
||||||
:register(function(player, other_player)
|
|
||||||
--- @cast other_player LuaPlayer
|
|
||||||
Warnings.remove_warning(other_player, player.name)
|
|
||||||
local player_name = format_player_name(player)
|
|
||||||
local other_player_name = format_player_name(other_player)
|
|
||||||
game.print{ "exp-commands_warnings.cleared-last", other_player_name, player_name }
|
|
||||||
end)
|
|
||||||
@@ -38,7 +38,6 @@ require("modules/exp_scenario/commands/surface")
|
|||||||
require("modules/exp_scenario/commands/teleport")
|
require("modules/exp_scenario/commands/teleport")
|
||||||
require("modules/exp_scenario/commands/trains")
|
require("modules/exp_scenario/commands/trains")
|
||||||
require("modules/exp_scenario/commands/vlayer")
|
require("modules/exp_scenario/commands/vlayer")
|
||||||
require("modules/exp_scenario/commands/warnings")
|
|
||||||
require("modules/exp_scenario/commands/waterfill")
|
require("modules/exp_scenario/commands/waterfill")
|
||||||
|
|
||||||
--- Control
|
--- Control
|
||||||
@@ -60,11 +59,13 @@ add(require("modules/exp_scenario/control/inventory_clear"))
|
|||||||
add(require("modules/exp_scenario/control/mine_depletion"))
|
add(require("modules/exp_scenario/control/mine_depletion"))
|
||||||
add(require("modules/exp_scenario/control/nuke_protection"))
|
add(require("modules/exp_scenario/control/nuke_protection"))
|
||||||
add(require("modules/exp_scenario/control/pollution_grading"))
|
add(require("modules/exp_scenario/control/pollution_grading"))
|
||||||
|
add(require("modules/exp_scenario/control/protection"))
|
||||||
add(require("modules/exp_scenario/control/protection_jail"))
|
add(require("modules/exp_scenario/control/protection_jail"))
|
||||||
add(require("modules/exp_scenario/control/report_jail"))
|
add(require("modules/exp_scenario/control/report_jail"))
|
||||||
add(require("modules/exp_scenario/control/research"))
|
add(require("modules/exp_scenario/control/research"))
|
||||||
add(require("modules/exp_scenario/control/roles"))
|
add(require("modules/exp_scenario/control/roles"))
|
||||||
add(require("modules/exp_scenario/control/spawn_area"))
|
add(require("modules/exp_scenario/control/spawn_area"))
|
||||||
|
add(require("modules/exp_scenario/control/spectate"))
|
||||||
add(require("modules/exp_scenario/control/station_auto_name"))
|
add(require("modules/exp_scenario/control/station_auto_name"))
|
||||||
|
|
||||||
--- Guis
|
--- Guis
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ Log certain actions into a file when events are triggered
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local ExpUtil = require("modules/exp_util")
|
local ExpUtil = require("modules/exp_util")
|
||||||
|
local Storage = require("modules/exp_util/storage")
|
||||||
local Roles = require("modules/exp_roles")
|
local Roles = require("modules/exp_roles")
|
||||||
local config = require("modules.exp_legacy.config.deconlog")
|
local config = require("modules.exp_legacy.config.deconlog")
|
||||||
|
|
||||||
@@ -130,31 +131,79 @@ local function on_player_mined_entity(event)
|
|||||||
add_log_line(player, "mined_entity", format_entity(event.entity))
|
add_log_line(player, "mined_entity", format_entity(event.entity))
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Log when rocket is fired
|
--- Ammo which is logged when fired
|
||||||
|
local logged_ammo = {
|
||||||
|
["rocket"] = config.fired_rocket,
|
||||||
|
["explosive-rocket"] = config.fired_explosive_rocket,
|
||||||
|
["atomic-bomb"] = config.fired_nuke,
|
||||||
|
}
|
||||||
|
|
||||||
|
--- @class ExpScenario_DeconstructionLog.AmmoSlot
|
||||||
|
--- @field name string
|
||||||
|
--- @field count number
|
||||||
|
|
||||||
|
--- The last seen contents of each ammo slot, keyed by player index then slot index
|
||||||
|
local ammo_slots = {} --- @type table<uint, table<uint, ExpScenario_DeconstructionLog.AmmoSlot>>
|
||||||
|
Storage.register(ammo_slots, function(tbl)
|
||||||
|
ammo_slots = tbl
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Read the ammo slots of a player, empty while they have no character
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @return table<uint, ExpScenario_DeconstructionLog.AmmoSlot>
|
||||||
|
local function read_ammo_slots(player)
|
||||||
|
local slots = {}
|
||||||
|
if not player.character then return slots end
|
||||||
|
|
||||||
|
local character_ammo = assert(player.get_inventory(defines.inventory.character_ammo))
|
||||||
|
for index = 1, #character_ammo do
|
||||||
|
local stack = character_ammo[index --[[@as uint]]]
|
||||||
|
if stack.valid_for_read then
|
||||||
|
slots[index] = { name = stack.name, count = stack.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return slots
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Log a shot, there is no fired event so a slot losing one of the same ammo is taken as a shot
|
||||||
--- @param event EventData.on_player_ammo_inventory_changed
|
--- @param event EventData.on_player_ammo_inventory_changed
|
||||||
local function on_player_ammo_inventory_changed(event)
|
local function on_player_ammo_inventory_changed(event)
|
||||||
local player = get_log_player(event)
|
local player = get_log_player(event)
|
||||||
if not player or not player.character then return end
|
if not player then return end
|
||||||
|
|
||||||
local character_ammo = assert(player.get_inventory(defines.inventory.character_ammo))
|
local previous_slots = ammo_slots[player.index] or {}
|
||||||
local gun_index = player.character.selected_gun_index --[[@as uint]]
|
local slots = read_ammo_slots(player)
|
||||||
local item = character_ammo[gun_index]
|
ammo_slots[player.index] = slots
|
||||||
if not item or not item.valid or not item.valid_for_read then
|
|
||||||
return
|
for index, previous in pairs(previous_slots) do
|
||||||
|
local current = slots[index]
|
||||||
|
local fired = nil --- @type string?
|
||||||
|
if current then
|
||||||
|
if previous.name == current.name and previous.count == current.count + 1 then
|
||||||
|
fired = current.name
|
||||||
|
end
|
||||||
|
elseif previous.count == 1 then
|
||||||
|
fired = previous.name
|
||||||
end
|
end
|
||||||
|
|
||||||
local action_name = "shot-" .. item.name
|
if fired and logged_ammo[fired] then
|
||||||
if not config.fired_rocket and action_name == "shot-rocket" then
|
add_log_line(player, "shot-" .. fired, format_position(player.physical_position), format_position(player.shooting_state.position))
|
||||||
return
|
end
|
||||||
elseif not config.fired_explosive_rocket and action_name == "shot-explosive-rocket" then
|
end
|
||||||
return
|
|
||||||
elseif not config.fired_nuke and action_name == "shot-atomic-bomb" then
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
add_log_line(player, action_name, format_position(player.physical_position), format_position(player.shooting_state.position))
|
--- Read the ammo of a player when they join or get a new character, so the first shot afterwards is seen
|
||||||
|
--- @param event EventData.on_player_joined_game | EventData.on_player_respawned
|
||||||
|
local function on_player_character_changed(event)
|
||||||
|
local player = assert(game.get_player(event.player_index))
|
||||||
|
ammo_slots[player.index] = read_ammo_slots(player)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Forget the ammo of a player who left
|
||||||
|
--- @param event EventData.on_player_left_game
|
||||||
|
local function on_player_left_game(event)
|
||||||
|
ammo_slots[event.player_index] = nil
|
||||||
|
end
|
||||||
|
|
||||||
local e = defines.events
|
local e = defines.events
|
||||||
local events = {
|
local events = {
|
||||||
@@ -175,6 +224,9 @@ end
|
|||||||
|
|
||||||
if config.fired_rocket or config.fired_explosive_rocket or config.fired_nuke then
|
if config.fired_rocket or config.fired_explosive_rocket or config.fired_nuke then
|
||||||
events[e.on_player_ammo_inventory_changed] = on_player_ammo_inventory_changed
|
events[e.on_player_ammo_inventory_changed] = on_player_ammo_inventory_changed
|
||||||
|
events[e.on_player_joined_game] = on_player_character_changed
|
||||||
|
events[e.on_player_respawned] = on_player_character_changed
|
||||||
|
events[e.on_player_left_game] = on_player_left_game
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ end
|
|||||||
|
|
||||||
--- Repeated protected entity mining
|
--- Repeated protected entity mining
|
||||||
if config.entity_protection then
|
if config.entity_protection then
|
||||||
local EntityProtection = require("modules.exp_legacy.modules.control.protection")
|
local EntityProtection = require("modules/exp_scenario/control/protection")
|
||||||
events[EntityProtection.events.on_repeat_violation] = function(event)
|
events[EntityProtection.on_repeat_violation] = function(event)
|
||||||
local player_name = get_player_name(event)
|
local player_name = get_player_name(event)
|
||||||
emit_event{
|
emit_event{
|
||||||
title = "Entity Protection",
|
title = "Entity Protection",
|
||||||
@@ -131,44 +131,10 @@ if config.player_reports then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Warnings added and removed
|
|
||||||
if config.player_warnings then
|
|
||||||
local Warnings = require("modules.exp_legacy.modules.control.warnings")
|
|
||||||
events[Warnings.events.on_warning_added] = function(event)
|
|
||||||
local player_name, by_player_name = get_player_name(event)
|
|
||||||
local player = assert(game.get_player(player_name))
|
|
||||||
emit_event{
|
|
||||||
title = "Warning",
|
|
||||||
description = "A player has been given a warning",
|
|
||||||
color = Colors.yellow,
|
|
||||||
fields = {
|
|
||||||
{ name = "Player", inline = true, value = append_playtime(player_name) },
|
|
||||||
{ name = "By", inline = true, value = append_playtime(by_player_name) },
|
|
||||||
{ name = "Report Count", inline = true, value = Warnings.count_warnings(player) },
|
|
||||||
{ name = "Reason", value = event.reason },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
end
|
|
||||||
events[Warnings.events.on_warning_removed] = function(event)
|
|
||||||
if event.batch ~= 1 then return end
|
|
||||||
local player_name = get_player_name(event)
|
|
||||||
emit_event{
|
|
||||||
title = "Warnings Removed",
|
|
||||||
description = "A player has a warning removed",
|
|
||||||
color = Colors.green,
|
|
||||||
fields = {
|
|
||||||
{ name = "Player", inline = true, value = append_playtime(player_name) },
|
|
||||||
{ name = "By", inline = true, value = append_playtime(event.removed_by_name) },
|
|
||||||
{ name = "Report Count", inline = true, value = tostring(event.batch_count) },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- When a player is jailed or unjailed
|
--- When a player is jailed or unjailed
|
||||||
if config.player_jail then
|
if config.player_jail then
|
||||||
local Jail = require("modules.exp_legacy.modules.control.jail")
|
local Jail = require("modules/exp_scenario/control/jail")
|
||||||
events[Jail.events.on_player_jailed] = function(event)
|
events[Jail.on_player_jailed] = function(event)
|
||||||
local player_name, by_player_name = get_player_name(event)
|
local player_name, by_player_name = get_player_name(event)
|
||||||
emit_event{
|
emit_event{
|
||||||
title = "Jail",
|
title = "Jail",
|
||||||
@@ -181,7 +147,7 @@ if config.player_jail then
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
events[Jail.events.on_player_unjailed] = function(event)
|
events[Jail.on_player_unjailed] = function(event)
|
||||||
local player_name, by_player_name = get_player_name(event)
|
local player_name, by_player_name = get_player_name(event)
|
||||||
emit_event{
|
emit_event{
|
||||||
title = "Unjail",
|
title = "Unjail",
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
--[[-- Control - Jail
|
||||||
|
Adds a way to jail players, the jail role suppresses all of their other roles
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Roles = require("modules/exp_roles")
|
||||||
|
|
||||||
|
--- @class ExpScenario_Jail
|
||||||
|
local Jail = {
|
||||||
|
--- Raised when a player is put into jail
|
||||||
|
--- @type EventData.ExpScenario_Jail.on_player_jailed
|
||||||
|
on_player_jailed = script.generate_event_name(),
|
||||||
|
--- Raised when a player is taken out of jail
|
||||||
|
--- @type EventData.ExpScenario_Jail.on_player_unjailed
|
||||||
|
on_player_unjailed = script.generate_event_name(),
|
||||||
|
}
|
||||||
|
|
||||||
|
--- @class EventData.ExpScenario_Jail.on_player_jailed : EventData
|
||||||
|
--- @field player_index uint
|
||||||
|
--- @field by_player_name string
|
||||||
|
--- @field reason string
|
||||||
|
|
||||||
|
--- @class EventData.ExpScenario_Jail.on_player_unjailed : EventData
|
||||||
|
--- @field player_index uint
|
||||||
|
--- @field by_player_name string
|
||||||
|
|
||||||
|
--- The role given to jailed players, it has a higher priority than every other role
|
||||||
|
--- @return ExpRoles.Role
|
||||||
|
local function get_jail_role()
|
||||||
|
return (assert(Roles.get_role_by_name("Jail"), "The Jail role does not exist"))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a player is in jail
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @return boolean
|
||||||
|
function Jail.is_jailed(player)
|
||||||
|
return get_jail_role():has_player(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Put a player into jail, which suppresses all of their other roles
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @param by_player_name string
|
||||||
|
--- @param reason string
|
||||||
|
--- @return boolean # False when the player was already in jail
|
||||||
|
function Jail.jail_player(player, by_player_name, reason)
|
||||||
|
local role = get_jail_role()
|
||||||
|
if role:has_player(player) then return false end
|
||||||
|
|
||||||
|
-- Stop whatever the player is doing, the jail permission group stops them from starting again
|
||||||
|
player.walking_state = { walking = false, direction = player.walking_state.direction }
|
||||||
|
player.riding_state = { acceleration = defines.riding.acceleration.nothing, direction = player.riding_state.direction }
|
||||||
|
player.mining_state = { mining = false }
|
||||||
|
player.shooting_state = { state = defines.shooting.not_shooting, position = player.shooting_state.position }
|
||||||
|
player.picking_state = false
|
||||||
|
player.repair_state = { repairing = false, position = player.repair_state.position }
|
||||||
|
|
||||||
|
role:assign(player, { by_player_name = by_player_name, silent = true })
|
||||||
|
|
||||||
|
script.raise_event(Jail.on_player_jailed, {
|
||||||
|
player_index = player.index,
|
||||||
|
by_player_name = by_player_name,
|
||||||
|
reason = reason,
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Take a player out of jail, which restores all of their other roles
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @param by_player_name string
|
||||||
|
--- @return boolean # False when the player was not in jail
|
||||||
|
function Jail.unjail_player(player, by_player_name)
|
||||||
|
local role = get_jail_role()
|
||||||
|
if not role:has_player(player) then return false end
|
||||||
|
|
||||||
|
role:unassign(player, { by_player_name = by_player_name, silent = true })
|
||||||
|
|
||||||
|
script.raise_event(Jail.on_player_unjailed, {
|
||||||
|
player_index = player.index,
|
||||||
|
by_player_name = by_player_name,
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return Jail
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
--[[-- Control - Protection
|
||||||
|
Protects entities and areas from being mined by players other than the one who placed them
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Storage = require("modules/exp_util/storage")
|
||||||
|
local Roles = require("modules/exp_roles")
|
||||||
|
local config = require("modules.exp_legacy.config.protection")
|
||||||
|
|
||||||
|
local format_string = string.format
|
||||||
|
local floor = math.floor
|
||||||
|
|
||||||
|
--- @class ExpScenario_Protection
|
||||||
|
local Protection = {
|
||||||
|
--- Raised when a player mines a protected entity
|
||||||
|
--- @type EventData.ExpScenario_Protection.on_player_mined_protected
|
||||||
|
on_player_mined_protected = script.generate_event_name(),
|
||||||
|
--- Raised when a player mines protected entities repeatedly, or one which always counts as repeated
|
||||||
|
--- @type EventData.ExpScenario_Protection.on_repeat_violation
|
||||||
|
on_repeat_violation = script.generate_event_name(),
|
||||||
|
--- Names of entities which are always protected
|
||||||
|
--- @type string[]
|
||||||
|
protected_entity_names = config.always_protected_names,
|
||||||
|
--- Types of entities which are always protected
|
||||||
|
--- @type string[]
|
||||||
|
protected_entity_types = config.always_protected_types,
|
||||||
|
--- @package
|
||||||
|
events = {},
|
||||||
|
--- @package
|
||||||
|
on_nth_tick = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
--- @class EventData.ExpScenario_Protection.on_player_mined_protected : EventData.on_pre_player_mined_item
|
||||||
|
--- @class EventData.ExpScenario_Protection.on_repeat_violation : EventData.on_pre_player_mined_item
|
||||||
|
|
||||||
|
--- @class ExpScenario_Protection.Repeat
|
||||||
|
--- @field last uint Tick of the last protected removal
|
||||||
|
--- @field count number Protected removals since the last repeat violation
|
||||||
|
|
||||||
|
--- @param values string[]
|
||||||
|
--- @return table<string, true>
|
||||||
|
local function to_set(values)
|
||||||
|
local set = {}
|
||||||
|
for _, value in ipairs(values) do
|
||||||
|
set[value] = true
|
||||||
|
end
|
||||||
|
return set
|
||||||
|
end
|
||||||
|
|
||||||
|
local always_protected_names = to_set(config.always_protected_names)
|
||||||
|
local always_protected_types = to_set(config.always_protected_types)
|
||||||
|
local always_trigger_repeat_names = to_set(config.always_trigger_repeat_names)
|
||||||
|
local always_trigger_repeat_types = to_set(config.always_trigger_repeat_types)
|
||||||
|
|
||||||
|
local protected_entities = {} --- @type table<uint, table<string, LuaEntity>> Keyed by surface index then entity key
|
||||||
|
local protected_areas = {} --- @type table<uint, table<string, BoundingBox>> Keyed by surface index then area key
|
||||||
|
local repeats = {} --- @type table<string, ExpScenario_Protection.Repeat> Keyed by player name
|
||||||
|
|
||||||
|
Storage.register({
|
||||||
|
protected_entities = protected_entities,
|
||||||
|
protected_areas = protected_areas,
|
||||||
|
repeats = repeats,
|
||||||
|
}, function(tbl)
|
||||||
|
protected_entities = tbl.protected_entities
|
||||||
|
protected_areas = tbl.protected_areas
|
||||||
|
repeats = tbl.repeats
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Get the key an entity is stored under
|
||||||
|
--- @param entity LuaEntity
|
||||||
|
--- @return string
|
||||||
|
function Protection.get_entity_key(entity)
|
||||||
|
return format_string("%i,%i", floor(entity.position.x), floor(entity.position.y))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the key an area is stored under
|
||||||
|
--- @param area BoundingBox
|
||||||
|
--- @return string
|
||||||
|
function Protection.get_area_key(area)
|
||||||
|
return format_string("%i,%i", floor(area.left_top.x), floor(area.left_top.y))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Protect an entity
|
||||||
|
--- @param entity LuaEntity
|
||||||
|
function Protection.add_entity(entity)
|
||||||
|
local entities = protected_entities[entity.surface.index]
|
||||||
|
if not entities then
|
||||||
|
entities = {}
|
||||||
|
protected_entities[entity.surface.index] = entities
|
||||||
|
end
|
||||||
|
entities[Protection.get_entity_key(entity)] = entity
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove the protection from an entity
|
||||||
|
--- @param entity LuaEntity
|
||||||
|
function Protection.remove_entity(entity)
|
||||||
|
local entities = protected_entities[entity.surface.index]
|
||||||
|
if not entities then return end
|
||||||
|
entities[Protection.get_entity_key(entity)] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the protected entities on a surface, always protected entities are not included
|
||||||
|
--- @param surface LuaSurface
|
||||||
|
--- @return table<string, LuaEntity>
|
||||||
|
function Protection.get_entities(surface)
|
||||||
|
return protected_entities[surface.index] or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if an entity is protected, either directly or by its name or type
|
||||||
|
--- @param entity LuaEntity
|
||||||
|
--- @return boolean
|
||||||
|
function Protection.is_entity_protected(entity)
|
||||||
|
if always_protected_names[entity.name] or always_protected_types[entity.type] then return true end
|
||||||
|
local entities = protected_entities[entity.surface.index]
|
||||||
|
if not entities then return false end
|
||||||
|
return entities[Protection.get_entity_key(entity)] == entity
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Protect every position within an area
|
||||||
|
--- @param surface LuaSurface
|
||||||
|
--- @param area BoundingBox
|
||||||
|
function Protection.add_area(surface, area)
|
||||||
|
local areas = protected_areas[surface.index]
|
||||||
|
if not areas then
|
||||||
|
areas = {}
|
||||||
|
protected_areas[surface.index] = areas
|
||||||
|
end
|
||||||
|
areas[Protection.get_area_key(area)] = area
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove the protection from an area
|
||||||
|
--- @param surface LuaSurface
|
||||||
|
--- @param area BoundingBox
|
||||||
|
function Protection.remove_area(surface, area)
|
||||||
|
local areas = protected_areas[surface.index]
|
||||||
|
if not areas then return end
|
||||||
|
areas[Protection.get_area_key(area)] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the protected areas on a surface
|
||||||
|
--- @param surface LuaSurface
|
||||||
|
--- @return table<string, BoundingBox>
|
||||||
|
function Protection.get_areas(surface)
|
||||||
|
return protected_areas[surface.index] or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a position is within a protected area
|
||||||
|
--- @param surface LuaSurface
|
||||||
|
--- @param position MapPosition
|
||||||
|
--- @return boolean
|
||||||
|
function Protection.is_position_protected(surface, position)
|
||||||
|
local areas = protected_areas[surface.index]
|
||||||
|
if not areas then return false end
|
||||||
|
for _, area in pairs(areas) do
|
||||||
|
if area.left_top.x <= position.x and area.left_top.y <= position.y
|
||||||
|
and area.right_bottom.x >= position.x and area.right_bottom.y >= position.y
|
||||||
|
then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Players are never checked against their own entities, and can be excluded by permission or admin status
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @param entity LuaEntity
|
||||||
|
--- @return boolean
|
||||||
|
local function is_ignored(player, entity)
|
||||||
|
if config.ignore_admins and player.admin then return true end
|
||||||
|
if entity.last_user == nil or entity.last_user.index == player.index then return true end
|
||||||
|
if config.ignore_permission and Roles.player_has_permission(player, config.ignore_permission) then return true end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Raise the protection events, the event data is reused with the name replaced
|
||||||
|
--- @param event EventData.on_pre_player_mined_item
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
local function raise_violation(event, player)
|
||||||
|
local player_repeats = repeats[player.name]
|
||||||
|
if not player_repeats then
|
||||||
|
player_repeats = { last = game.tick, count = 0 }
|
||||||
|
repeats[player.name] = player_repeats
|
||||||
|
end
|
||||||
|
player_repeats.last = game.tick
|
||||||
|
player_repeats.count = player_repeats.count + 1
|
||||||
|
|
||||||
|
script.raise_event(Protection.on_player_mined_protected, event)
|
||||||
|
|
||||||
|
local entity = event.entity
|
||||||
|
local always_repeat = always_trigger_repeat_names[entity.name] or always_trigger_repeat_types[entity.type]
|
||||||
|
if always_repeat or player_repeats.count >= config.repeat_count then
|
||||||
|
player_repeats.count = 0
|
||||||
|
script.raise_event(Protection.on_repeat_violation, event)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Raise the protection events when a protected entity is mined, then forget the entity
|
||||||
|
--- @param event EventData.on_pre_player_mined_item
|
||||||
|
local function on_pre_player_mined_item(event)
|
||||||
|
local entity = event.entity
|
||||||
|
local player = game.players[event.player_index]
|
||||||
|
if
|
||||||
|
not is_ignored(player, entity)
|
||||||
|
and (Protection.is_entity_protected(entity) or Protection.is_position_protected(entity.surface, entity.position))
|
||||||
|
then
|
||||||
|
raise_violation(event, player)
|
||||||
|
end
|
||||||
|
|
||||||
|
Protection.remove_entity(entity)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Forget an entity once it no longer exists
|
||||||
|
--- @param event { entity: LuaEntity }
|
||||||
|
local function on_entity_removed(event)
|
||||||
|
Protection.remove_entity(event.entity)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Forget protected removals older than the repeat lifetime
|
||||||
|
local function clear_old_repeats()
|
||||||
|
local old = game.tick - config.repeat_lifetime
|
||||||
|
for player_name, player_repeats in pairs(repeats) do
|
||||||
|
if player_repeats.last <= old then
|
||||||
|
repeats[player_name] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local e = defines.events
|
||||||
|
|
||||||
|
Protection.events[e.on_pre_player_mined_item] = on_pre_player_mined_item
|
||||||
|
Protection.events[e.on_space_platform_pre_mined] = on_entity_removed
|
||||||
|
Protection.events[e.on_robot_pre_mined] = on_entity_removed
|
||||||
|
Protection.events[e.on_entity_died] = on_entity_removed
|
||||||
|
Protection.events[e.script_raised_destroy] = on_entity_removed
|
||||||
|
Protection.on_nth_tick[config.refresh_rate] = clear_old_repeats
|
||||||
|
|
||||||
|
return Protection
|
||||||
@@ -4,8 +4,8 @@ When a player triggers protection multiple times they are automatically jailed
|
|||||||
|
|
||||||
local ExpUtil = require("modules/exp_util")
|
local ExpUtil = require("modules/exp_util")
|
||||||
local Storage = require("modules/exp_util/storage")
|
local Storage = require("modules/exp_util/storage")
|
||||||
local Jail = require("modules.exp_legacy.modules.control.jail")
|
local Jail = require("modules/exp_scenario/control/jail")
|
||||||
local Protection = require("modules.exp_legacy.modules.control.protection")
|
local Protection = require("modules/exp_scenario/control/protection")
|
||||||
|
|
||||||
local format_player_name = ExpUtil.format_player_name_locale
|
local format_player_name = ExpUtil.format_player_name_locale
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ local e = defines.events
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
events = {
|
events = {
|
||||||
[Protection.events.on_repeat_violation] = on_repeat_violation,
|
[Protection.on_repeat_violation] = on_repeat_violation,
|
||||||
[e.on_player_left_game] = on_player_left_game,
|
[e.on_player_left_game] = on_player_left_game,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ When a player is reported, the player is automatically jailed if the combined pl
|
|||||||
]]
|
]]
|
||||||
|
|
||||||
local ExpUtil = require("modules/exp_util")
|
local ExpUtil = require("modules/exp_util")
|
||||||
local Jail = require("modules.exp_legacy.modules.control.jail")
|
local Jail = require("modules/exp_scenario/control/jail")
|
||||||
local Reports = require("modules.exp_legacy.modules.control.reports")
|
local Reports = require("modules.exp_legacy.modules.control.reports")
|
||||||
|
|
||||||
local max = math.max
|
local max = math.max
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
--[[-- Control - Spectate
|
||||||
|
Lets players spectate without losing their character, and follow other players or entities
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Storage = require("modules/exp_util/storage")
|
||||||
|
local Gui = require("modules/exp_gui")
|
||||||
|
|
||||||
|
--- @class ExpScenario_Spectate
|
||||||
|
local Spectate = {
|
||||||
|
--- @package
|
||||||
|
events = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
--- @class ExpScenario_Spectate.Following
|
||||||
|
--- @field player LuaPlayer
|
||||||
|
--- @field target LuaPlayer | LuaEntity
|
||||||
|
--- @field position MapPosition Where the player was after the last update, moving away stops following
|
||||||
|
--- @field started_spectate boolean True when start_follow put the player into spectator mode
|
||||||
|
--- @field stop boolean? Set when following must end on the next tick
|
||||||
|
|
||||||
|
local following = {} --- @type table<uint, ExpScenario_Spectate.Following> Keyed by player index
|
||||||
|
local spectating = {} --- @type table<uint, LuaEntity> The character a player returns to, keyed by player index
|
||||||
|
|
||||||
|
Storage.register({
|
||||||
|
following = following,
|
||||||
|
spectating = spectating,
|
||||||
|
}, function(tbl)
|
||||||
|
following = tbl.following
|
||||||
|
spectating = tbl.spectating
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Label shown while following, clicking it or pressing escape stops following
|
||||||
|
--- @class ExpScenario_Spectate.follow_label: ExpElement
|
||||||
|
--- @overload fun(parent: LuaGuiElement, target: LuaPlayer | LuaEntity): LuaGuiElement
|
||||||
|
local follow_label = Gui.define("spectate/follow_label")
|
||||||
|
:draw(function(_, parent, target)
|
||||||
|
Gui.destroy_if_valid(parent.follow_label)
|
||||||
|
|
||||||
|
local label = parent.add{
|
||||||
|
type = "label",
|
||||||
|
name = "follow_label",
|
||||||
|
style = "frame_title",
|
||||||
|
caption = { "exp_spectate.follow-label", target.name },
|
||||||
|
}
|
||||||
|
|
||||||
|
local player = Gui.get_player(parent)
|
||||||
|
local res = player.display_resolution
|
||||||
|
label.location = { 0, res.height - 150 }
|
||||||
|
label.style.width = res.width
|
||||||
|
label.style.horizontal_align = "center"
|
||||||
|
player.opened = label
|
||||||
|
|
||||||
|
return label
|
||||||
|
end)
|
||||||
|
:on_click(function(_, player)
|
||||||
|
Spectate.stop_follow(player)
|
||||||
|
end)
|
||||||
|
:on_closed(function(_, player)
|
||||||
|
-- set_controller can not be called during on_gui_closed, so the next update stops following
|
||||||
|
local data = following[player.index]
|
||||||
|
if data then data.stop = true end
|
||||||
|
end) --[[@as any]]
|
||||||
|
|
||||||
|
--- Check if a player is in spectator mode
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @return boolean
|
||||||
|
function Spectate.is_spectating(player)
|
||||||
|
return player.controller_type == defines.controllers.spectator
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Put a player into spectator mode while keeping their character
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @return boolean # False when the player was already spectating or has no character
|
||||||
|
function Spectate.start_spectate(player)
|
||||||
|
if spectating[player.index] or not player.character then return false end
|
||||||
|
local character = player.character
|
||||||
|
local opened = player.opened
|
||||||
|
|
||||||
|
player.set_controller{ type = defines.controllers.spectator }
|
||||||
|
player.associate_character(character)
|
||||||
|
spectating[player.index] = character
|
||||||
|
|
||||||
|
if opened then player.opened = opened end -- Changing controller closes the opened gui
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Return a player to their character, or respawn them if it was killed
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
function Spectate.stop_spectate(player)
|
||||||
|
local character = spectating[player.index]
|
||||||
|
spectating[player.index] = nil
|
||||||
|
|
||||||
|
if character and character.valid then
|
||||||
|
local opened = player.opened
|
||||||
|
player.teleport(character.position, character.surface)
|
||||||
|
player.set_controller{ type = defines.controllers.character, character = character }
|
||||||
|
if opened then player.opened = opened end -- Changing controller closes the opened gui
|
||||||
|
else
|
||||||
|
player.ticks_to_respawn = 300
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a player is following something
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @return boolean
|
||||||
|
function Spectate.is_following(player)
|
||||||
|
return following[player.index] ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Put a player into spectator mode and keep their camera on a target as it moves
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @param target LuaPlayer | LuaEntity
|
||||||
|
function Spectate.start_follow(player, target)
|
||||||
|
local started_spectate = Spectate.start_spectate(player)
|
||||||
|
|
||||||
|
follow_label(player.gui.screen, target)
|
||||||
|
player.teleport(target.position, target.surface)
|
||||||
|
following[player.index] = {
|
||||||
|
player = player,
|
||||||
|
target = target,
|
||||||
|
position = player.position,
|
||||||
|
started_spectate = started_spectate,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Give a player their camera back, returning them to their character if start_follow took it
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
function Spectate.stop_follow(player)
|
||||||
|
local data = following[player.index]
|
||||||
|
if data and data.started_spectate and Spectate.is_spectating(player) then
|
||||||
|
Spectate.stop_spectate(player)
|
||||||
|
end
|
||||||
|
|
||||||
|
Gui.destroy_if_valid(player.gui.screen.follow_label)
|
||||||
|
following[player.index] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Move a following player onto their target, or stop following when they have moved away or regained a character
|
||||||
|
--- @param data ExpScenario_Spectate.Following
|
||||||
|
local function update_following(data)
|
||||||
|
local player, target = data.player, data.target
|
||||||
|
local position = player.position
|
||||||
|
if
|
||||||
|
data.stop
|
||||||
|
or player.character
|
||||||
|
or not target.valid
|
||||||
|
or position.x ~= data.position.x
|
||||||
|
or position.y ~= data.position.y
|
||||||
|
then
|
||||||
|
Spectate.stop_follow(player)
|
||||||
|
else
|
||||||
|
player.teleport(target.position, target.surface)
|
||||||
|
data.position = player.position
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function on_tick()
|
||||||
|
for _, data in pairs(following) do
|
||||||
|
update_following(data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Stop following when a player leaves, and stop anyone who was following them
|
||||||
|
--- @param event EventData.on_pre_player_left_game
|
||||||
|
local function on_pre_player_left_game(event)
|
||||||
|
local player = game.players[event.player_index]
|
||||||
|
Spectate.stop_follow(player)
|
||||||
|
for _, data in pairs(following) do
|
||||||
|
if data.target == player then
|
||||||
|
Spectate.stop_follow(data.player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local e = defines.events
|
||||||
|
|
||||||
|
Spectate.events[e.on_tick] = on_tick
|
||||||
|
Spectate.events[e.on_pre_player_left_game] = on_pre_player_left_game
|
||||||
|
|
||||||
|
return Spectate
|
||||||
@@ -206,6 +206,78 @@ function Elements.camera.refresh_online()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Slot in the header showing what the player a camera follows holds in their cursor
|
||||||
|
--- @class ExpGui_Surveillance.elements.cursor_slot: ExpElement
|
||||||
|
--- @field data table<LuaGuiElement, LuaGuiElement> The camera the slot belongs to
|
||||||
|
--- @overload fun(parent: LuaGuiElement, camera: LuaGuiElement): LuaGuiElement
|
||||||
|
Elements.cursor_slot = Gui.define("surveillance/cursor_slot")
|
||||||
|
:track_all_elements()
|
||||||
|
:draw{
|
||||||
|
type = "sprite-button",
|
||||||
|
style = "slot_button",
|
||||||
|
tooltip = { "exp-gui_surveillance.tooltip-cursor-empty" },
|
||||||
|
}
|
||||||
|
:style{
|
||||||
|
height = 26,
|
||||||
|
width = 26,
|
||||||
|
margin = { -1, -1, -1, -2 },
|
||||||
|
}
|
||||||
|
:element_data(
|
||||||
|
Gui.from_argument(1)
|
||||||
|
) --[[@as any]]
|
||||||
|
|
||||||
|
--- @class ExpGui_Surveillance.elements.cursor_slot.display_data
|
||||||
|
--- @field sprite SpritePath? Nil when the cursor is empty
|
||||||
|
--- @field number number? Nil for a ghost, which has no count
|
||||||
|
--- @field tooltip LocalisedString
|
||||||
|
|
||||||
|
--- Calculate what a slot shows for the cursor of a player
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @return ExpGui_Surveillance.elements.cursor_slot.display_data
|
||||||
|
function Elements.cursor_slot.calculate_display_data(player)
|
||||||
|
local cursor_stack = player.cursor_stack
|
||||||
|
if cursor_stack and cursor_stack.valid_for_read then
|
||||||
|
return {
|
||||||
|
sprite = "item/" .. cursor_stack.name,
|
||||||
|
number = cursor_stack.count,
|
||||||
|
tooltip = { "exp-gui_surveillance.tooltip-cursor", cursor_stack.prototype.localised_name, cursor_stack.count },
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local cursor_ghost = player.cursor_ghost --[[@as ItemIDAndQualityIDPair?]]
|
||||||
|
if cursor_ghost then
|
||||||
|
local prototype = cursor_ghost.name --[[@as LuaItemPrototype]]
|
||||||
|
return {
|
||||||
|
sprite = "item/" .. prototype.name,
|
||||||
|
tooltip = { "exp-gui_surveillance.tooltip-cursor-ghost", prototype.localised_name },
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return { tooltip = { "exp-gui_surveillance.tooltip-cursor-empty" } }
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh a slot, a ghost is shown greyed out and the slot is hidden when the camera is not following a player
|
||||||
|
--- @param cursor_slot LuaGuiElement
|
||||||
|
--- @param target_player LuaPlayer?
|
||||||
|
function Elements.cursor_slot.refresh(cursor_slot, target_player)
|
||||||
|
cursor_slot.visible = target_player ~= nil
|
||||||
|
if not target_player then return end
|
||||||
|
|
||||||
|
local display_data = Elements.cursor_slot.calculate_display_data(target_player)
|
||||||
|
cursor_slot.sprite = display_data.sprite or ""
|
||||||
|
cursor_slot.number = display_data.number
|
||||||
|
cursor_slot.tooltip = display_data.tooltip
|
||||||
|
cursor_slot.enabled = display_data.sprite == nil or display_data.number ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Refresh the slots of all online cameras
|
||||||
|
function Elements.cursor_slot.refresh_online()
|
||||||
|
for _, cursor_slot in Elements.cursor_slot:online_elements() do
|
||||||
|
local camera = Elements.cursor_slot.data[cursor_slot]
|
||||||
|
Elements.cursor_slot.refresh(cursor_slot, Elements.camera.data[camera])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Container added to the screen
|
--- Container added to the screen
|
||||||
Elements.container = Gui.define("surveillance/container")
|
Elements.container = Gui.define("surveillance/container")
|
||||||
:draw(function(def, parent)
|
:draw(function(def, parent)
|
||||||
@@ -214,6 +286,7 @@ Elements.container = Gui.define("surveillance/container")
|
|||||||
|
|
||||||
local target_player = Gui.get_player(parent)
|
local target_player = Gui.get_player(parent)
|
||||||
local camera = Elements.camera(screen_frame, target_player)
|
local camera = Elements.camera(screen_frame, target_player)
|
||||||
|
Elements.cursor_slot(button_flow, camera)
|
||||||
|
|
||||||
local type_dropdown_data = {
|
local type_dropdown_data = {
|
||||||
camera = camera,
|
camera = camera,
|
||||||
@@ -248,6 +321,7 @@ return {
|
|||||||
[e.on_tick] = Elements.camera.refresh_online,
|
[e.on_tick] = Elements.camera.refresh_online,
|
||||||
},
|
},
|
||||||
on_nth_tick = {
|
on_nth_tick = {
|
||||||
|
[10] = Elements.cursor_slot.refresh_online,
|
||||||
[600] = Elements.type_dropdown.refresh_online,
|
[600] = Elements.type_dropdown.refresh_online,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,25 +249,6 @@ description=Print all vlayer information.
|
|||||||
title=VLayer Information:
|
title=VLayer Information:
|
||||||
result=__1__: __2__
|
result=__1__: __2__
|
||||||
|
|
||||||
[exp-commands_warnings]
|
|
||||||
description-create=Gives a warning to a player; may lead to automatic script action.
|
|
||||||
description-get=Gets the number of warnings a player has. If no player then lists all players and the number of warnings they have.
|
|
||||||
description-clear=Clears all warnings (and script warnings) from a player.
|
|
||||||
description-clear-script=Clears all script warnings from a player.
|
|
||||||
description-clear-last=Clears the last warning from a player.
|
|
||||||
arg-player-create=Player to give the warning to.
|
|
||||||
arg-player-get=Player to get the warning of, if not given all players are returned.
|
|
||||||
arg-player-clear=Player to clear the warnings of.
|
|
||||||
arg-reason=Reason the user is receiving a warning.
|
|
||||||
create=__1__ received a warning from __2__ for __3__.
|
|
||||||
player-title=__1__ has __2__ warnings and __3__/__4__ script warnings.
|
|
||||||
list-element-player=__1__: __2__
|
|
||||||
warnings-title=The following players have warnings aginst them (and script warnings):
|
|
||||||
list-element=__1__: __2__ (__3__/__4__)
|
|
||||||
cleared=__1__ had all their warnings cleared by __2__.
|
|
||||||
cleared-script=__1__ had all their script warnings cleared by __2__.
|
|
||||||
cleared-last=__1__ had their last warning cleared by __2__.
|
|
||||||
|
|
||||||
[exp-commands_waterfill]
|
[exp-commands_waterfill]
|
||||||
description=Replace tiles with shallow water.
|
description=Replace tiles with shallow water.
|
||||||
requires-explosives=__ITEM__cliff-explosives__ are required to create water.
|
requires-explosives=__ITEM__cliff-explosives__ are required to create water.
|
||||||
@@ -326,7 +307,6 @@ reason-entry=Enter Reason
|
|||||||
goto-player=Goto player
|
goto-player=Goto player
|
||||||
bring-player=Bring player
|
bring-player=Bring player
|
||||||
report-player=Report player
|
report-player=Report player
|
||||||
warn-player=Warn player
|
|
||||||
jail-player=Jail player
|
jail-player=Jail player
|
||||||
kick-player=Kick player
|
kick-player=Kick player
|
||||||
ban-player=Ban player
|
ban-player=Ban player
|
||||||
@@ -489,6 +469,9 @@ caption-set-location=Set
|
|||||||
type-player=Player
|
type-player=Player
|
||||||
type-static=Static
|
type-static=Static
|
||||||
type-loop=Loop
|
type-loop=Loop
|
||||||
|
tooltip-cursor=__1__ x__2__
|
||||||
|
tooltip-cursor-ghost=__1__ (ghost)
|
||||||
|
tooltip-cursor-empty=Empty cursor
|
||||||
|
|
||||||
[exp-gui_task-list]
|
[exp-gui_task-list]
|
||||||
caption-main=Task List [img=info]
|
caption-main=Task List [img=info]
|
||||||
@@ -577,3 +560,6 @@ chat-jailed=__1__ was jailed because they removed too many protected entities. P
|
|||||||
|
|
||||||
[exp_report-jail]
|
[exp_report-jail]
|
||||||
chat-jailed=__1__ was jailed because they were reported too many times. Please wait for a moderator.
|
chat-jailed=__1__ was jailed because they were reported too many times. Please wait for a moderator.
|
||||||
|
|
||||||
|
[exp_spectate]
|
||||||
|
follow-label=Following __1__.\nClick here or press escape to stop following.
|
||||||
|
|||||||
@@ -246,25 +246,6 @@ description=vlayer 資訊
|
|||||||
title=vlayer 資訊:
|
title=vlayer 資訊:
|
||||||
result=__1__: __2__
|
result=__1__: __2__
|
||||||
|
|
||||||
[exp-commands_warnings]
|
|
||||||
description-create=給用戶一個警告; 可能會導致系統的自動行動。
|
|
||||||
description-get=取得用戶收到的警告次數。如果沒有用戶,則列出所有用戶以及他們受到警告的次數。
|
|
||||||
description-clear=清除用戶的所有警告(和系統警告)。
|
|
||||||
description-clear-script=清除用戶的系統警告。
|
|
||||||
description-clear-last=清除用戶的最後警告。
|
|
||||||
arg-player-create=要警告的用戶。
|
|
||||||
arg-player-get=要取得的用戶, 若沒有則返回所有用戶。
|
|
||||||
arg-player-clear=要清除的用戶。
|
|
||||||
arg-reason=原因。
|
|
||||||
create=__1__ 被 __2__ 因 __3__ 作出警告。
|
|
||||||
player-title=__1__ 有 __2__ 個警告和 __3__/__4__ 的系統警告。
|
|
||||||
list-element-player=__1__: __2__
|
|
||||||
warnings-title=該用戶警告如下:
|
|
||||||
list-element=__1__: __2__ (__3__/__4__)
|
|
||||||
cleared=__1__ 的警告己被 __2__ 清除。
|
|
||||||
cleared-script=__1__ 的系統警告己被 __2__ 清除。
|
|
||||||
cleared-last=__1__ 的最後警告己被 __2__ 清除。
|
|
||||||
|
|
||||||
[exp-commands_waterfill]
|
[exp-commands_waterfill]
|
||||||
description=把地換為淺水。
|
description=把地換為淺水。
|
||||||
requires-explosives=沒有足夠的 __ITEM__cliff-explosives__ 。
|
requires-explosives=沒有足夠的 __ITEM__cliff-explosives__ 。
|
||||||
@@ -474,6 +455,9 @@ caption-set-location=設
|
|||||||
type-player=用戶
|
type-player=用戶
|
||||||
type-static=靜態
|
type-static=靜態
|
||||||
type-loop=循環
|
type-loop=循環
|
||||||
|
tooltip-cursor=__1__ x__2__
|
||||||
|
tooltip-cursor-ghost=__1__ (幻影)
|
||||||
|
tooltip-cursor-empty=游標為空
|
||||||
|
|
||||||
[exp-gui_task-list]
|
[exp-gui_task-list]
|
||||||
caption-main=工作流程 [img=info]
|
caption-main=工作流程 [img=info]
|
||||||
|
|||||||
@@ -246,25 +246,6 @@ description=vlayer 資訊
|
|||||||
title=vlayer 資訊:
|
title=vlayer 資訊:
|
||||||
result=__1__: __2__
|
result=__1__: __2__
|
||||||
|
|
||||||
[exp-commands_warnings]
|
|
||||||
description-create=給用戶一個警告; 可能會導致系統的自動行動。
|
|
||||||
description-get=取得用戶收到的警告次數。如果沒有用戶,則列出所有用戶以及他們受到警告的次數。
|
|
||||||
description-clear=清除用戶的所有警告(和系統警告)。
|
|
||||||
description-clear-script=清除用戶的系統警告。
|
|
||||||
description-clear-last=清除用戶的最後警告。
|
|
||||||
arg-player-create=要警告的用戶。
|
|
||||||
arg-player-get=要取得的用戶, 若沒有則返回所有用戶。
|
|
||||||
arg-player-clear=要清除的用戶。
|
|
||||||
arg-reason=原因。
|
|
||||||
create=__1__ 被 __2__ 因 __3__ 作出警告。
|
|
||||||
player-title=__1__ 有 __2__ 個警告和 __3__/__4__ 的系統警告。
|
|
||||||
list-element-player=__1__: __2__
|
|
||||||
warnings-title=該用戶警告如下:
|
|
||||||
list-element=__1__: __2__ (__3__/__4__)
|
|
||||||
cleared=__1__ 的警告己被 __2__ 清除。
|
|
||||||
cleared-script=__1__ 的系統警告己被 __2__ 清除。
|
|
||||||
cleared-last=__1__ 的最後警告己被 __2__ 清除。
|
|
||||||
|
|
||||||
[exp-commands_waterfill]
|
[exp-commands_waterfill]
|
||||||
description=把地換為淺水。
|
description=把地換為淺水。
|
||||||
requires-explosives=沒有足夠的 __ITEM__cliff-explosives__ 。
|
requires-explosives=沒有足夠的 __ITEM__cliff-explosives__ 。
|
||||||
@@ -474,6 +455,9 @@ caption-set-location=設
|
|||||||
type-player=用戶
|
type-player=用戶
|
||||||
type-static=靜態
|
type-static=靜態
|
||||||
type-loop=循環
|
type-loop=循環
|
||||||
|
tooltip-cursor=__1__ x__2__
|
||||||
|
tooltip-cursor-ghost=__1__ (幻影)
|
||||||
|
tooltip-cursor-empty=游標為空
|
||||||
|
|
||||||
[exp-gui_task-list]
|
[exp-gui_task-list]
|
||||||
caption-main=工作流程 [img=info]
|
caption-main=工作流程 [img=info]
|
||||||
|
|||||||
@@ -26,25 +26,20 @@ const definitions: Definition[] = [
|
|||||||
["exp_scenario.command.clear_blueprints_surface", "/clear-blueprints-surface", "Clear all blueprints on the current surface."],
|
["exp_scenario.command.clear_blueprints_surface", "/clear-blueprints-surface", "Clear all blueprints on the current surface."],
|
||||||
["exp_scenario.command.clear_ground_items", "/clear-ground-items", "Clear all items on the ground."],
|
["exp_scenario.command.clear_ground_items", "/clear-ground-items", "Clear all items on the ground."],
|
||||||
["exp_scenario.command.clear_inventory", "/clear-inventory", "Clear a player's inventory, moving all items to spawn."],
|
["exp_scenario.command.clear_inventory", "/clear-inventory", "Clear a player's inventory, moving all items to spawn."],
|
||||||
["exp_scenario.command.clear_last_warnings", "/clear-last-warnings", "Clears the last warning from a player."],
|
|
||||||
["exp_scenario.command.clear_pollution", "/clear-pollution", "Clear pollution from your current surface, or another surface."],
|
["exp_scenario.command.clear_pollution", "/clear-pollution", "Clear pollution from your current surface, or another surface."],
|
||||||
["exp_scenario.command.clear_reports", "/clear-reports", "Clears all reports from a player or just the report from one player."],
|
["exp_scenario.command.clear_reports", "/clear-reports", "Clears all reports from a player or just the report from one player."],
|
||||||
["exp_scenario.command.clear_script_warnings", "/clear-script-warnings", "Clears all script warnings from a player."],
|
|
||||||
["exp_scenario.command.clear_warnings", "/clear-warnings", "Clears all warnings (and script warnings) from a player."],
|
|
||||||
["exp_scenario.command.collectdata", "/collectdata", "Collect data for RCON usage."],
|
["exp_scenario.command.collectdata", "/collectdata", "Collect data for RCON usage."],
|
||||||
["exp_scenario.command.commands", "/commands", "List and search all commands for a keyword.", true],
|
["exp_scenario.command.commands", "/commands", "List and search all commands for a keyword.", true],
|
||||||
["exp_scenario.command.connect", "/connect", "Connect to another server.", true],
|
["exp_scenario.command.connect", "/connect", "Connect to another server.", true],
|
||||||
["exp_scenario.command.connect_all", "/connect-all", "Connect all players to another server."],
|
["exp_scenario.command.connect_all", "/connect-all", "Connect all players to another server."],
|
||||||
["exp_scenario.command.connect_player", "/connect-player", "Connect a player to a different server."],
|
["exp_scenario.command.connect_player", "/connect-player", "Connect a player to a different server."],
|
||||||
["exp_scenario.command.create_report", "/create-report", "Reports a player and notifies moderators.", true],
|
["exp_scenario.command.create_report", "/create-report", "Reports a player and notifies moderators.", true],
|
||||||
["exp_scenario.command.create_warning", "/create-warning", "Gives a warning to a player; may lead to automatic script action."],
|
|
||||||
["exp_scenario.command.data_preference", "/data-preference", "Allows you to set/get your data saving preference.", true],
|
["exp_scenario.command.data_preference", "/data-preference", "Allows you to set/get your data saving preference.", true],
|
||||||
["exp_scenario.command.debug", "/debug", "Opens the debug gui."],
|
["exp_scenario.command.debug", "/debug", "Opens the debug gui."],
|
||||||
["exp_scenario.command.follow", "/follow", "Start following a player in spectator."],
|
["exp_scenario.command.follow", "/follow", "Start following a player in spectator."],
|
||||||
["exp_scenario.command.get_home", "/get-home", "Returns your current home location."],
|
["exp_scenario.command.get_home", "/get-home", "Returns your current home location."],
|
||||||
["exp_scenario.command.get_reports", "/get-reports", "List the reports against a player, or against every player."],
|
["exp_scenario.command.get_reports", "/get-reports", "List the reports against a player, or against every player."],
|
||||||
["exp_scenario.command.get_roles", "/get-roles", "Get all roles that a player has, if no player provided it lists all roles.", true],
|
["exp_scenario.command.get_roles", "/get-roles", "Get all roles that a player has, if no player provided it lists all roles.", true],
|
||||||
["exp_scenario.command.get_warnings", "/get-warnings", "List the warnings against a player, or against every player."],
|
|
||||||
["exp_scenario.command.goto", "/goto", "Teleports you to a player."],
|
["exp_scenario.command.goto", "/goto", "Teleports you to a player."],
|
||||||
["exp_scenario.command.home", "/home", "Teleports you to your home location."],
|
["exp_scenario.command.home", "/home", "Teleports you to your home location."],
|
||||||
["exp_scenario.command.jail", "/jail", "Puts a player into jail, which suppresses all of their other roles."],
|
["exp_scenario.command.jail", "/jail", "Puts a player into jail, which suppresses all of their other roles."],
|
||||||
|
|||||||
Reference in New Issue
Block a user