1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-04 09:42:30 +02:00

Add admin panel (#1432)

* Add admin panel
This commit is contained in:
RedRafe 2024-09-02 22:32:20 +02:00 committed by GitHub
parent 9da9fd021a
commit 4b040d1048
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 1266 additions and 50 deletions

View File

@ -1052,6 +1052,7 @@ stds.factorio_defines = {
'on_gui_elem_changed',
'on_gui_opened',
'on_gui_selection_state_changed',
'on_gui_switch_state_changed',
'on_gui_text_changed',
'on_gui_value_changed',
'on_land_mine_armed',

View File

@ -470,6 +470,9 @@ global.config = {
clear_corpses = true,
battery_charge = true,
}
},
admin_panel = {
enabled = true,
}
}

View File

@ -135,6 +135,11 @@ if config.map_info.enabled then
require 'features.gui.info'
require 'features.gui.description_generator'
end
if config.admin_panel.enabled then
require 'features.gui.admin_panel.player_manager'
require 'features.gui.admin_panel.map_manager'
require 'features.gui.admin_panel.lua_console'
end
if config.player_list.enabled then
require 'features.gui.player_list'
end

View File

@ -24,8 +24,8 @@ Global.register(
)
--- Informs the actor that there is no target. Acts as a central place where this message can be changed.
local function print_no_target(target_name)
Game.player_print({'common.fail_no_target', target_name}, Color.fail)
local function print_no_target(target_name, player)
Game.player_print({'common.fail_no_target', target_name}, Color.fail, player)
end
local function know_player_or_rerun(player_name, actor, command_name)
@ -38,7 +38,7 @@ local function know_player_or_rerun(player_name, actor, command_name)
return true;
end
Game.player_print({'common.rerun_no_target', player_name}, Color.fail)
Game.player_print({'common.rerun_no_target', player_name}, Color.fail, actor)
return false
end
@ -57,21 +57,21 @@ end
--- Toggles cheat mode for a player
local function toggle_cheat_mode(_, player)
player.cheat_mode = not player.cheat_mode
Game.player_print({'admin_commands.toggle_cheat_mode', tostring(player.cheat_mode)})
Game.player_print({'admin_commands.toggle_cheat_mode', tostring(player.cheat_mode)}, nil, player)
end
--- Promote someone to regular
local function add_regular(args)
local function add_regular(args, player)
local target_name = args.player
local maybe_target_player = game.get_player(target_name)
local actor = Utils.get_actor()
local actor = args.actor or Utils.get_actor()
if not maybe_target_player and not know_player_or_rerun(target_name, actor, 'regular') then
return
end
if Rank.less_than(target_name, Ranks.guest) then
Game.player_print({'admin_commands.regular_add_fail_probation'}, Color.fail)
Game.player_print({'admin_commands.regular_add_fail_probation'}, Color.fail, player)
return
end
@ -82,15 +82,15 @@ local function add_regular(args)
maybe_target_player.print({'admin_commands.regular_add_notify_target'}, Color.warning)
end
else
Game.player_print({'admin_commands.regular_add_fail', target_name, Rank.get_player_rank_name(target_name)}, Color.fail)
Game.player_print({'admin_commands.regular_add_fail', target_name, Rank.get_player_rank_name(target_name)}, Color.fail, player)
end
end
--- Demote someone from regular
local function remove_regular(args)
local function remove_regular(args, player)
local target_name = args.player
local maybe_target_player = game.get_player(target_name)
local actor = Utils.get_actor()
local actor = args.actor or Utils.get_actor()
if not maybe_target_player and not know_player_or_rerun(target_name, actor, 'regular-remove') then
return
@ -104,22 +104,22 @@ local function remove_regular(args)
end
else
local rank_name = Rank.get_player_rank_name(target_name)
Game.player_print({'admin_commands.regular_remove_fail', target_name, rank_name}, Color.fail)
Game.player_print({'admin_commands.regular_remove_fail', target_name, rank_name}, Color.fail, player)
end
end
--- Put someone on probation
local function probation_add(args)
local function probation_add(args, player)
local target_name = args.player
local maybe_target_player = game.get_player(target_name)
local actor = Utils.get_actor()
local actor = args.actor or Utils.get_actor()
if not maybe_target_player and not know_player_or_rerun(target_name, actor, 'probation') then
return
end
if Rank.equal(target_name, Ranks.admin) then
Game.player_print({'admin_commands.probation_add_fail_admin'}, Color.fail)
Game.player_print({'admin_commands.probation_add_fail_admin'}, Color.fail, player)
if maybe_target_player then
maybe_target_player.print({'admin_commands.probation_warn_admin', actor}, Color.warning)
end
@ -133,15 +133,15 @@ local function probation_add(args)
maybe_target_player.print({'admin_commands.probation_add_notify_target'}, Color.warning)
end
else
Game.player_print({'admin_commands.probation_add_fail', target_name}, Color.fail)
Game.player_print({'admin_commands.probation_add_fail', target_name}, Color.fail, player)
end
end
--- Remove someone from probation
local function probation_remove(args)
local function probation_remove(args, player)
local target_name = args.player
local maybe_target_player = game.get_player(target_name)
local actor = Utils.get_actor()
local actor = args.actor or Utils.get_actor()
if not maybe_target_player and not know_player_or_rerun(target_name, actor, 'probation-remove') then
return
@ -154,7 +154,7 @@ local function probation_remove(args)
maybe_target_player.print({'admin_commands.probation_remove_notify_target'}, Color.warning)
end
else
Game.player_print({'admin_commands.probation_remove_fail', target_name}, Color.fail)
Game.player_print({'admin_commands.probation_remove_fail', target_name}, Color.fail, player)
end
end
@ -169,7 +169,7 @@ local function jail_player(args, player)
local target = Utils.validate_player(target_ident)
if not target then
print_no_target(target_ident)
print_no_target(target_ident, player)
return
end
@ -182,7 +182,7 @@ local function unjail_player(args, player)
local target = Utils.validate_player(target_ident)
if not target then
print_no_target(target_ident)
print_no_target(target_ident, player)
return
end
Report.unjail(target, player)
@ -199,6 +199,7 @@ local function pool(_, player)
end
player.surface.set_tiles(t)
player.surface.create_entity {name = 'fish', position = {p.x + 0.5, p.y + 5}}
Game.player_print({'admin_commands.create_pool'}, Color.success, player)
end
--- Takes a target and teleports them to player
@ -207,13 +208,13 @@ local function invoke(args, player)
local target = Utils.validate_player(target_ident)
if not target then
print_no_target(target_ident)
print_no_target(target_ident, player)
return
end
local pos = player.surface.find_non_colliding_position('character', player.position, 50, 1)
if not pos then
Game.player_print({'admin_commands.invoke_fail_no_location'})
Game.player_print({'admin_commands.invoke_fail_no_location'}, player)
return
end
target.teleport({pos.x, pos.y}, player.surface)
@ -226,7 +227,7 @@ local function teleport_player(args, player)
local target = Utils.validate_player(target_ident)
if not target then
print_no_target(target_ident)
print_no_target(target_ident, player)
return
end
@ -234,27 +235,27 @@ local function teleport_player(args, player)
local surface = target.surface
local pos = surface.find_non_colliding_position('character', target.position, 50, 1)
if not pos then
Game.player_print({'admin_commands.tp_fail_no_location'})
Game.player_print({'admin_commands.tp_fail_no_location'}, Color.fail, player)
return
end
player.teleport(pos, surface)
game.print({'admin_commands.tp_player_announce', target_name})
Game.player_print({'admin_commands.tp_player_success', target_name})
Game.player_print({'admin_commands.tp_player_success', target_name}, Color.success, player)
end
--- Takes a selected entity and teleports player to it
local function teleport_location(_, player)
if not player.selected then
Game.player_print({'admin_commands.tp_ent_fail_no_ent'})
Game.player_print({'admin_commands.tp_ent_fail_no_ent'}, Color.fail, player)
return
end
local pos = player.surface.find_non_colliding_position('character', player.selected.position, 50, 1)
if not pos then
Game.player_print({'admin_commands.tp_fail_no_location'})
Game.player_print({'admin_commands.tp_fail_no_location'}, Color.fail, player)
return
end
player.teleport(pos)
Game.player_print({'admin_commands.tp_end_success'})
Game.player_print({'admin_commands.tp_end_success'}, Color.success, player)
end
--- If a player is in the tp_players list, remove ghosts they place and teleport them to that position
@ -280,10 +281,10 @@ local function toggle_tp_mode(_, player)
if toggled then
tp_players[index] = nil
Game.player_print({'admin_commands.tp_mode_off'})
Game.player_print({'admin_commands.tp_mode_off'}, nil, player)
else
tp_players[index] = true
Game.player_print({'admin_commands.tp_mode_on'})
Game.player_print({'admin_commands.tp_mode_on'}, nil, player)
end
end
@ -303,19 +304,22 @@ end
local function revive_ghosts(args, player)
local radius = args.radius
local pos = player.position
local count = 0
for _, e in pairs(player.surface.find_entities_filtered {area = {{pos.x - radius, pos.y - radius}, {pos.x + radius, pos.y + radius}}, type = 'entity-ghost'}) do
e.revive()
count = count + 1
end
Game.player_print({'admin_commands.revive_ghosts', count}, Color.success, player)
end
--- Destroys the player's selected entity
local function destroy_selected(_, player)
local ent = player.selected
if ent then
Game.player_print({'admin_commands.destroy_success', ent.localised_name})
Game.player_print({'admin_commands.destroy_success', ent.localised_name}, player)
ent.destroy()
else
Game.player_print({'admin_commands.destroy_fail'})
Game.player_print({'admin_commands.destroy_fail'}, player)
end
end
@ -472,3 +476,19 @@ Command.add(
},
destroy_selected
)
return {
create_pool = pool,
destroy_selected = destroy_selected,
invoke_player = invoke,
jail_player = jail_player,
probation_add = probation_add,
probation_remove = probation_remove,
regular_add = add_regular,
regular_remove = remove_regular,
revive_ghosts = revive_ghosts,
show_reports = show_reports,
teleport_command = teleport_command,
toggle_cheat_mode = toggle_cheat_mode,
unjail_player = unjail_player,
}

