mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-11-12 15:54:52 +09:00
The community name, Discord, website, status, GitHub, and Patreon links lived in exp_legacy/config/server_detail.lua, so changing them meant editing the scenario. They are now the community_details feature and can be edited from the Scenario Features page. Chat auto reply, help bubbles, and the readme read the live config instead of copying the values when the file loads, so an edit shows up without a restart. Help bubbles store the location name in their task and build the messages each cycle; the readme tab tooltip can be a function which is called when the readme opens. Every feature gets an enabled switch from the framework. There is no sensible meaning for a disabled community name, so the values are always used and the feature description says the switch does nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
733 lines
26 KiB
Lua
733 lines
26 KiB
Lua
--[[-- Gui Module - Readme
|
|
Adds a main gui that contains important information about the server.
|
|
]]
|
|
|
|
local ExpUtil = require("modules/exp_util")
|
|
local Gui = require("modules/exp_gui")
|
|
local Roles = require("modules/exp_roles")
|
|
local Commands = require("modules/exp_commands")
|
|
local PlayerData = require("modules.exp_legacy.expcore.player_data")
|
|
local ExpServerList = require("modules/exp_server_list")
|
|
local community = require("modules/exp_scenario/config/community_details").config
|
|
|
|
local format_number = require("util").format_number
|
|
local format_time = ExpUtil.format_time_factory_locale{ format = "long", days = true, hours = true, minutes = true }
|
|
|
|
local frame_width = 595
|
|
local title_width = 270
|
|
local scroll_height = 275
|
|
local description_length = 120
|
|
|
|
--- Cut a string to a number of bytes without splitting a utf8 character
|
|
--- @param str string
|
|
--- @param length number
|
|
--- @return string
|
|
local function shorten(str, length)
|
|
if #str <= length then
|
|
return str
|
|
end
|
|
local next_byte = str:byte(length + 1)
|
|
while length > 0 and next_byte >= 0x80 and next_byte < 0xC0 do
|
|
length = length - 1
|
|
next_byte = str:byte(length + 1)
|
|
end
|
|
return str:sub(1, length) .. "..."
|
|
end
|
|
|
|
--- @class ExpGui_Readme.elements
|
|
local Elements = {}
|
|
|
|
--- @type table<number, { caption: LocalisedString, tooltip: LocalisedString | (fun(): LocalisedString), element: ExpElement }>
|
|
local tabs = {}
|
|
|
|
--- Register a readme tab
|
|
--- @param caption LocalisedString
|
|
--- @param tooltip LocalisedString | fun(): LocalisedString Functions are called when the readme opens
|
|
--- @param element ExpElement
|
|
local function define_tab(caption, tooltip, element)
|
|
tabs[#tabs + 1] = { caption = caption, tooltip = tooltip, element = element }
|
|
end
|
|
|
|
--- Create a title section table
|
|
--- @class ExpGui_Readme.elements.title_table: ExpElement
|
|
--- @overload fun(parent: LuaGuiElement, bar_size: number, caption: LocalisedString, column_count: number): LuaGuiElement
|
|
Elements.title_table = Gui.define("readme/title_table")
|
|
:draw(function(_, parent, bar_size, caption, column_count)
|
|
Gui.elements.title_label(parent, bar_size, caption)
|
|
return parent.add{
|
|
type = "table",
|
|
column_count = column_count,
|
|
style = "bordered_table",
|
|
}
|
|
end)
|
|
:style{
|
|
padding = 0,
|
|
cell_padding = 0,
|
|
vertical_align = "center",
|
|
horizontally_stretchable = true,
|
|
} --[[@as any]]
|
|
|
|
--- Scroll pane used for title tables
|
|
--- @class ExpGui_Readme.elements.title_table_scroll: ExpElement
|
|
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
|
|
Elements.title_table_scroll = Gui.define("readme/title_table_scroll")
|
|
:draw{
|
|
type = "scroll-pane",
|
|
direction = "vertical",
|
|
horizontal_scroll_policy = "never",
|
|
vertical_scroll_policy = "auto",
|
|
style = "scroll_pane_under_subheader",
|
|
}
|
|
:style{
|
|
padding = { 1, 3 },
|
|
maximal_height = scroll_height,
|
|
horizontally_stretchable = true,
|
|
} --[[@as any]]
|
|
|
|
--- Sub content frame
|
|
--- @class ExpGui_Readme.elements.sub_content: ExpElement
|
|
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
|
|
Elements.sub_content = Gui.define("readme/sub_content")
|
|
:draw{
|
|
type = "frame",
|
|
direction = "vertical",
|
|
style = "inside_deep_frame",
|
|
}
|
|
:style{
|
|
horizontally_stretchable = true,
|
|
horizontal_align = "center",
|
|
padding = { 2, 2 },
|
|
top_margin = 2,
|
|
} --[[@as any]]
|
|
|
|
--- @class ExpGui_Readme.elements.join_server.elements
|
|
--- @field server_id number
|
|
|
|
--- Join server button
|
|
--- @class ExpGui_Readme.elements.join_server: ExpElement
|
|
--- @field data table<LuaGuiElement, ExpGui_Readme.elements.join_server.elements>
|
|
--- @overload fun(parent: LuaGuiElement, server: ExpServerList.Server): LuaGuiElement
|
|
Elements.join_server = Gui.define("readme/join_server")
|
|
:track_all_elements()
|
|
:draw(function(def, parent, server)
|
|
--- @cast def ExpGui_Readme.elements.join_server
|
|
--- @cast server ExpServerList.Server
|
|
local flow = parent.add{
|
|
type = "flow",
|
|
}
|
|
|
|
local button = flow.add{
|
|
type = "sprite-button",
|
|
sprite = "utility/circuit_network_panel",
|
|
hovered_sprite = "utility/circuit_network_panel",
|
|
style = "frame_action_button",
|
|
}
|
|
|
|
def.data[button] = {
|
|
server_id = server.id,
|
|
}
|
|
|
|
Elements.join_server.refresh(button, server)
|
|
return button
|
|
end)
|
|
:style{
|
|
size = 20,
|
|
padding = -1,
|
|
}
|
|
:on_click(function(def, player, button)
|
|
--- @cast def ExpGui_Readme.elements.join_server
|
|
local server = ExpServerList.get_server(def.data[button].server_id)
|
|
if server and ExpServerList.is_online(server) then
|
|
ExpServerList.request_connection(player, server, true)
|
|
end
|
|
end) --[[@as any]]
|
|
|
|
--- Refresh join server button
|
|
--- @param button LuaGuiElement
|
|
--- @param server ExpServerList.Server?
|
|
function Elements.join_server.refresh(button, server)
|
|
local current = ExpServerList.get_current()
|
|
local status, detail = "Online", nil
|
|
if not server or not ExpServerList.is_online(server) then
|
|
status = "Offline"
|
|
elseif current and server.id == current.id then
|
|
status = "Current"
|
|
elseif current and server.factorio_version ~= current.factorio_version then
|
|
status, detail = "Version", server.factorio_version
|
|
elseif server.has_password then
|
|
status = "Password"
|
|
elseif current and server.mod_pack_name ~= current.mod_pack_name then
|
|
status, detail = "Modded", server.mod_pack_name
|
|
end
|
|
|
|
-- Factorio drops nil parameters, which would shift the player count into __1__
|
|
local player_count = server and server.player_count or 0
|
|
button.tooltip = { "exp-gui_readme.servers-connect-" .. status, detail or "", player_count }
|
|
|
|
if status == "Offline" or status == "Current" then
|
|
button.enabled = false
|
|
button.sprite = "utility/circuit_network_panel"
|
|
button.hovered_sprite = "utility/circuit_network_panel"
|
|
|
|
elseif status == "Version" then
|
|
button.enabled = false
|
|
button.sprite = "utility/shuffle"
|
|
button.hovered_sprite = "utility/shuffle"
|
|
|
|
elseif status == "Password" then
|
|
button.enabled = true
|
|
button.sprite = "utility/warning_white"
|
|
button.hovered_sprite = "utility/warning"
|
|
|
|
elseif status == "Modded" then
|
|
button.enabled = true
|
|
button.sprite = "utility/downloading_white"
|
|
button.hovered_sprite = "utility/downloading"
|
|
|
|
else
|
|
button.enabled = true
|
|
button.sprite = "utility/circuit_network_panel"
|
|
button.hovered_sprite = "utility/circuit_network_panel"
|
|
end
|
|
end
|
|
|
|
--- Refresh all join buttons
|
|
function Elements.join_server.refresh_all()
|
|
for _, button in Elements.join_server:tracked_elements() do
|
|
local server_id = Elements.join_server.data[button].server_id
|
|
Elements.join_server.refresh(button, ExpServerList.get_server(server_id))
|
|
end
|
|
end
|
|
|
|
--- Welcome tab
|
|
define_tab(
|
|
{ "exp-gui_readme.welcome-tab" },
|
|
function() return { "exp-gui_readme.welcome-tooltip", community.community_name } end,
|
|
Gui.define("readme/welcome")
|
|
:draw(function(_, parent)
|
|
local player = Gui.get_player(parent)
|
|
|
|
local server_details = {
|
|
name = community.community_name .. " S0 - Local",
|
|
welcome = "Failed to load description: disconnected from the controller.",
|
|
reset_time = "Not Set",
|
|
}
|
|
|
|
local current = ExpServerList.get_current()
|
|
if current then
|
|
server_details = {
|
|
name = current.name,
|
|
welcome = current.welcome ~= "" and current.welcome or { "exp-gui_readme.welcome-default" },
|
|
reset_time = current.reset_time ~= "" and current.reset_time or "Not Set",
|
|
}
|
|
end
|
|
|
|
local container = parent.add{ type = "flow", direction = "vertical" }
|
|
|
|
local top_flow = container.add{ type = "flow" }
|
|
top_flow.add{ type = "sprite", sprite = "file/modules/exp_scenario/gui/logo.png" }
|
|
|
|
local center_flow = top_flow.add{ type = "flow", direction = "vertical" }
|
|
center_flow.style.horizontal_align = "center"
|
|
|
|
Gui.elements.centered_label(center_flow, 380, { "exp-gui_readme.welcome-title", server_details.name })
|
|
Gui.elements.centered_label(center_flow, 380, server_details.welcome)
|
|
|
|
top_flow.add{ type = "sprite", sprite = "file/modules/exp_scenario/gui/logo.png" }
|
|
|
|
Gui.elements.bar(container)
|
|
container.add{ type = "flow" }.style.height = 4
|
|
|
|
local role_names = {}
|
|
for i, role in ipairs(Roles.sort_roles(Roles.get_player_roles(player))) do
|
|
role_names[i] = role.name
|
|
end
|
|
|
|
Gui.elements.centered_label(
|
|
Elements.sub_content(container),
|
|
frame_width,
|
|
{
|
|
"exp-gui_readme.welcome-general",
|
|
community.community_name,
|
|
format_time(game.tick),
|
|
server_details.reset_time,
|
|
}
|
|
)
|
|
|
|
Gui.elements.centered_label(
|
|
Elements.sub_content(container),
|
|
frame_width,
|
|
{
|
|
"exp-gui_readme.welcome-roles",
|
|
table.concat(role_names, ", "),
|
|
}
|
|
)
|
|
|
|
Gui.elements.centered_label(
|
|
Elements.sub_content(container),
|
|
frame_width,
|
|
{ "exp-gui_readme.welcome-chat" }
|
|
)
|
|
|
|
return container
|
|
end) --[[@as any]]
|
|
)
|
|
|
|
--- Rules tab
|
|
define_tab(
|
|
{ "exp-gui_readme.rules-tab" },
|
|
{ "exp-gui_readme.rules-tooltip" },
|
|
Gui.define("readme/rules")
|
|
:draw(function(_, parent)
|
|
local container = parent.add{ type = "flow", direction = "vertical" }
|
|
Gui.elements.title_label(container, title_width - 3, { "exp-gui_readme.rules-tab" })
|
|
Gui.elements.centered_label(container, frame_width, { "exp-gui_readme.rules-general" })
|
|
Gui.elements.bar(container)
|
|
container.add{ type = "flow" }
|
|
|
|
local rules = Gui.elements.scroll_table(container, scroll_height, 1)
|
|
rules.style = "bordered_table"
|
|
local rules_style = rules.style --[[@as LuaStyle]]
|
|
rules_style.cell_padding = 4
|
|
|
|
for i = 1, 15 do
|
|
Gui.elements.centered_label(rules, frame_width - 30, { "exp-gui_readme.rules-" .. i })
|
|
end
|
|
|
|
return container
|
|
end) --[[@as any]]
|
|
)
|
|
|
|
--- Commands tab
|
|
define_tab(
|
|
{ "exp-gui_readme.commands-tab" },
|
|
{ "exp-gui_readme.commands-tooltip" },
|
|
Gui.define("readme/commands")
|
|
:draw(function(_, parent)
|
|
local player = Gui.get_player(parent)
|
|
|
|
local container = parent.add{ type = "flow", direction = "vertical" }
|
|
Gui.elements.title_label(container, title_width - 20, { "exp-gui_readme.commands-tab" })
|
|
Gui.elements.centered_label(container, frame_width, { "exp-gui_readme.commands-general" })
|
|
Gui.elements.bar(container)
|
|
container.add{ type = "flow" }
|
|
|
|
local commands = Gui.elements.scroll_table(container, scroll_height, 2)
|
|
commands.style = "bordered_table"
|
|
local commands_style = commands.style --[[@as LuaStyle]]
|
|
commands_style.cell_padding = 0
|
|
|
|
for name, command in pairs(Commands.list_for_player(player)) do
|
|
Gui.elements.centered_label(commands, 120, name)
|
|
Gui.elements.centered_label(commands, 450, command.description)
|
|
end
|
|
|
|
return container
|
|
end) --[[@as any]]
|
|
)
|
|
|
|
--- Servers tab
|
|
define_tab(
|
|
{ "exp-gui_readme.servers-tab" },
|
|
{ "exp-gui_readme.servers-tooltip" },
|
|
Gui.define("readme/servers")
|
|
:draw(function(_, parent)
|
|
local container = parent.add{ type = "flow", direction = "vertical" }
|
|
Gui.elements.title_label(container, title_width - 10, { "exp-gui_readme.servers-tab" })
|
|
Gui.elements.centered_label(container, frame_width, { "exp-gui_readme.servers-general" })
|
|
Gui.elements.bar(container)
|
|
container.add{ type = "flow" }
|
|
|
|
local scroll_pane = Elements.title_table_scroll(container)
|
|
scroll_pane.style.maximal_height = scroll_height + 20
|
|
|
|
local factorio_servers = Elements.title_table(scroll_pane, 225, { "exp-gui_readme.servers-factorio" }, 3)
|
|
for _, server in ipairs(ExpServerList.get_servers()) do
|
|
local description = shorten(server.description, description_length)
|
|
local tooltip = description ~= server.description and server.description or nil
|
|
Gui.elements.centered_label(factorio_servers, 110, server.display_name)
|
|
Gui.elements.centered_label(factorio_servers, 436, description, tooltip)
|
|
Elements.join_server(factorio_servers, server)
|
|
end
|
|
|
|
local external_links = Elements.title_table(scroll_pane, 235, { "exp-gui_readme.servers-external" }, 2)
|
|
for _, key in ipairs{ "discord", "website", "patreon", "status", "github" } do
|
|
Gui.elements.centered_label(external_links, 110, key:gsub("^%l", string.upper))
|
|
Gui.elements.centered_label(external_links, 460, community[key], { "exp-gui_readme.servers-open-in-browser" })
|
|
end
|
|
|
|
return container
|
|
end) --[[@as any]]
|
|
)
|
|
|
|
--- Backers tab
|
|
--- Content area for the backers tab
|
|
define_tab(
|
|
{ "exp-gui_readme.backers-tab" },
|
|
{ "exp-gui_readme.backers-tooltip" },
|
|
Gui.define("readme/backers")
|
|
:draw(function(_, parent)
|
|
local container = parent.add{ type = "flow", direction = "vertical" }
|
|
Gui.elements.title_label(container, title_width - 10, { "exp-gui_readme.backers-tab" })
|
|
Gui.elements.centered_label(container, frame_width, { "exp-gui_readme.backers-general" })
|
|
Gui.elements.bar(container)
|
|
container.add{ type = "flow" }
|
|
|
|
local groups = {
|
|
{
|
|
roles = { "Senior Administrator", "Administrator" },
|
|
title = { "exp-gui_readme.backers-management" },
|
|
width = 230,
|
|
players = {}, --- @type string[]
|
|
},
|
|
{
|
|
roles = { "Board Member", "Senior Backer" },
|
|
title = { "exp-gui_readme.backers-board" },
|
|
width = 145,
|
|
players = {}, --- @type string[]
|
|
},
|
|
{
|
|
roles = { "Sponsor", "Supporter" },
|
|
title = { "exp-gui_readme.backers-backers" },
|
|
width = 196,
|
|
players = {}, --- @type string[]
|
|
},
|
|
{
|
|
roles = { "Moderator", "Trainee" },
|
|
title = { "exp-gui_readme.backers-staff" },
|
|
width = 235,
|
|
players = {}, --- @type string[]
|
|
},
|
|
{
|
|
roles = {},
|
|
time = 3 * 3600 * 60,
|
|
title = { "exp-gui_readme.backers-active" },
|
|
width = 235,
|
|
players = {}, --- @type string[]
|
|
},
|
|
}
|
|
|
|
local done = {}
|
|
|
|
-- Fill groups from the players who hold the roles, a player can be in more than one group
|
|
for _, group in ipairs(groups) do
|
|
local seen = {}
|
|
for _, role_name in ipairs(group.roles) do
|
|
local role = Roles.get_role_by_name(role_name)
|
|
for _, player_name in ipairs(role and role:get_player_names() or {}) do
|
|
if not seen[player_name] then
|
|
seen[player_name] = true
|
|
done[player_name] = true
|
|
group.players[#group.players + 1] = player_name
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Fill active player group
|
|
for _, player in pairs(game.players) do
|
|
if not done[player.name] then
|
|
for _, group in ipairs(groups) do
|
|
if group.time and player.online_time > group.time then
|
|
group.players[#group.players + 1] = player.name
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local scroll_pane = Elements.title_table_scroll(container)
|
|
|
|
for _, group in ipairs(groups) do
|
|
if #group.players > 0 then
|
|
local backers_table = Elements.title_table(scroll_pane, group.width, group.title, 4)
|
|
|
|
for _, player_name in ipairs(group.players) do
|
|
Gui.elements.centered_label(backers_table, 140, player_name)
|
|
end
|
|
|
|
if #group.players < 4 then
|
|
for i = 1, 4 - #group.players do
|
|
Gui.elements.centered_label(backers_table, 140)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return container
|
|
end) --[[@as any]]
|
|
)
|
|
|
|
--- @class (exact) ExpGui_Readme.elements.readme_data.param table
|
|
--- @field scroll_pane LuaGuiElement
|
|
--- @field player LuaPlayer
|
|
--- @field player_name string
|
|
--- @field children table
|
|
--- @field title LocalisedString
|
|
--- @field locale_prefix string
|
|
--- @field default_stringify fun(value: any): string
|
|
--- @field columns number
|
|
--- @field title_width number
|
|
--- @field column_width number
|
|
--- @field extra_rows fun(data_table: LuaGuiElement)?
|
|
|
|
--- Render a player data category
|
|
--- @param opts ExpGui_Readme.elements.readme_data.param
|
|
local function render_data_category(opts)
|
|
local data_table = Elements.title_table(opts.scroll_pane, opts.title_width, opts.title, opts.columns)
|
|
|
|
if opts.extra_rows then
|
|
opts.extra_rows(data_table)
|
|
end
|
|
|
|
for name, child in pairs(opts.children) do
|
|
local metadata = child.metadata
|
|
|
|
if not metadata.permission or Roles.player_has_permission(opts.player, metadata.permission) then
|
|
local value = child:get(opts.player_name)
|
|
|
|
if value ~= nil or metadata.show_always then
|
|
if metadata.stringify_short then
|
|
value = metadata.stringify_short(value)
|
|
elseif metadata.stringify then
|
|
value = metadata.stringify(value)
|
|
else
|
|
value = opts.default_stringify(value)
|
|
end
|
|
|
|
local tooltip = metadata.tooltip or { opts.locale_prefix .. name .. "-tooltip" }
|
|
Gui.elements.centered_label(
|
|
data_table, 150,
|
|
metadata.name or { opts.locale_prefix .. name },
|
|
tooltip
|
|
)
|
|
|
|
Gui.elements.centered_label(
|
|
data_table, opts.column_width,
|
|
{ "exp-gui_readme.data-format", value, metadata.unit or "" },
|
|
metadata.value_tooltip or { "?", { opts.locale_prefix .. name .. "-value-tooltip" }, tooltip }
|
|
)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Content area for the player data tab
|
|
define_tab(
|
|
{ "exp-gui_readme.data-tab" },
|
|
{ "exp-gui_readme.data-tooltip" },
|
|
Gui.define("readme/data")
|
|
:draw(function(_, parent)
|
|
local container = parent.add{ type = "flow", direction = "vertical" }
|
|
|
|
local player = Gui.get_player(parent)
|
|
local player_name = player.name
|
|
|
|
local enum = PlayerData.PreferenceEnum
|
|
local preference = PlayerData.DataSavingPreference:get(player_name)
|
|
local preference_meta = PlayerData.DataSavingPreference.metadata
|
|
preference = enum[preference]
|
|
|
|
Gui.elements.title_label(container, title_width, { "exp-gui_readme.data-tab" })
|
|
Gui.elements.centered_label(container, frame_width, { "exp-gui_readme.data-general" })
|
|
Gui.elements.bar(container)
|
|
container.add{ type = "flow" }
|
|
|
|
local scroll_pane = Elements.title_table_scroll(container)
|
|
|
|
render_data_category{
|
|
scroll_pane = scroll_pane,
|
|
player = player,
|
|
player_name = player_name,
|
|
children = PlayerData.Required.children,
|
|
title = { "exp-gui_readme.data-required" },
|
|
locale_prefix = "exp-required.",
|
|
columns = 2,
|
|
title_width = 250,
|
|
column_width = 420,
|
|
default_stringify = tostring,
|
|
extra_rows = function(required)
|
|
Gui.elements.centered_label(required, 150, preference_meta.name, preference_meta.tooltip)
|
|
Gui.elements.centered_label(required, 420, { "expcore-data.preference-" .. enum[preference] }, preference_meta.value_tooltip)
|
|
end,
|
|
}
|
|
|
|
if preference <= enum.Settings then
|
|
render_data_category{
|
|
scroll_pane = scroll_pane,
|
|
player = player,
|
|
player_name = player_name,
|
|
children = PlayerData.Settings.children,
|
|
title = { "exp-gui_readme.data-settings" },
|
|
locale_prefix = "exp-settings.",
|
|
columns = 2,
|
|
title_width = 255,
|
|
column_width = 420,
|
|
default_stringify = function(value)
|
|
return tostring(value or "None set")
|
|
end,
|
|
}
|
|
end
|
|
|
|
if preference <= enum.Statistics then
|
|
render_data_category{
|
|
scroll_pane = scroll_pane,
|
|
player = player,
|
|
player_name = player_name,
|
|
children = PlayerData.Statistics.children,
|
|
title = { "exp-gui_readme.data-statistics" },
|
|
locale_prefix = "exp-statistics.",
|
|
columns = 4,
|
|
title_width = 250,
|
|
column_width = 130,
|
|
default_stringify = function(value)
|
|
return format_number(value or 0, false)
|
|
end,
|
|
}
|
|
end
|
|
|
|
local skip = {
|
|
DataSavingPreference = true,
|
|
Settings = true,
|
|
Statistics = true,
|
|
Required = true,
|
|
}
|
|
|
|
local count = 0
|
|
for _ in pairs(PlayerData.All.children) do
|
|
count = count + 1
|
|
end
|
|
|
|
if preference <= enum.All and count > 4 then
|
|
local misc = {}
|
|
for name, child in pairs(PlayerData.All.children) do
|
|
if not skip[name] then
|
|
misc[name] = child
|
|
end
|
|
end
|
|
|
|
render_data_category{
|
|
scroll_pane = scroll_pane,
|
|
player = player,
|
|
player_name = player_name,
|
|
children = misc,
|
|
title = { "exp-gui_readme.data-misc" },
|
|
locale_prefix = "",
|
|
columns = 2,
|
|
title_width = 232,
|
|
column_width = 420,
|
|
default_stringify = tostring,
|
|
}
|
|
end
|
|
|
|
return container
|
|
end) --[[@as any]]
|
|
)
|
|
|
|
--- @class ExpGui_Readme.elements.container.elements
|
|
--- @field pane LuaGuiElement
|
|
|
|
--- Main readme container
|
|
--- @class ExpGui_Readme.elements.container: ExpElement
|
|
--- @field data table<LuaGuiElement, ExpGui_Readme.elements.container.elements>
|
|
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
|
|
Elements.container = Gui.define("readme/container")
|
|
:track_all_elements()
|
|
:draw(function(def, parent)
|
|
--- @cast def ExpGui_Readme.elements.container
|
|
local container = parent.add{ name = def.name, type = "frame", style = "invisible_frame" }
|
|
|
|
local left_alignment = Gui.elements.aligned_flow(container, { vertical_align = "bottom" })
|
|
left_alignment.style.padding = { 32, 0, 0, 0 }
|
|
|
|
local left_side = left_alignment.add{ type = "frame", style = "character_gui_left_side" }
|
|
left_side.style.vertically_stretchable = true
|
|
left_side.style.padding = 0
|
|
left_side.style.width = 5
|
|
|
|
local pane = container.add{
|
|
name = "pane",
|
|
type = "tabbed-pane",
|
|
style = "frame_tabbed_pane",
|
|
}
|
|
|
|
for _, tab in ipairs(tabs) do
|
|
local tooltip = tab.tooltip
|
|
if type(tooltip) == "function" then
|
|
tooltip = tooltip()
|
|
end
|
|
|
|
local gui_tab = pane.add{
|
|
type = "tab",
|
|
style = "frame_tab",
|
|
caption = tab.caption,
|
|
tooltip = tooltip,
|
|
}
|
|
|
|
pane.add_tab(gui_tab, tab.element(pane))
|
|
end
|
|
|
|
def.data[container] = {
|
|
pane = pane,
|
|
}
|
|
|
|
return container
|
|
end)
|
|
:on_opened(function(def, player)
|
|
Gui.toolbar.set_button_toggled_state(Elements.toggle_button, player, true)
|
|
end)
|
|
:on_closed(function(def, player, element)
|
|
Gui.toolbar.set_button_toggled_state(Elements.toggle_button, player, false)
|
|
Gui.destroy_if_valid(element)
|
|
end)
|
|
|
|
--- Toggle button
|
|
Elements.toggle_button = Gui.toolbar.create_button{
|
|
name = "readme_toggle",
|
|
auto_toggle = true,
|
|
sprite = "virtual-signal/signal-info",
|
|
tooltip = { "exp-gui_readme.main-tooltip" },
|
|
visible = function(player)
|
|
return Roles.player_has_permission(player, "exp_scenario.gui.readme")
|
|
end,
|
|
}
|
|
:on_click(function(_, player)
|
|
local center = player.gui.center
|
|
local readme = center[Elements.container.name]
|
|
|
|
if readme then
|
|
player.opened = nil
|
|
else
|
|
player.opened = Elements.container(center)
|
|
end
|
|
end)
|
|
|
|
--- Open readme for new players
|
|
--- @param event EventData.on_player_created
|
|
local function open_readme(event)
|
|
local player = assert(game.get_player(event.player_index))
|
|
local element = Elements.container(player.gui.center)
|
|
element.pane.selected_tab_index = 1
|
|
player.opened = element
|
|
end
|
|
|
|
--- Clear stale readme
|
|
--- @param event EventData.on_player_joined_game | EventData.on_player_respawned
|
|
local function clear_readme(event)
|
|
local player = game.players[event.player_index]
|
|
if not player.opened then
|
|
Gui.destroy_if_valid(player.gui.center[Elements.container.name])
|
|
end
|
|
end
|
|
|
|
local e = defines.events
|
|
|
|
return {
|
|
elements = Elements,
|
|
events = {
|
|
[e.on_player_created] = open_readme,
|
|
[e.on_player_joined_game] = clear_readme,
|
|
[e.on_player_respawned] = clear_readme,
|
|
[ExpServerList.on_servers_updated] = Elements.join_server.refresh_all,
|
|
},
|
|
}
|