mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
Add Tool Gui (#20)
* Update _file_loader.lua * Create tool.lua * Update trains.lua * Update research.lua * Fix use of created_entity in events * Update trains.lua * Update tool.lua * Update research.lua * Update research.lua * Update tool.lua * Update research.lua * Update trains.lua * Fix waterfill locale * Fix bug with selection tools and remote view * Fix tool GUI * Update tool.lua --------- Co-authored-by: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com>
This commit is contained in:
@@ -56,6 +56,7 @@ return {
|
|||||||
"modules.gui.research",
|
"modules.gui.research",
|
||||||
"modules.gui.module",
|
"modules.gui.module",
|
||||||
"modules.gui.landfill",
|
"modules.gui.landfill",
|
||||||
|
"modules.gui.tool",
|
||||||
"modules.gui.production",
|
"modules.gui.production",
|
||||||
"modules.gui.playerdata",
|
"modules.gui.playerdata",
|
||||||
"modules.gui.surveillance",
|
"modules.gui.surveillance",
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ Roles.new_role("Member", "Mem")
|
|||||||
"gui/warp-list/edit",
|
"gui/warp-list/edit",
|
||||||
"gui/surveillance",
|
"gui/surveillance",
|
||||||
"gui/vlayer-edit",
|
"gui/vlayer-edit",
|
||||||
|
"gui/tool",
|
||||||
"command/save-quickbar",
|
"command/save-quickbar",
|
||||||
"command/vlayer-info",
|
"command/vlayer-info",
|
||||||
"command/personal-logistic",
|
"command/personal-logistic",
|
||||||
|
|||||||
@@ -31,9 +31,10 @@ Storage.register({
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
--- Let a player select an area by providing a selection planner
|
--- Let a player select an area by providing a selection planner
|
||||||
-- @tparam LuaPlayer player The player to place into selection mode
|
--- @param player LuaPlayer The player to place into selection mode
|
||||||
-- @tparam string selection_name The name of the selection to start, used with on_selection
|
--- @param selection_name string The name of the selection to start, used with on_selection
|
||||||
-- @tparam[opt=false] boolean single_use When true the selection will stop after first use
|
--- @param single_use boolean? When true the selection will stop after first use
|
||||||
|
--- @param ... any Arguments to pass to the selection handler
|
||||||
function Selection.start(player, selection_name, single_use, ...)
|
function Selection.start(player, selection_name, single_use, ...)
|
||||||
if not player or not player.valid then return end
|
if not player or not player.valid then return end
|
||||||
if selections[player.index] then
|
if selections[player.index] then
|
||||||
@@ -67,10 +68,15 @@ function Selection.start(player, selection_name, single_use, ...)
|
|||||||
player.clear_cursor() -- Clear the current item
|
player.clear_cursor() -- Clear the current item
|
||||||
player.cursor_stack.set_stack(selection_tool)
|
player.cursor_stack.set_stack(selection_tool)
|
||||||
|
|
||||||
|
-- This does not work for selection planners, will make a feature request for it
|
||||||
|
--player.cursor_stack_temporary = true
|
||||||
|
|
||||||
-- Make a slot to place the selection tool even if inventory is full
|
-- Make a slot to place the selection tool even if inventory is full
|
||||||
if not player.character then return end
|
|
||||||
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus + 1
|
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus + 1
|
||||||
player.hand_location = { inventory = defines.inventory.character_main, slot = #player.get_main_inventory() }
|
local inventory = player.get_main_inventory()
|
||||||
|
if inventory then
|
||||||
|
player.hand_location = { inventory = inventory.index, slot = #inventory }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Stop a player selection by removing the selection planner
|
--- Stop a player selection by removing the selection planner
|
||||||
@@ -150,6 +156,16 @@ Event.add(defines.events.on_player_cursor_stack_changed, function(event)
|
|||||||
if player.cursor_stack.is_selection_tool then return end
|
if player.cursor_stack.is_selection_tool then return end
|
||||||
Selection.stop(player)
|
Selection.stop(player)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
--- Make sure the hand location exists when the player returns from remote view
|
||||||
|
Event.add(defines.events.on_player_controller_changed, function(event)
|
||||||
|
local player = game.players[event.player_index] --- @cast player -nil
|
||||||
|
local inventory = player.get_main_inventory()
|
||||||
|
if player.cursor_stack.is_selection_tool and inventory then
|
||||||
|
player.hand_location = { inventory = inventory.index, slot = #inventory }
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
--- Stop selection after an event such as death or leaving the game
|
--- Stop selection after an event such as death or leaving the game
|
||||||
local function stop_after_event(event)
|
local function stop_after_event(event)
|
||||||
local player = game.players[event.player_index]
|
local player = game.players[event.player_index]
|
||||||
|
|||||||
262
exp_legacy/module/modules/gui/tool.lua
Normal file
262
exp_legacy/module/modules/gui/tool.lua
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
--[[-- Gui Module - Tool
|
||||||
|
@gui Tool
|
||||||
|
@alias tool_container
|
||||||
|
]]
|
||||||
|
|
||||||
|
local ExpUtil = require("modules/exp_util")
|
||||||
|
local Gui = require("modules/exp_legacy/expcore/gui") --- @dep expcore.gui
|
||||||
|
local Roles = require("modules.exp_legacy.expcore.roles") --- @dep expcore.roles
|
||||||
|
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
|
||||||
|
local Selection = require("modules/exp_legacy/modules/control/selection") --- @dep modules.control.selection
|
||||||
|
local addon_train = require("modules/exp_scenario/commands/trains")
|
||||||
|
local addon_research = require("modules/exp_scenario/commands/research")
|
||||||
|
|
||||||
|
local tool_container
|
||||||
|
|
||||||
|
local SelectionArtyArea = "ExpCommand_Artillery"
|
||||||
|
local SelectionWaterfillArea = "ExpCommand_Waterfill"
|
||||||
|
|
||||||
|
local style = {
|
||||||
|
label = {
|
||||||
|
width = 160
|
||||||
|
},
|
||||||
|
button = {
|
||||||
|
width = 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Arty label
|
||||||
|
-- @element tool_gui_arty_l
|
||||||
|
local tool_gui_arty_l =
|
||||||
|
Gui.element{
|
||||||
|
type = "label",
|
||||||
|
name = "tool_arty_l",
|
||||||
|
caption = { "tool.artillery" },
|
||||||
|
tooltip = { "tool.artillery-tooltip" },
|
||||||
|
style = "heading_2_label"
|
||||||
|
}:style(
|
||||||
|
style.label
|
||||||
|
)
|
||||||
|
|
||||||
|
--- Arty button
|
||||||
|
-- @element tool_gui_arty_b
|
||||||
|
local tool_gui_arty_b =
|
||||||
|
Gui.element{
|
||||||
|
type = "button",
|
||||||
|
name = "tool_arty_b",
|
||||||
|
caption = { "tool.apply" }
|
||||||
|
}:style(
|
||||||
|
style.button
|
||||||
|
):on_click(function(player, _, _)
|
||||||
|
if Selection.is_selecting(player, SelectionArtyArea) then
|
||||||
|
Selection.stop(player)
|
||||||
|
|
||||||
|
else
|
||||||
|
Selection.start(player, SelectionArtyArea)
|
||||||
|
player.print{ "tool.entered-area-selection" }
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Waterfill label
|
||||||
|
-- @element tool_gui_waterfill_l
|
||||||
|
local tool_gui_waterfill_l =
|
||||||
|
Gui.element{
|
||||||
|
type = "label",
|
||||||
|
name = "tool_waterfill_l",
|
||||||
|
caption = { "tool.waterfill" },
|
||||||
|
tooltip = { "tool.waterfill-tooltip" },
|
||||||
|
style = "heading_2_label"
|
||||||
|
}:style(
|
||||||
|
style.label
|
||||||
|
)
|
||||||
|
|
||||||
|
--- Waterfill button
|
||||||
|
-- @element tool_gui_waterfill_b
|
||||||
|
local tool_gui_waterfill_b =
|
||||||
|
Gui.element{
|
||||||
|
type = "button",
|
||||||
|
name = "tool_waterfill_b",
|
||||||
|
caption = { "tool.apply" }
|
||||||
|
}:style(
|
||||||
|
style.button
|
||||||
|
):on_click(function(player, _, _)
|
||||||
|
if Selection.is_selecting(player, SelectionWaterfillArea) then
|
||||||
|
Selection.stop(player)
|
||||||
|
return player.print{ "exp-commands_waterfill.exit" }
|
||||||
|
elseif player.get_item_count("cliff-explosives") == 0 then
|
||||||
|
return player.print{ "exp-commands_waterfill.requires-explosives" }
|
||||||
|
else
|
||||||
|
Selection.start(player, SelectionWaterfillArea)
|
||||||
|
return player.print{ "exp-commands_waterfill.enter" }
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Train label
|
||||||
|
-- @element tool_gui_train_l
|
||||||
|
local tool_gui_train_l =
|
||||||
|
Gui.element{
|
||||||
|
type = "label",
|
||||||
|
name = "tool_train_l",
|
||||||
|
caption = { "tool.train" },
|
||||||
|
tooltip = { "tool.train-tooltip" },
|
||||||
|
style = "heading_2_label"
|
||||||
|
}:style(
|
||||||
|
style.label
|
||||||
|
)
|
||||||
|
|
||||||
|
--- Train button
|
||||||
|
-- @element tool_gui_train_b
|
||||||
|
local tool_gui_train_b =
|
||||||
|
Gui.element{
|
||||||
|
type = "button",
|
||||||
|
name = "tool_train_b",
|
||||||
|
caption = { "tool.apply" }
|
||||||
|
}:style(
|
||||||
|
style.button
|
||||||
|
):on_click(function(player, _, _)
|
||||||
|
addon_train.manual(player)
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Research label
|
||||||
|
-- @element tool_gui_research_l
|
||||||
|
local tool_gui_research_l =
|
||||||
|
Gui.element{
|
||||||
|
type = "label",
|
||||||
|
name = "tool_research_l",
|
||||||
|
caption = { "tool.research" },
|
||||||
|
tooltip = { "tool.research-tooltip" },
|
||||||
|
style = "heading_2_label"
|
||||||
|
}:style(
|
||||||
|
style.label
|
||||||
|
)
|
||||||
|
|
||||||
|
--- Research button
|
||||||
|
-- @element tool_gui_research_b
|
||||||
|
local tool_gui_research_b =
|
||||||
|
Gui.element{
|
||||||
|
type = "button",
|
||||||
|
name = "tool_research_b",
|
||||||
|
caption = { "tool.apply" }
|
||||||
|
}:style(
|
||||||
|
style.button
|
||||||
|
):on_click(function(player, _, _)
|
||||||
|
local enabled = addon_research.set_auto_research()
|
||||||
|
|
||||||
|
if enabled then
|
||||||
|
addon_research.res_queue(player.force, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
local player_name = ExpUtil.format_player_name_locale(player)
|
||||||
|
game.print{ "exp-commands_research.auto-research", player_name, enabled }
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Spawn label
|
||||||
|
-- @element tool_gui_spawn_l
|
||||||
|
local tool_gui_spawn_l =
|
||||||
|
Gui.element{
|
||||||
|
type = "label",
|
||||||
|
name = "tool_spawn_l",
|
||||||
|
caption = { "tool.spawn" },
|
||||||
|
tooltip = { "tool.spawn-tooltip" },
|
||||||
|
style = "heading_2_label"
|
||||||
|
}:style(
|
||||||
|
style.label
|
||||||
|
)
|
||||||
|
|
||||||
|
--- Spawn button
|
||||||
|
-- @element tool_gui_spawn_b
|
||||||
|
local tool_gui_spawn_b =
|
||||||
|
Gui.element{
|
||||||
|
type = "button",
|
||||||
|
name = "tool_spawn_b",
|
||||||
|
caption = { "tool.apply" }
|
||||||
|
}:style(
|
||||||
|
style.button
|
||||||
|
):on_click(function(player, _, _)
|
||||||
|
if not player.character
|
||||||
|
or player.character.health <= 0
|
||||||
|
or not ExpUtil.teleport_player(player, game.surfaces.nauvis, { 0, 0 }, "dismount") then
|
||||||
|
return player.print{ "exp-commands_teleport.unavailable" }
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function tool_perm(player)
|
||||||
|
local frame = Gui.get_left_element(player, tool_container)
|
||||||
|
local disp = frame.container["tool_st"].disp.table
|
||||||
|
local allowed
|
||||||
|
|
||||||
|
allowed = Roles.player_allowed(player, "command/artillery")
|
||||||
|
disp[tool_gui_arty_l.name].visible = allowed
|
||||||
|
disp[tool_gui_arty_b.name].visible = allowed
|
||||||
|
|
||||||
|
allowed = Roles.player_allowed(player, "command/waterfill")
|
||||||
|
disp[tool_gui_waterfill_l.name].visible = allowed
|
||||||
|
disp[tool_gui_waterfill_b.name].visible = allowed
|
||||||
|
|
||||||
|
allowed = Roles.player_allowed(player, "command/set-trains-to-automatic")
|
||||||
|
disp[tool_gui_train_l.name].visible = allowed
|
||||||
|
disp[tool_gui_train_b.name].visible = allowed
|
||||||
|
|
||||||
|
allowed = Roles.player_allowed(player, "command/set-auto-research")
|
||||||
|
disp[tool_gui_research_l.name].visible = allowed
|
||||||
|
disp[tool_gui_research_b.name].visible = allowed
|
||||||
|
|
||||||
|
allowed = Roles.player_allowed(player, "command/spawn")
|
||||||
|
disp[tool_gui_spawn_l.name].visible = allowed
|
||||||
|
disp[tool_gui_spawn_b.name].visible = allowed
|
||||||
|
end
|
||||||
|
|
||||||
|
--- A vertical flow containing all the tool
|
||||||
|
-- @element tool_set
|
||||||
|
local tool_set =
|
||||||
|
Gui.element(function(_, parent, name)
|
||||||
|
local tool_set = parent.add{ type = "flow", direction = "vertical", name = name }
|
||||||
|
local disp = Gui.scroll_table(tool_set, 240, 2, "disp")
|
||||||
|
|
||||||
|
tool_gui_arty_l(disp)
|
||||||
|
tool_gui_arty_b(disp)
|
||||||
|
|
||||||
|
tool_gui_waterfill_l(disp)
|
||||||
|
tool_gui_waterfill_b(disp)
|
||||||
|
|
||||||
|
tool_gui_train_l(disp)
|
||||||
|
tool_gui_train_b(disp)
|
||||||
|
|
||||||
|
tool_gui_research_l(disp)
|
||||||
|
tool_gui_research_b(disp)
|
||||||
|
|
||||||
|
tool_gui_spawn_l(disp)
|
||||||
|
tool_gui_spawn_b(disp)
|
||||||
|
|
||||||
|
return tool_set
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- The main container for the tool gui
|
||||||
|
-- @element tool_container
|
||||||
|
tool_container =
|
||||||
|
Gui.element(function(definition, parent)
|
||||||
|
local player = Gui.get_player_from_element(parent)
|
||||||
|
local container = Gui.container(parent, definition.name, 240)
|
||||||
|
|
||||||
|
tool_set(container, "tool_st")
|
||||||
|
|
||||||
|
tool_perm(player)
|
||||||
|
|
||||||
|
return container.parent
|
||||||
|
end)
|
||||||
|
:static_name(Gui.unique_static_name)
|
||||||
|
:add_to_left_flow()
|
||||||
|
|
||||||
|
--- Button on the top flow used to toggle the tool container
|
||||||
|
-- @element toggle_left_element
|
||||||
|
Gui.left_toolbar_button("item/repair-pack", { "tool.main-tooltip" }, tool_container, function(player)
|
||||||
|
return Roles.player_allowed(player, "gui/tool")
|
||||||
|
end)
|
||||||
|
|
||||||
|
Event.add(Roles.events.on_role_assigned, function(event)
|
||||||
|
tool_perm(game.players[event.player_index])
|
||||||
|
end)
|
||||||
|
|
||||||
|
Event.add(Roles.events.on_role_unassigned, function(event)
|
||||||
|
tool_perm(game.players[event.player_index])
|
||||||
|
end)
|
||||||
@@ -36,24 +36,34 @@ function module.res_queue(force, silent)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- @param state boolean? use nil to toggle current state
|
||||||
|
--- @return boolean # New auto research state
|
||||||
|
function module.set_auto_research(state)
|
||||||
|
local new_state
|
||||||
|
if state == nil then
|
||||||
|
new_state = not research.res_queue_enable
|
||||||
|
else
|
||||||
|
new_state = state ~= false
|
||||||
|
end
|
||||||
|
|
||||||
|
research.res_queue_enable = new_state
|
||||||
|
return new_state
|
||||||
|
end
|
||||||
|
|
||||||
--- Sets the auto research state
|
--- Sets the auto research state
|
||||||
Commands.new("set-auto-research", { "exp-commands_research.description" })
|
Commands.new("set-auto-research", { "exp-commands_research.description" })
|
||||||
:optional("state", { "exp-commands_research.arg-state" }, Commands.types.boolean)
|
:optional("state", { "exp-commands_research.arg-state" }, Commands.types.boolean)
|
||||||
:add_aliases{ "auto-research" }
|
:add_aliases{ "auto-research" }
|
||||||
:register(function(player, state)
|
:register(function(player, state)
|
||||||
--- @cast state boolean?
|
--- @cast state boolean?
|
||||||
if state == nil then
|
local enabled = module.set_auto_research(state)
|
||||||
research.res_queue_enable = not research.res_queue_enable
|
|
||||||
else
|
|
||||||
research.res_queue_enable = state
|
|
||||||
end
|
|
||||||
|
|
||||||
if research.res_queue_enable then
|
if enabled then
|
||||||
module.res_queue(player.force --[[@as LuaForce]], true)
|
module.res_queue(player.force --[[@as LuaForce]], true)
|
||||||
end
|
end
|
||||||
|
|
||||||
local player_name = format_player_name(player)
|
local player_name = format_player_name(player)
|
||||||
game.print{ "exp-commands_research.auto-research", player_name, research.res_queue_enable }
|
game.print{ "exp-commands_research.auto-research", player_name, enabled }
|
||||||
end)
|
end)
|
||||||
|
|
||||||
--- @param event EventData.on_research_finished
|
--- @param event EventData.on_research_finished
|
||||||
|
|||||||
@@ -4,16 +4,12 @@ Adds a command that set all train back to automatic
|
|||||||
|
|
||||||
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 format_number = require("util").format_number
|
local format_number = require("util").format_number
|
||||||
|
|
||||||
--- Set all trains to automatic
|
--- @class Command.Trains
|
||||||
Commands.new("set-trains-to-automatic", { "exp-commands_trains.description" })
|
local module = {}
|
||||||
:optional("surface", { "exp-commands_trains.arg-surface" }, Commands.types.surface)
|
|
||||||
:optional("force", { "exp-commands_trains.arg-force" }, Commands.types.force)
|
function module.manual(player, surface, force)
|
||||||
:register(function(player, surface, force)
|
|
||||||
--- @cast surface LuaSurface?
|
|
||||||
--- @cast force LuaForce?
|
|
||||||
local trains = game.train_manager.get_trains{
|
local trains = game.train_manager.get_trains{
|
||||||
has_passenger = false,
|
has_passenger = false,
|
||||||
is_manual = true,
|
is_manual = true,
|
||||||
@@ -26,4 +22,16 @@ Commands.new("set-trains-to-automatic", { "exp-commands_trains.description" })
|
|||||||
end
|
end
|
||||||
|
|
||||||
game.print{ "exp-commands_trains.response", format_player_name(player), format_number(#trains, false) }
|
game.print{ "exp-commands_trains.response", format_player_name(player), format_number(#trains, false) }
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set all trains to automatic
|
||||||
|
Commands.new("set-trains-to-automatic", { "exp-commands_trains.description" })
|
||||||
|
:optional("surface", { "exp-commands_trains.arg-surface" }, Commands.types.surface)
|
||||||
|
:optional("force", { "exp-commands_trains.arg-force" }, Commands.types.force)
|
||||||
|
:register(function(player, surface, force)
|
||||||
|
--- @cast surface LuaSurface?
|
||||||
|
--- @cast force LuaForce?
|
||||||
|
module.manual(player, surface, force)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
return module
|
||||||
|
|||||||
@@ -29,19 +29,19 @@ Selection.on_selection(SelectionName, function(event)
|
|||||||
local surface = event.surface
|
local surface = event.surface
|
||||||
|
|
||||||
if surface.planet and surface.planet ~= game.planets.nauvis then
|
if surface.planet and surface.planet ~= game.planets.nauvis then
|
||||||
player.print({ "exp-cods_waterfill.nauvis-only" }, Commands.print_settings.error)
|
player.print({ "exp-commands_waterfill.nauvis-only" }, Commands.print_settings.error)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local area_size = (area.right_bottom.x - area.left_top.x) * (area.right_bottom.y - area.left_top.y)
|
local area_size = (area.right_bottom.x - area.left_top.x) * (area.right_bottom.y - area.left_top.y)
|
||||||
if area_size > 1000 then
|
if area_size > 1000 then
|
||||||
player.print({ "exp-cods_waterfill.area-too-large", 1000, area_size }, Commands.print_settings.error)
|
player.print({ "exp-commands_waterfill.area-too-large", 1000, area_size }, Commands.print_settings.error)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local item_count = player.get_item_count("cliff-explosives")
|
local item_count = player.get_item_count("cliff-explosives")
|
||||||
if item_count < area_size then
|
if item_count < area_size then
|
||||||
player.print({ "exp-cods_waterfill.too-few-explosives", area_size, item_count }, Commands.print_settings.error)
|
player.print({ "exp-commands_waterfill.too-few-explosives", area_size, item_count }, Commands.print_settings.error)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -62,8 +62,8 @@ Selection.on_selection(SelectionName, function(event)
|
|||||||
player.remove_item{ name = "cliff-explosives", count = tile_count - remaining_tiles }
|
player.remove_item{ name = "cliff-explosives", count = tile_count - remaining_tiles }
|
||||||
|
|
||||||
if remaining_tiles > 0 then
|
if remaining_tiles > 0 then
|
||||||
player.print({ "exp-cods_waterfill.part-complete", tile_count, remaining_tiles }, Commands.print_settings.default)
|
player.print({ "exp-commands_waterfill.part-complete", tile_count, remaining_tiles }, Commands.print_settings.default)
|
||||||
else
|
else
|
||||||
player.print({ "exp-cods_waterfill.complete", tile_count }, Commands.print_settings.default)
|
player.print({ "exp-commands_waterfill.complete", tile_count }, Commands.print_settings.default)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|||||||
Reference in New Issue
Block a user