View File

@ -0,0 +1,214 @@
local Event = require 'utils.event'
local Gui = require 'utils.gui'
local Global = require 'utils.global'
local Config = require 'config'.admin_panel
local main_button_name = Gui.uid_name()
local main_frame_name = Gui.uid_name()
local close_button_name = Gui.uid_name()
local pages = {
--[[
{
type = 'sprite-button',
sprite = 'item/programmable-speaker',
tooltip = 'First page',
},
{
type = 'sprite-button',
sprite = 'utility/spawn_flag',
tooltip = 'Second page',
},
{
type = 'sprite-button',
sprite = 'utility/scripting_editor_icon',
tooltip = 'Third page',
},
{
type = 'sprite-button',
sprite = 'utility/surface_editor_icon',
tooltip = 'Fourth page',
},
]]
}
Global.register(pages, function(tbl) pages = tbl end)
local Public = {}
function Public.get_pages()
return pages
end
function Public.get_canvas(player)
return Gui.get_data(Public.get_main_frame(player)).right
end
function Public.get_main_frame(player)
local frame = player.gui.screen[main_frame_name]
if frame and frame.valid then
return frame
end
frame = player.gui.screen.add {
type = 'frame',
name = main_frame_name,
direction = 'vertical',
style = 'frame',
}
frame.auto_center = true
player.opened = frame
Gui.set_style(frame, {
horizontally_stretchable = true,
vertically_stretchable = true,
natural_width = 400,
natural_height = 400,
top_padding = 8,
bottom_padding = 8,
})
local data = {}
do -- title
local flow = frame.add { type = 'flow', direction = 'horizontal' }
Gui.set_style(flow, { horizontal_spacing = 8, vertical_align = 'center', bottom_padding = 4 })
local label = flow.add { type = 'label', caption = 'Admin panel', style = 'heading_1_label' }
label.drag_target = frame
local dragger = flow.add { type = 'empty-widget', style = 'draggable_space_header' }
dragger.drag_target = frame
Gui.set_style(dragger, { height = 24, horizontally_stretchable = true })
flow.add {
type = 'sprite-button',
name = close_button_name,
sprite = 'utility/close_white',
clicked_sprite = 'utility/close_black',
style = 'close_button',
tooltip = {'gui.close-instruction'}
}
end
local main_flow = frame.add { type = 'flow', name = 'flow', direction = 'horizontal' }
Gui.set_style(main_flow, { horizontal_spacing = 12 })
do -- left
local left = main_flow
.add { type = 'flow', name = 'left', direction = 'vertical' }
.add { type = 'frame', direction = 'vertical', style = 'inside_deep_frame' }
.add { type = 'flow', direction = 'vertical' }
Gui.set_style(left, {
vertically_stretchable = true,
horizontal_align = 'center',
padding = 10,
vertical_spacing = 10,
})
for _, page in pairs(pages) do
left.add(page)
end
data.left = left
end
do -- right
local right = main_flow
.add { type = 'frame', name = 'right', style = 'inside_shallow_frame_with_padding' }
.add { type = 'flow', name = 'flow', direction = 'vertical' }
Gui.set_style(right, {
minimal_width = 300,
minimal_height = 300,
vertically_stretchable = true,
horizontally_stretchable = true,
})
data.right = right
end
Gui.set_data(frame, data)
end
function Public.update_top_button(player)
if not Config.enabled then
return
end
local button = Gui.add_top_element(player, {
type = 'sprite-button',
name = main_button_name,
sprite = 'item/power-armor-mk2',
tooltip = {'admin_panel.info_tooltip'},
})
button.visible = player.admin
end
function Public.toggle_main_button(player)
local main_frame = player.gui.screen[main_frame_name]
if main_frame then
Gui.destroy(main_frame)
else
Public.get_main_frame(player)
end
end
function Public.close_all_pages(player)
local frame = player.gui.screen[main_frame_name]
if not (frame and frame.valid) then
return
end
for _, button in pairs(Gui.get_data(frame).left.children) do
button.toggled = false
end
end
Event.add(defines.events.on_player_created, function(event)
local player = game.get_player(event.player_index)
if not (player and player.valid) then
return
end
Public.update_top_button(player)
end)
Event.add(defines.events.on_player_joined_game, function(event)
local player = game.get_player(event.player_index)
if not (player and player.valid) then
return
end
Public.update_top_button(player)
local frame = player.gui.screen[main_frame_name]
if (frame and frame.valid and not player.admin) then
Gui.destroy(frame)
end
end)
Event.add(defines.events.on_gui_closed, function(event)
local element = event.element
if not (element and element.valid) then
return
end
local player = game.get_player(event.player_index)
if not (player and player.valid) then
return
end
if element.name == main_frame_name then
Public.toggle_main_button(player)
end
end)
Gui.allow_player_to_toggle_top_element_visibility(main_button_name)
Gui.on_click(main_button_name, function(event)
Public.toggle_main_button(event.player)
end)
Gui.on_click(close_button_name, function(event)
Public.toggle_main_button(event.player)
end)
Gui.on_player_show_top(main_button_name, function(event)
Public.update_top_button(event.player)
end)
return Public

View File

@ -0,0 +1,143 @@
local Color = require 'resources.color_presets'
local Game = require 'utils.game'
local Performance = require 'features.performance'
local Report = require 'features.report'
-- == ACTIONS =================================================================
local Actions = require 'features.admin_commands'
---@param filename? string
---@param player? LuaPlayer
function Actions.save_game(filename, player)
filename = filename or 'currently-running'
game.auto_save(filename)
Game.player_print('Saving map: _autosave-' .. filename ..'.zip', Color.success, player)
end
---@param player? LuaPlayer
function Actions.remove_all_ghost_entities(player)
local count = 0
for _, surface in pairs(game.surfaces) do
for _, ghost in pairs(surface.find_entities_filtered { type = { 'entity-ghost', 'tile-ghost' }}) do
ghost.destroy()
count = count + 1
end
end
Game.player_print(count .. ' ghost entities removed from all surfaces.', Color.success, player)
end
---@param player? LuaPlayer
function Actions.destroy_all_speakers(player)
local count = 0
for _, surface in pairs(game.surfaces) do
for _, speaker in pairs(surface.find_entities_filtered { type = 'programmable-speaker' }) do
if speaker.parameters.playback_globally == true then
speaker.die('player')
count = count + 1
end
end
end
Game.player_print(count .. ' speakers removed from all surfaces.', Color.success, player)
end
---@param player? LuaPlayer
function Actions.kill_all_enemy_units(player)
game.forces.enemy.kill_all_units()
Game.player_print('All enemy units have been killed.', Color.success, player)
end
---@param player? LuaPlayer
function Actions.kill_all_enemies(player)
local count = 0
for _, surface in pairs(game.surfaces) do
for _, enemy in pairs(surface.find_entities_filtered { force = 'enemy' }) do
enemy.die('player')
count = count + 1
end
end
game.forces.enemy.kill_all_units()
Game.player_print(count .. ' enemies have been killed.', Color.success, player)
end
---@param target_name string
---@param reason? string
---@param admin? LuaPlayer
function Actions.ban_player(target_name, reason, admin)
local player = game.get_player(target_name)
if not (player and player.valid) then
Game.player_print('Could not ban player: ' .. target_name, Color.fail, admin)
return
end
Report.ban_player(player, reason, admin)
end
---@param target_player string
---@param source_player LuaPlayer
function Actions.spank(target_name, source_player)
local target_player = game.get_player(target_name)
local character = target_player.character
if not (character and character.valid) then
return
end
if character.health > 5 then
character.damage(5, 'player')
end
target_player.surface.create_entity { name = 'water-splash', position = target_player.position }
game.print(source_player.name .. ' spanked ' .. target_player.name, Color.warning)
end
-- == SURFACE =================================================================
local Surface = {}
---@param scale number
function Surface.performance_scale_set(scale)
Performance.set_time_scale(scale)
local stat_mod = Performance.get_player_stat_modifier()
game.print({'performance.stat_preamble'})
game.print({'performance.generic_stat', {'performance.game_speed'}, string.format('%.2f', Performance.get_time_scale())})
local stat_string = string.format('%.2f', stat_mod)
game.print({'performance.output_formatter', {'performance.running_speed'}, stat_string, {'performance.manual_mining_speed'}, stat_string, {'performance.manual_crafting_speed'}, stat_string})
end
---@param player LuaPlayer
---@param radius number
function Surface.chart_map(player, radius)
local position = player.position
local area = {
left_top = { x = position.x - radius, y = position.y - radius },
right_bottom = { x = position.x + radius, y = position.y + radius }
}
player.force.chart(player.surface, area)
Game.player_print('Revealing the area around you...', Color.success, player)
end
---@param player LuaPlayer
function Surface.hide_all(player)
local surface = player.surface
local force = player.force
for chunk in surface.get_chunks() do
force.unchart_chunk({ x = chunk.x, y = chunk.y }, surface)
end
Game.player_print('Hidden all of ' ..surface.name .. ' surface', Color.success, player)
end
---@param player LuaPlayer
function Surface.reveal_all(player)
player.force.chart_all()
Game.player_print('Removing the fog from ' .. player.surface.name .. ' surface', Color.success, player)
end
---@param player LuaPlayer
function Surface.rechart_all(player)
player.force.rechart()
Game.player_print('Revealing all of ' .. player.surface.name .. ' surface', Color.success, player)
end
-- ============================================================================
return {
actions = Actions,
surface = Surface,
}

View File

@ -0,0 +1,117 @@
local Gui = require 'utils.gui'
local Global = require 'utils.global'
local AdminPanel = require 'features.gui.admin_panel.core'
local main_button_name = Gui.uid_name()
local clear_button_name = Gui.uid_name()
local dry_run_button_name = Gui.uid_name()
local confirm_button_name = Gui.uid_name()
local this = {
last_lua_input = {},
last_lua_output = {},
}
Global.register(this, function(tbl) this = tbl end)
local pages = AdminPanel.get_pages()
pages[#pages +1] = {
type = 'sprite-button',
sprite = 'utility/scripting_editor_icon',
tooltip = '[font=default-bold]Lua console[/font]',
name = main_button_name,
auto_toggle = true,
}
local function draw_gui(player)
local canvas = AdminPanel.get_canvas(player)
Gui.clear(canvas)
this.last_lua_input[player.index] = this.last_lua_input[player.index] or ''
this.last_lua_output[player.index] = this.last_lua_output[player.index] or ''
local info = canvas.add { type = 'frame', style = 'deep_frame_in_shallow_frame_for_tabs', direction = 'vertical' }
Gui.set_style(info, { padding = 12, horizontally_stretchable = true })
info.add { type = 'label', caption = '[font=default-bold][color=green]Input:[/color][/font]' }
info.add { type = 'label', caption = ' - no need to append `/c` at the beginning of the code' }
info.add { type = 'label', caption = ' - can accept pure strings instead of commands' }
info.add { type = 'label', caption = '[font=default-bold][color=red]Output:[/color][/font]' }
info.add { type = 'label', caption = ' - errors of the code will be displayed here, if any' }
local input = canvas
.add { type = 'frame', style = 'bordered_frame', direction = 'vertical', caption = 'Input' }
.add { type = 'text-box', name = 'input' }
input.word_wrap = true
input.text = this.last_lua_input[player.index]
Gui.set_style(input, { minimal_height = 240, minimal_width = 460, maximal_height = 800 })
local output = canvas
.add { type = 'frame', style = 'bordered_frame', direction = 'vertical', caption = 'Output' }
.add { type = 'text-box', name = 'output' }
output.word_wrap = true
output.text = this.last_lua_output[player.index]
Gui.set_style(output, { minimal_height = 60, minimal_width = 460, maximal_height = 120 })
local button_flow = canvas.add { type = 'flow', direction = 'horizontal' }
Gui.add_pusher(button_flow)
button_flow.add { type = 'button', name = clear_button_name, style = 'red_back_button', caption = 'Clear' }
local dry_run = button_flow.add { type = 'button', name = dry_run_button_name, style = 'forward_button', caption = 'Dry run' }
local confirm = button_flow.add { type = 'button', name = confirm_button_name, style = 'confirm_double_arrow_button', caption = 'Confirm', tooltip = 'Run input code' }
Gui.set_style(confirm, { left_margin = - 4 })
Gui.set_data(dry_run, { input = input, output = output })
Gui.set_data(confirm, { input = input, output = output })
end
local function process_command(event)
local player = event.player
local data = Gui.get_data(event.element)
local input, output = data.input, data.output
local cmd = input.text
this.last_lua_input[player.index] = cmd
rawset(game, 'player', player)
local f, err, _
f, err = loadstring(cmd)
if not f then
cmd = 'game.players[' .. player.index .. '].print(' .. cmd .. ')'
f, err = loadstring(cmd)
end
if event.element.name ~= dry_run_button_name then
_, err = pcall(f)
end
rawset(game, 'player', nil)
if err then
local text = ''
text = text .. cmd .. '\n'
text = text .. '----------------------------------------------------------------------\n'
text = text .. err:sub(1, err:find('\n'))
output.text = text
this.last_lua_output[player.index] = text
end
end
Gui.on_click(main_button_name, function(event)
local player = event.player
local element = event.element
if element.toggled then
AdminPanel.close_all_pages(player)
event.element.toggled = true
draw_gui(player)
else
Gui.clear(AdminPanel.get_canvas(player))
end
end)
Gui.on_click(dry_run_button_name, process_command)
Gui.on_click(confirm_button_name, process_command)
Gui.on_click(clear_button_name, function(event)
local player = event.player
this.last_lua_input[player.index] = ''
this.last_lua_output[player.index] = ''
draw_gui(player)
end)

View File

@ -0,0 +1,354 @@
local AdminPanel = require 'features.gui.admin_panel.core'
local Event = require 'utils.event'
local Gui = require 'utils.gui'
local math = require 'utils.math'
local Surface = require 'features.gui.admin_panel.functions'.surface
local main_button_name = Gui.uid_name()
local slider_tag_name = Gui.uid_name()
local on_performance_speed = Gui.uid_name()
local on_slow_down = Gui.uid_name()
local on_speed_up = Gui.uid_name()
local on_pollution_ageing = Gui.uid_name()
local on_pollution_diffusion = Gui.uid_name()
local on_pollution_attack_modifier = Gui.uid_name()
local on_evolution_value = Gui.uid_name()
local on_evolution_destroy_factor= Gui.uid_name()
local on_evolution_time_factor = Gui.uid_name()
local on_map_chart = Gui.uid_name()
local on_map_hide = Gui.uid_name()
local on_map_reveal = Gui.uid_name()
local on_map_rechart = Gui.uid_name()
local pages = AdminPanel.get_pages()
pages[#pages +1] = {
type = 'sprite-button',
sprite = 'utility/surface_editor_icon',
tooltip = '[font=default-bold]Map manager[/font]',
name = main_button_name,
auto_toggle = true,
}
local function make_button(parent, params)
local button = parent.add {
type = 'button',
caption = params.caption,
name = params.name,
tooltip = params.tooltip,
}
Gui.set_style(button, {
horizontally_stretchable = true,
})
return button
end
local function make_slider(parent, params)
local flow = parent.add { type = 'flow', direction = 'horizontal' }
Gui.set_style(flow, { vertical_align = 'center', maximal_width = 467 })
local button = flow.add(params.button)
Gui.set_style(button, { width = 150 })
params.slider.value = math.clamp(params.value, params.slider.minimum_value, params.slider.maximum_value)
local slider = flow.add(params.slider)
slider.tags = { name = slider_tag_name }
slider.tooltip = string.format(params.format, slider.slider_value)
Gui.set_style(slider, { width = 250 })
local label = flow.add { type = 'label', caption = string.format(params.format, params.value), tooltip = params.tooltip or 'Current value' }
Gui.set_style(label, { width = 52, horizontal_align = 'right' })
local data = { button = button, slider = slider, label = label, format = params.format }
Gui.set_data(button, data)
Gui.set_data(slider, data)
end
local function update_slider(element)
local data = Gui.get_data(element)
data.label.caption = string.format(data.format, data.slider.slider_value)
return data.slider.slider_value
end
local function draw_gui(player)
local canvas = AdminPanel.get_canvas(player)
Gui.clear(canvas)
local ms = game.map_settings
local evolution = ms.enemy_evolution
local pollution = ms.pollution
local row_1 = canvas.add { type = 'frame', style = 'bordered_frame', direction = 'vertical', caption = 'Game speed' }
make_slider(row_1, {
button = {
type = 'button',
name = on_performance_speed,
caption = 'Performance speed',
tooltip = {'command_description.performance_scale_set'},
},
slider = {
type = 'slider',
minimum_value = 0.05,
maximum_value = 1,
value_step = 0.05,
},
format = '%.2f',
value = game.speed,
})
make_slider(row_1, {
button = {
type = 'button',
name = on_slow_down,
caption = 'Slow down'
},
slider = {
type = 'slider',
minimum_value = 0.05,
maximum_value = 1,
value_step = 0.05,
},
format = '%.2f',
value = game.speed,
})
make_slider(row_1, {
button = {
type = 'button',
name = on_speed_up,
caption = 'Speed up'
},
slider = {
type = 'slider',
minimum_value = 1,
maximum_value = 10,
value_step = 0.5,
},
format = '%.2f',
value = game.speed,
})
local row_2 = canvas.add { type = 'frame', style = 'bordered_frame', direction = 'vertical', caption = 'Pollution' }
make_slider(row_2, {
button = {
type = 'button',
name = on_pollution_ageing,
caption = 'Ageing'
},
slider = {
type = 'slider',
style = 'notched_slider',
minimum_value = 0.1,
maximum_value = 1,
value_step = 0.1,
},
format = '%.2f',
value = pollution.ageing,
})
make_slider(row_2, {
button = {
type = 'button',
name = on_pollution_diffusion,
caption = 'Diffusion ratio'
},
slider = {
type = 'slider',
style = 'notched_slider',
minimum_value = 0,
maximum_value = 0.1,
value_step = 0.02,
},
format = '%.2f',
value = pollution.diffusion_ratio,
})
make_slider(row_2, {
button = {
type = 'button',
name = on_pollution_attack_modifier,
caption = 'Atk. modifier'
},
slider = {
type = 'slider',
style = 'notched_slider',
minimum_value = 0.1,
maximum_value = 1,
value_step = 0.1,
},
format = '%.2f',
value = pollution.enemy_attack_pollution_consumption_modifier,
})
local row_3 = canvas.add { type = 'frame', style = 'bordered_frame', direction = 'vertical', caption = 'Evolution' }
make_slider(row_3, {
button = {
type = 'button',
name = on_evolution_value,
caption = 'Enemy evolution'
},
slider = {
type = 'slider',
minimum_value = 0,
maximum_value = 100,
value_step = 0.01,
},
format = '%.2f',
value = game.forces.enemy.evolution_factor * 100,
tooltip = 'Current value, %',
})
make_slider(row_3, {
button = {
type = 'button',
name = on_evolution_destroy_factor,
caption = 'Destroy factor'
},
slider = {
type = 'slider',
style = 'notched_slider',
minimum_value = 0.00,
maximum_value = 1.00,
value_step = 0.05,
},
format = '%.2f',
value = evolution.destroy_factor * 100,
tooltip = 'Current value, x100',
})
make_slider(row_3, {
button = {
type = 'button',
name = on_evolution_time_factor,
caption = 'Time factor'
},
slider = {
type = 'slider',
minimum_value = 0.000,
maximum_value = 0.100,
value_step = 0.002,
},
format = '%.3f',
value = evolution.time_factor * 1000,
tooltip = 'Current value, x1000',
})
local row_4 = canvas.add { type = 'frame', style = 'bordered_frame', direction = 'vertical', caption = 'Exploration' }
make_slider(row_4, {
button = {
type = 'button',
name = on_map_chart,
caption = 'Chart map'
},
slider = {
type = 'slider',
minimum_value = 1,
maximum_value = 5000,
value_step = 1,
},
format = '%d',
value = 0,
})
local table_4 = row_4.add { type = 'table', column_count = 3 }
for _, button in pairs({
{ name = on_map_hide, caption = 'Hide all' },
{ name = on_map_reveal, caption = 'Reveal all' },
{ name = on_map_rechart, caption = 'Re-chart all' },
}) do make_button(table_4, button) end
end
Gui.on_click(main_button_name, function(event)
local player = event.player
local element = event.element
if element.toggled then
AdminPanel.close_all_pages(player)
event.element.toggled = true
draw_gui(player)
else
Gui.clear(AdminPanel.get_canvas(player))
end
end)
Event.add(defines.events.on_gui_value_changed, function(event)
local element = event.element
if not (element and element.valid) then
return
end
local tag = element.tags and element.tags.name
if not tag or tag ~= slider_tag_name then
return
end
local data = Gui.get_data(element)
data.slider.tooltip = string.format(data.format, data.slider.slider_value)
end)
Gui.on_click(on_performance_speed, function(event)
local element = event.element
local value = update_slider(element)
Surface.performance_scale_set(value)
end)
Gui.on_click(on_slow_down, function(event)
local element = event.element
local value = update_slider(element)
game.speed = value
game.print(string.format('Game speed: %.2f', game.speed))
end)
Gui.on_click(on_speed_up, function(event)
local element = event.element
local value = update_slider(element)
game.speed = value
game.print(string.format('Game speed: %.2f', game.speed))
end)
Gui.on_click(on_pollution_ageing, function(event)
local element = event.element
local value = update_slider(element)
game.map_settings.pollution.ageing = value
end)
Gui.on_click(on_pollution_diffusion, function(event)
local element = event.element
local value = update_slider(element)
game.map_settings.pollution.diffusion_ratio = value
end)
Gui.on_click(on_pollution_attack_modifier, function(event)
local element = event.element
local value = update_slider(element)
game.map_settings.pollution.enemy_attack_pollution_consumption_modifier = value
end)
Gui.on_click(on_evolution_value, function(event)
local element = event.element
local value = update_slider(element)
game.forces.enemy.evolution_factor = value / 100
end)
Gui.on_click(on_evolution_destroy_factor, function(event)
local element = event.element
local value = update_slider(element)
game.map_settings.enemy_evolution.destroy_factor = value / 100
end)
Gui.on_click(on_evolution_time_factor, function(event)
local element = event.element
local value = update_slider(element)
game.map_settings.enemy_evolution.time_factor = value / 1000
end)
Gui.on_click(on_map_chart, function(event)
local element = event.element
local player = event.player
local value = update_slider(element)
Surface.chart_map(player, value)
end)
Gui.on_click(on_map_hide, function(event)
local player = event.player
Surface.hide_all(player)
end)
Gui.on_click(on_map_reveal, function(event)
local player = event.player
Surface.reveal_all(player)
end)
Gui.on_click(on_map_rechart, function(event)
local player = event.player
Surface.rechart_all(player)
end)

View File

@ -0,0 +1,323 @@
local Actions = require 'features.gui.admin_panel.functions'.actions
local AdminPanel = require 'features.gui.admin_panel.core'
local Global = require 'utils.global'
local Gui = require 'utils.gui'
local Table = require 'utils.table'
local main_button_name = Gui.uid_name()
local selection_switch_name = Gui.uid_name()
local selection_dropdown_name = Gui.uid_name()
local on_cheat_mode = Gui.uid_name()
local on_show_reports = Gui.uid_name()
local on_create_pool = Gui.uid_name()
local on_revive_ghosts = Gui.uid_name()
local on_save_game = Gui.uid_name()
local on_delete_blueprints = Gui.uid_name()
local on_destroy_speakers = Gui.uid_name()
local on_remove_biters = Gui.uid_name()
local on_remove_enemies = Gui.uid_name()
local on_add_regular = Gui.uid_name()
local on_add_probation = Gui.uid_name()
local on_jail_player = Gui.uid_name()
local on_remove_regular = Gui.uid_name()
local on_remove_probation = Gui.uid_name()
local on_unjail_player = Gui.uid_name()
local on_invoke_player = Gui.uid_name()
local on_goto_player = Gui.uid_name()
local on_spank_player = Gui.uid_name()
local on_ban_player = Gui.uid_name()
-- local on_teleport = Gui.uid_name()
-- local on_destroy_selected = Gui.uid_name()
local this = {
---@type table<number, table< index: number, name: string >>
player_selection = {},
---@type table<number, string>
selection_switch = {},
---@type table<number, table<string>>
player_ban_items = {},
}
Global.register(this, function(tbl) this = tbl end)
local pages = AdminPanel.get_pages()
pages[#pages +1] = {
type = 'sprite-button',
sprite = 'entity/character',
tooltip = '[font=default-bold]Player manager[/font]',
name = main_button_name,
auto_toggle = true,
}
local ban_items = {}
for _, text in pairs({
'damaging base',
'griefing',
'insulting other players',
'mass deconstruction',
'offensive language',
'resource hoarding',
'tanking server UPS',
'toxic behavior',
}) do table.insert(ban_items, { name = Gui.uid_name(), caption = text }) end
local function get_selected_player(player)
return this.player_selection[player.index].name or '__NIL__'
end
local function get_player_list(player_index)
local player_list = { '-- ▼ -- select player -- ▼ --' }
local mode = this.selection_switch[player_index] or 'none'
if mode == 'none' then -- all
for _, p in pairs(game.players) do
player_list[#player_list +1] = p.name
end
elseif mode == 'left' then --- online
for _, p in pairs(game.connected_players) do
player_list[#player_list +1] = p.name
end
elseif mode == 'right' then -- offline
for _, p in pairs(game.players) do
if not p.connected then
player_list[#player_list +1] = p.name
end
end
end
return player_list
end
local function generate_ban_text(player)
local items = this.player_ban_items[player.index]
return table.concat(items, ', ') .. '. To appeal ban visit redmew.com/discord #helpdesk.'
end
local function make_button(parent, params)
local button = parent.add {
type = 'button',
caption = params.caption,
name = params.name,
tooltip = params.tooltip,
}
Gui.set_style(button, {
horizontally_stretchable = true,
})
return button
end
local function make_checkbox(parent, params)
local checkbox = parent.add {
type = 'checkbox',
caption = params.caption,
name = params.name,
tooltip = params.tooltip,
state = params.state or false,
}
Gui.set_style(checkbox, {
horizontally_stretchable = true,
})
return checkbox
end
local function make_player_dropdown(parent)
local player_index = parent.player_index
local player_list = get_player_list(player_index)
local selection_data = this.player_selection[player_index]
if selection_data.index > #player_list then
selection_data.index = 1
end
selection_data.name = player_list[selection_data.index]
local selection_flow = parent.add { type = 'flow', direction = 'horizontal' }
Gui.set_style(selection_flow, { vertical_align = 'center' })
selection_flow.add { type = 'label', caption = '[font=default-small][color=255,230,192]ONLINE[/color][/font]' }
selection_flow.add { type = 'switch', name = selection_switch_name, switch_state = this.selection_switch[player_index], allow_none_state = true }
selection_flow.add { type = 'label', caption = '[font=default-small][color=255,230,192]OFFLINE[/color][/font]' }
local dropdown = selection_flow.add { type = 'drop-down', name = selection_dropdown_name, selected_index = selection_data.index, items = player_list }
Gui.set_style(dropdown, { horizontally_stretchable = true })
return selection_flow
end
local function draw_gui(player)
local canvas = AdminPanel.get_canvas(player)
Gui.clear(canvas)
this.player_selection[player.index] = this.player_selection[player.index] or { index = 1 }
this.selection_switch[player.index] = this.selection_switch[player.index] or 'none'
this.player_ban_items[player.index] = this.player_ban_items[player.index] or {}
local row_1 = canvas.add { type = 'frame', style = 'bordered_frame', direction = 'vertical', caption = 'General actions' }
local table_1 = row_1.add { type = 'table', column_count = 3 }
for _, button in pairs({
{ name = on_cheat_mode, caption = 'Cheat mode' },
{ name = on_show_reports, caption = 'Show reports' },
{ name = on_create_pool, caption = 'Create pool' },
{ name = on_revive_ghosts, caption = 'Revive ghosts' },
{ name = on_save_game, caption = 'Save game' },
{ name = on_delete_blueprints, caption = 'Destroy ghost entities' },
{ name = on_destroy_speakers, caption = 'Destroy speakers' },
{ name = on_remove_biters, caption = 'Remove biters' },
{ name = on_remove_enemies, caption = 'Remove all enemies' },
-- { name = on_teleport, caption = 'Teleport' },
-- { name = on_destroy_selected, caption = 'Destroy selected' }
}) do make_button(table_1, button) end
local row_2 = canvas.add { type = 'frame', style = 'bordered_frame', direction = 'vertical', caption = 'Players management' }
local table_2 = row_2.add { type = 'table', column_count = 3 }
for _, button in pairs({
{ name = on_add_regular, caption = 'Add regular' },
{ name = on_add_probation, caption = 'Add probation' },
{ name = on_jail_player, caption = 'Jail player' },
{ name = on_remove_regular, caption = 'Remove regular' },
{ name = on_remove_probation, caption = 'Remove probation' },
{ name = on_unjail_player, caption = 'Unjail player' },
{ name = on_invoke_player, caption = 'Invoke player' },
{ name = on_goto_player, caption = 'Goto player' },
{ name = on_spank_player, caption = 'Spank player' },
}) do make_button(table_2, button) end
make_player_dropdown(row_2)
local row_3 = canvas.add { type = 'frame', style = 'bordered_frame', direction = 'vertical', caption = 'Players ban' }
local table_3 = row_3.add { type = 'table', column_count = 2 }
for _, item in pairs(ban_items) do
make_checkbox(table_3, {
caption = item.caption,
name = item.name,
state = Table.contains(this.player_ban_items[player.index], item.caption),
})
end
make_player_dropdown(row_3)
local textbox = row_3.add { type = 'text-box', text = generate_ban_text(player) }
Gui.set_style(textbox, { minimal_width = 460, maximal_width = 460, minimal_height = 72, horizontally_stretchable = true, vertically_stretchable = true })
textbox.word_wrap = true
textbox.clear_and_focus_on_right_click = true
local flow_3 = row_3.add { type = 'flow', direction = 'horizontal' }
Gui.add_pusher(flow_3)
local ban_button = flow_3.add { type = 'button', name = on_ban_player, style = 'confirm_button', caption = 'Ban player' }
Gui.set_data(ban_button, { textbox = textbox })
end
Gui.on_click(main_button_name, function(event)
local player = event.player
local element = event.element
if element.toggled then
AdminPanel.close_all_pages(player)
event.element.toggled = true
draw_gui(player)
else
Gui.clear(AdminPanel.get_canvas(player))
end
end)
Gui.on_switch_state_changed(selection_switch_name, function(event)
local player = event.player
this.selection_switch[player.index] = event.element.switch_state
this.player_selection[player.index].index = 1
draw_gui(player)
end)
Gui.on_selection_state_changed(selection_dropdown_name, function(event)
local player = event.player
local element = event.element
this.player_selection[player.index].index = element.selected_index
draw_gui(player)
end)
for _, ban_item in pairs(ban_items) do
Gui.on_checked_state_changed(ban_item.name, function(event)
local player = event.player
local element = event.element
if element.state then
table.insert(this.player_ban_items[player.index], element.caption)
else
Table.remove_element(this.player_ban_items[player.index], element.caption)
end
draw_gui(player)
end)
end
Gui.on_click(on_ban_player, function(event)
local data = Gui.get_data(event.element)
local target_name = get_selected_player(event.player)
Actions.ban_player(target_name, data.textbox.text, event.player)
end)
Gui.on_click(on_cheat_mode, function(event)
Actions.toggle_cheat_mode(nil, event.player)
end)
Gui.on_click(on_show_reports, function(event)
Actions.show_reports(nil, event.player)
end)
Gui.on_click(on_create_pool, function(event)
Actions.create_pool(nil, event.player)
end)
Gui.on_click(on_revive_ghosts, function(event)
Actions.revive_ghosts({ radius = 32 * 10 }, event.player)
end)
Gui.on_click(on_save_game, function(event)
Actions.save_game(nil, event.player)
end)
Gui.on_click(on_delete_blueprints, function(event)
Actions.remove_all_ghost_entities(event.player)
end)
Gui.on_click(on_destroy_speakers, function(event)
Actions.destroy_all_speakers(event.player)
end)
Gui.on_click(on_remove_biters, function(event)
Actions.kill_all_enemy_units(event.player)
end)
Gui.on_click(on_remove_enemies, function(event)
Actions.kill_all_enemies(event.player)
end)
Gui.on_click(on_add_regular, function(event)
local target_name = get_selected_player(event.player)
Actions.regular_add({ player = target_name, actor = event.player.name }, event.player)
end)
Gui.on_click(on_add_probation, function(event)
local target_name = get_selected_player(event.player)
Actions.probation_add({ player = target_name, actor = event.player.name }, event.player)
end)
Gui.on_click(on_jail_player, function(event)
local target_name = get_selected_player(event.player)
Actions.jail_player({ player = target_name }, event.player)
end)
Gui.on_click(on_remove_regular, function(event)
local target_name = get_selected_player(event.player)
Actions.regular_remove({ player = target_name, actor = event.player.name }, event.player)
end)
Gui.on_click(on_remove_probation, function(event)
local target_name = get_selected_player(event.player)
Actions.probation_remove({ player = target_name, actor = event.player.name }, event.player)
end)
Gui.on_click(on_unjail_player, function(event)
local target_name = get_selected_player(event.player)
Actions.unjail_player({ player = target_name }, event.player)
end)
Gui.on_click(on_spank_player, function(event)
local target_name = get_selected_player(event.player)
Actions.spank(target_name, event.player)
end)
Gui.on_click(on_invoke_player, function(event)
local target_name = get_selected_player(event.player)
Actions.invoke_player({ player = target_name }, event.player)
end)

View File

@ -84,7 +84,7 @@ Command.add(
p({'performance.stat_preamble'})
p({'performance.generic_stat', {'performance.game_speed'}, format('%.2f', Performance.get_time_scale())})
local stat_string = format('%.2f', stat_mod)
p({'performance.output_formatter', {'performance.game_speed'}, stat_string, {'performance.manual_mining_speed'}, stat_string, {'performance.manual_crafting_speed'}, stat_string})
p({'performance.output_formatter', {'performance.running_speed'}, stat_string, {'performance.manual_mining_speed'}, stat_string, {'performance.manual_crafting_speed'}, stat_string})
end
)
@ -98,7 +98,7 @@ Command.add(
local stat_mod = Performance.get_player_stat_modifier()
p({'performance.generic_stat', {'performance.game_speed'}, format('%.2f', Performance.get_time_scale())})
local stat_string = format('%.2f', stat_mod)
p({'performance.output_formatter', {'performance.game_speed'}, stat_string, {'performance.manual_mining_speed'}, stat_string, {'performance.manual_crafting_speed'}, stat_string})
p({'performance.output_formatter', {'performance.running_speed'}, stat_string, {'performance.manual_mining_speed'}, stat_string, {'performance.manual_crafting_speed'}, stat_string})
end
)

View File

@ -47,12 +47,12 @@ local function report_command(args, player)
local reported_player = game.get_player(reported_player_name)
if not reported_player then
Game.player_print(reported_player_name .. ' does not exist.')
Game.player_print(reported_player_name .. ' does not exist.', Color.fail, player)
return nil
end
Module.report(player, reported_player, args.message)
Game.player_print('Your report has been sent.')
Game.player_print('Your report has been sent.', Color.success, player)
end
local function draw_report(parent, report_id)
@ -380,7 +380,7 @@ function Module.unjail(target_player, player)
local permissions = game.permissions
local jail_permission_group = permissions.get_group(jail_name)
if (not jail_permission_group) or target_player.permission_group ~= jail_permission_group or not target_jail_data then
Game.player_print(format('%s is already not in Jail.', target_name))
Game.player_print(format('%s is already not in Jail.', target_name), Color.warning, player)
return
end
@ -416,7 +416,7 @@ function Module.unjail(target_player, player)
-- Check that it worked
if target_player.permission_group == permission_group then
-- Let admin know it worked, let target know what's going on.
Game.player_print(target_name .. ' has been returned to the default group. They have been advised of this.')
Game.player_print(target_name .. ' has been returned to the default group. They have been advised of this.', Color.success, player)
target_player.print(prefix)
target_player.print('Your ability to perform actions has been restored', Color.light_green)
target_player.print(prefix_e)
@ -426,14 +426,15 @@ function Module.unjail(target_player, player)
-- Let admin know it didn't work.
Game.player_print(format(
'Something went wrong in the unjailing of %s. You can still change their group via /permissions and inform them.',
target_name))
target_name), Color.fail, player)
end
end
--- Bans the player and reports the ban to moderation log channel.
-- @param player<LuaPlayer>
-- @param reason<string?> defaults to empty string.
function Module.ban_player(player, reason)
-- @param player <LuaPlayer>
-- @param reason <string?> defaults to empty string.
-- @param actor <LuaPlayer?> the player performing the ban action, if any
function Module.ban_player(player, reason, actor)
if not player or not player.valid then
return
end
@ -448,10 +449,16 @@ function Module.ban_player(player, reason)
local server_id = Server.get_server_id()
local server_name = Server.get_server_name()
local actor_name = '<script>'
if actor and actor.valid then
actor_name = actor.name
end
Server.report_ban(player.name, actor_name, reason)
local text = {'**'}
text[#text + 1] = Utils.sanitise_string_for_discord(player.name)
text[#text + 1] = ' was banned by <script>**\\n'
text[#text + 1] = ' was banned by ' .. actor_name .. '**\\n'
if server_id ~= '' then
text[#text + 1] = 'Server: s'
@ -476,7 +483,8 @@ end
--- kicks the player and reports the kick to moderation log channel.
-- @param player<LuaPlayer>
-- @param reason<string?> defaults to empty string.
function Module.kick_player(player, reason)
-- @param actor <LuaPlayer?> the player performing the kick action, if any
function Module.kick_player(player, reason, actor)
if not player or not player.valid then
return
end
@ -491,10 +499,14 @@ function Module.kick_player(player, reason)
local server_id = Server.get_server_id()
local server_name = Server.get_server_name()
local actor_name = '<script>'
if actor and actor.valid then
actor_name = actor.name
end
local text = {'**'}
text[#text + 1] = Utils.sanitise_string_for_discord(player.name)
text[#text + 1] = ' was kicked by <script>**\\n'
text[#text + 1] = ' was kicked by ' .. actor_name .. '**\\n'
if server_id ~= '' then
text[#text + 1] = 'Server: s'

View File

@ -55,6 +55,7 @@ local data_tracked_tag = '[DATA-TRACKED]'
local query_players_tag = '[QUERY-PLAYERS]'
local player_join_tag = '[PLAYER-JOIN]'
local player_leave_tag = '[PLAYER-LEAVE]'
local player_banned_tag = '[BAN]'
Public.raw_print = raw_print
@ -180,6 +181,17 @@ function Public.to_discord_named_embed_raw(channel_name, message)
raw_print(concat({discord_named_embed_raw_tag, channel_name, ' ', message}))
end
--- Tells the server that a ban has happend, this will overwrite any existing bans.
-- The purpose is that game.ban doesn't report the admin so we use this function to fill that in.
-- @param player_name<string> the player to ban.
-- @param admin_name<string> the admin that did the ban.
-- @param reason<string> the optional reason for the ban.
function Public.report_ban(player_name, admin_name, reason)
assert_non_empty_string_and_no_spaces(player_name, 'player_name')
assert_non_empty_string_and_no_spaces(admin_name, 'admin_name')
raw_print(concat({player_banned_tag, ' ', player_name, ' was banned by ', admin_name, '. Reason: ', reason}))
end
--- Stops and saves the factorio server and starts the named scenario.
-- @param scenario_name<string> The name of the scenario as appears in the scenario table on http://redmew.com/admin
-- @usage

View File

@ -31,6 +31,8 @@ tp_mode_off=tp mode is now off
tp_mode_on=tp mode is now on - place a ghost entity to teleport there.
destroy_success=__1__ destroyed
destroy_fail=Nothing found to destroy. (You must have an entity under your cursor when you hit enter)
revive_ghosts=Revived __1__ ghost(s).
create_pool=Ready to swim!
[redmew_commands]
kill_fail_suicide_no_character=Sorry, you don't have a character to kill.

View File

@ -133,3 +133,6 @@ battery_charge_caption=Battery recharge
battery_charge_tooltip=[font=default-bold]Battery recharge[/font] - Recharge battery equipments in your armor from nearby accumulators.\nThey must have at least 3MJ of energy stored.
auto_stash_caption=Auto stash
auto_stash_tooltip=[font=default-bold]Auto stash[/font] - Sort your inventory into nearby chests.\n[color=yellow][font=default-bold]LMB[/font][/color]: Everything, excluding quickbar items.\n[color=yellow][font=default-bold]RMB[/font][/color]: Only ores to nearby chests, excluding quickbar items.\n[color=yellow][font=default-bold]CTRL + RMB[/font][/color]: Fill nearby furnaces.\n[color=yellow][font=default-bold]SHIFT + LMB[/font][/color]: Everything onto filtered slots to wagon/chests.\n[color=yellow][font=default-bold]SHIFT + RMB[/font][/color]: Only ores to wagon.
[admin_panel]
info_tooltip=[font=default-bold]Admin panel[/font] - Toggle your admin panel

View File

@ -30,10 +30,11 @@ end
--- Prints to player or console.
-- @param msg <string|table> table if locale is used
-- @param color <table> defaults to white
function Game.player_print(msg, color)
-- @param player <LuaPlayer?>
function Game.player_print(msg, color, player)
color = color or Color.white
local player = game.player
if player then
player = player or game.player
if player and player.valid then
player.print(msg, color)
else
print(msg)

View File

@ -304,6 +304,12 @@ Gui.on_text_changed = handler_factory(defines.events.on_gui_text_changed)
-- Adds a player field to the event table.
Gui.on_value_changed = handler_factory(defines.events.on_gui_value_changed)
-- Register a handler for the on_gui_switch_state_changed event for LuaGuiElements with element_name.
-- Can only have one handler per element name.
-- Guarantees that the element and the player are valid when calling the handler.
-- Adds a player field to the event table.
Gui.on_switch_state_changed = handler_factory(defines.events.on_gui_switch_state_changed)
-- Register a handler for when the player shows the top LuaGuiElements with element_name.
-- Assuming the element_name has been added with Gui.allow_player_to_toggle_top_element_visibility.
-- Can only have one handler per element name.

View File

@ -7,8 +7,8 @@ Declare.module({'utils', 'Gui'}, function()
Declare.module('can toggle top buttons', function()
local function count_gui_elements(player)
-- local gui = player.gui
-- return #gui.top.children + #gui.left.children + #gui.center.children
return #Gui.get_top_flow(player).children + #Gui.get_left_flow(player).children + #player.gui.center.children
-- return #gui.top.children + #gui.left.children + #gui.center.children + #gui.screen.children
return #Gui.get_top_flow(player).children + #Gui.get_left_flow(player).children + #player.gui.center.children + #player.gui.screen.children
end
local function is_ignored_element(element)