1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-14 10:13:13 +02:00
RedMew/features/gui/info.lua
2019-06-21 10:56:37 +01:00

833 lines
29 KiB
Lua

local Gui = require 'utils.gui'
local Global = require 'utils.global'
local Event = require 'utils.event'
local Donator = require 'features.donator'
local Rank = require 'features.rank_system'
local PlayerRewards = require 'utils.player_rewards'
local Server = require 'features.server'
local Token = require 'utils.token'
local Color = require 'resources.color_presets'
local format = string.format
local config = global.config
local config_mapinfo = config.map_info
local config_prewards = config.player_rewards
local normal_color = Color.white
local focus_color = Color.dark_orange
local unfocus_color = Color.black
local reward_amount = 2
local reward_token = PlayerRewards.get_reward()
local info_tab_flags = {
0x1, -- welcome
0x2, -- rules
0x4, -- map_info
0x8, -- scenario_mods
0x10 -- whats_new
}
local flags_sum = 0
for _, v in pairs(info_tab_flags) do
flags_sum = flags_sum + v
end
local map_name_key = 1
local map_description_key = 2
local map_extra_info_key = 3
local new_info_key = 4
local rewarded_players = {}
local primitives = {
map_extra_info_lock = nil,
info_edited = nil
}
local editable_info = {
[map_name_key] = config_mapinfo.map_name_key,
[map_description_key] = config_mapinfo.map_description_key,
[map_extra_info_key] = config_mapinfo.map_extra_info_key,
[new_info_key] = config_mapinfo.new_info_key
}
Global.register(
{
rewarded_players = rewarded_players,
editable_info = editable_info,
primitives = primitives
},
function(tbl)
rewarded_players = tbl.rewarded_players
editable_info = tbl.editable_info
primitives = tbl.primitives
end
)
--- Sets the "new info" according to the changelog located on the server
local function process_changelog(data)
local key = data.key
if key ~= 'changelog' then
return
end
local value = data.value -- will be nil if no data
if value then
editable_info[new_info_key] = value
end
end
local changelog_callback = Token.register(process_changelog)
--- Uploads the contents of new info tab to the server.
-- Is triggered on closing the info window by clicking the close button or by pressing escape.
local function upload_changelog(player)
if not player or not player.valid or not player.admin then
return
end
if editable_info[new_info_key] ~= config_mapinfo.new_info_key and primitives.info_edited then
Server.set_data('misc', 'changelog', editable_info[new_info_key])
primitives.info_edited = nil
end
end
--- Tries to download the latest changelog
local function download_changelog()
Server.try_get_data('misc', 'changelog', changelog_callback)
end
local function prepare_title()
local welcome_title =
[[
111111 1111111 111111 111 111 1111111 11 11
11 11 11 11 11 1111 1111 11 11 11
111111 11111 11 11 11 1111 11 11111 11 1 11
11 11 11 11 11 11 11 11 11 11 111 11
11 11 1111111 111111 11 11 1111111 111 111
]]
local row = {}
local welcome_title2 = {row}
local row_index = 1
local column_index = 1
local max = 0
for i = 1, #welcome_title do
local char = welcome_title:sub(i, i)
if char == '\n' then
row_index = row_index + 1
row = {}
welcome_title2[row_index] = row
max = math.max(max, column_index - 1)
column_index = 1
elseif char == '1' then
row[column_index] = true
column_index = column_index + 1
elseif char == ' ' then
row[column_index] = false
column_index = column_index + 1
end
end
return welcome_title2, max
end
local title, title_max = prepare_title()
local main_button_name = Gui.uid_name()
local main_frame_name = Gui.uid_name()
local tab_button_name = Gui.uid_name()
local editable_textbox_name = Gui.uid_name()
local function line_bar(parent)
local bar = parent.add {type = 'progressbar', value = 1}
local style = bar.style
style.color = normal_color
style.horizontally_stretchable = true
end
local function centered_label(parent, string)
local flow = parent.add {type = 'flow'}
local flow_style = flow.style
flow_style.horizontal_align = 'center'
flow_style.horizontally_stretchable = true
local label = flow.add {type = 'label', caption = string}
local label_style = label.style
label_style.horizontal_align = 'center'
label_style.single_line = false
return label
end
local function header_label(parent, string)
local flow = parent.add {type = 'flow'}
local flow_style = flow.style
flow_style.horizontal_align = 'center'
flow_style.horizontally_stretchable = true
local label = flow.add {type = 'label', caption = string}
local label_style = label.style
label_style.horizontal_align = 'center'
label_style.single_line = false
label_style.font = 'default-dialog-button'
return label
end
local pages = {
{
tab_button = function(parent)
local button = parent.add {type = 'button', name = tab_button_name, caption = 'Welcome'}
return button
end,
content = function(parent)
local parent_style = parent.style
parent_style.right_padding = 0
parent_style.left_padding = 0
parent_style.top_padding = 1
parent =
parent.add {
type = 'scroll-pane',
vertical_scroll_policy = 'auto-and-reserve-space',
horizontal_scroll_policy = 'never'
}
parent_style = parent.style
parent_style.vertically_stretchable = false
header_label(parent, {'info.welcome_header'})
centered_label(parent, {'info.welcome_text'})
header_label(parent, {'info.chatting_header'})
centered_label(
parent,
{'info.chatting_text', {'gui-menu.settings'}, {'gui-menu.controls'}, {'controls.toggle-console'}}
)
if config_prewards.enabled and config_prewards.info_player_reward then
header_label(parent, {'info.free_coin_header'})
centered_label(
parent,
{'info.free_coin_text', reward_amount, reward_token, reward_amount, reward_token}
)
end
header_label(parent, {'info.links_header'})
centered_label(parent, {'info.links_discord'})
local discord_textbox_flow = parent.add {type = 'flow'}
local discord_textbox_flow_style = discord_textbox_flow.style
discord_textbox_flow_style.horizontal_align = 'center'
discord_textbox_flow_style.horizontally_stretchable = true
discord_textbox_flow.add({type = 'label', caption = 'Discord: '}).style.font = 'default-bold'
local discord_textbox =
discord_textbox_flow.add {type = 'text-box', text = 'https://www.redmew.com/discord '}
discord_textbox.read_only = true
discord_textbox.style.width = 235
discord_textbox.style.height = 28
centered_label(parent, {'info.links_patreon'})
local patreon_flow = parent.add {type = 'flow', direction = 'horizontal'}
local patreon_flow_style = patreon_flow.style
patreon_flow_style.horizontal_align = 'center'
patreon_flow_style.horizontally_stretchable = true
patreon_flow.add({type = 'label', caption = 'Patreon:'}).style.font = 'default-bold'
local patreon_textbox = patreon_flow.add {type = 'text-box', text = 'https://www.patreon.com/redmew '}
patreon_textbox.read_only = true
patreon_textbox.style.width = 235
patreon_textbox.style.height = 28
centered_label(parent, {'info.links_saves'})
local save_textbox_flow = parent.add {type = 'flow'}
local save_textbox_flow_style = save_textbox_flow.style
save_textbox_flow_style.horizontal_align = 'center'
save_textbox_flow_style.horizontally_stretchable = true
save_textbox_flow.add({type = 'label', caption = 'Saves: '}).style.font = 'default-bold'
local save_textbox = save_textbox_flow.add {type = 'text-box', text = 'http://www.redmew.com/saves/ '}
save_textbox.read_only = true
save_textbox.style.width = 235
save_textbox.style.height = 28
centered_label(parent, {'info.links_factoriomaps'})
local maps_textbox_flow = parent.add {type = 'flow'}
local maps_textbox_flow_style = maps_textbox_flow.style
maps_textbox_flow_style.horizontal_align = 'center'
maps_textbox_flow_style.horizontally_stretchable = true
maps_textbox_flow.add({type = 'label', caption = 'Maps: '}).style.font = 'default-bold'
local maps_textbox =
maps_textbox_flow.add {type = 'text-box', text = 'https://factoriomaps.com/browse/redmew.html '}
maps_textbox.read_only = true
maps_textbox.style.width = 315
maps_textbox.style.height = 28
parent.add({type = 'flow'}).style.height = 24
end
},
{
tab_button = function(parent)
local button = parent.add {type = 'button', name = tab_button_name, caption = 'Rules'}
return button
end,
content = function(parent)
local parent_style = parent.style
parent_style.right_padding = 0
parent_style.left_padding = 0
parent_style.top_padding = 1
parent =
parent.add {
type = 'flow',
direction = 'vertical'
}
parent_style = parent.style
parent_style.vertically_stretchable = false
parent_style.width = 600
header_label(parent, {'info.rules_header'})
centered_label(parent, {'info.rules_text'})
end
},
{
tab_button = function(parent)
local button = parent.add {type = 'button', name = tab_button_name, caption = {'info.map_info_button'}}
return button
end,
content = function(parent, player)
local read_only = not player.admin
local text_width = 490
local top_flow = parent.add {type = 'flow'}
local top_flow_style = top_flow.style
top_flow_style.horizontal_align = 'center'
top_flow_style.horizontally_stretchable = true
local top_label = top_flow.add {type = 'label', caption = {'info.map_info_header'}}
local top_label_style = top_label.style
top_label_style.font = 'default-dialog-button'
local grid = parent.add {type = 'table', column_count = 2}
local grid_style = grid.style
grid_style.horizontally_stretchable = true
grid.add {type = 'label', caption = {'info.map_name_label'}}
local map_name_textbox =
grid.add({type = 'flow'}).add {
type = 'text-box',
name = editable_textbox_name,
text = editable_info[map_name_key]
}
map_name_textbox.read_only = read_only
--map_name_textbox.word_wrap = true
local map_name_textbox_style = map_name_textbox.style
map_name_textbox_style.width = text_width
map_name_textbox_style.maximal_height = 30
Gui.set_data(map_name_textbox, map_name_key)
grid.add {type = 'label', caption = {'info.map_desc_label'}}
local map_description_textbox =
grid.add({type = 'flow'}).add {
type = 'text-box',
name = editable_textbox_name,
text = editable_info[map_description_key]
}
map_description_textbox.read_only = read_only
--map_description_textbox.word_wrap = true
local map_description_textbox_style = map_description_textbox.style
map_description_textbox_style.width = text_width
map_description_textbox_style.minimal_height = 80
map_description_textbox_style.vertically_stretchable = true
map_description_textbox_style.maximal_height = 100
Gui.set_data(map_description_textbox, map_description_key)
grid.add {type = 'label', caption = {'info.map_extra_info_label'}}
local map_extra_info_textbox =
grid.add({type = 'flow'}).add {
type = 'text-box',
name = editable_textbox_name,
text = editable_info[map_extra_info_key]
}
map_extra_info_textbox.read_only = read_only
--map_extra_info_textbox.word_wrap = true
local map_extra_info_textbox_style = map_extra_info_textbox.style
map_extra_info_textbox_style.width = text_width
map_extra_info_textbox_style.height = 210
Gui.set_data(map_extra_info_textbox, map_extra_info_key)
end
},
{
tab_button = function(parent)
local button = parent.add {type = 'button', name = tab_button_name, caption = {'info.softmods_button'}}
return button
end,
content = function(parent, player)
local parent_style = parent.style
parent_style.right_padding = 0
parent_style.left_padding = 0
parent_style.top_padding = 1
parent =
parent.add {
type = 'scroll-pane',
vertical_scroll_policy = 'auto-and-reserve-space',
horizontal_scroll_policy = 'never'
}
parent_style = parent.style
parent_style.vertically_stretchable = true
header_label(parent, {'info.softmods_header'})
local grid = parent.add {type = 'table', column_count = 3}
local grid_style = grid.style
grid_style.vertical_spacing = 24
grid_style.horizontal_spacing = 8
grid_style.top_padding = 8
grid_style.bottom_padding = 16
grid.add {type = 'label'}
local ranks = grid.add {type = 'label', caption = 'Ranks'}
ranks.style.font = 'default-listbox'
local ranks_flow = grid.add {type = 'flow', direction = 'vertical'}
local ranks_label =
ranks_flow.add {
type = 'label',
caption = {'info.softmods_rank_text'}
}
local ranks_label_style = ranks_label.style
ranks_label_style.single_line = false
local player_rank_flow = ranks_flow.add {type = 'flow', direction = 'horizontal'}
player_rank_flow.add {type = 'label', caption = {'info.softmods_rank_is'}}
local player_name = player.name
local rank_label = player_rank_flow.add {type = 'label', caption = Rank.get_player_rank_name(player_name)}
rank_label.style.font_color = Rank.get_player_rank_color(player_name)
if Donator.is_donator(player_name) then
local donator_label = player_rank_flow.add {type = 'label', caption = {'ranks.donator'}}
donator_label.style.font_color = Color.donator
end
grid.add {type = 'sprite', sprite = 'entity/market'}
local market = grid.add {type = 'label', caption = {'info.softmods_market_label'}}
market.style.font = 'default-listbox'
local market_label =
grid.add {
type = 'label',
caption = {'info.softmods_market_text'}
}
market_label.style.single_line = false
grid.add {type = 'sprite', sprite = 'item/small-plane'}
local train_savior = grid.add {type = 'label', caption = {'info.softmods_saviour_label'}}
local train_savior_style = train_savior.style
train_savior_style.font = 'default-listbox'
train_savior_style.single_line = false
local train_savior_label =
grid.add {
type = 'label',
caption = {'info.softmods_saviour_text'}
}
train_savior_label.style.single_line = false
if config.player_list.enabled then
grid.add {type = 'sprite', sprite = 'entity/character'}
local player_list = grid.add {type = 'label', caption = {'info.softmods_plist_label'}}
player_list.style.font = 'default-listbox'
player_list.style.single_line = false
local player_list_label =
grid.add {
type = 'label',
caption = {'info.softmods_plist_text'}
}
player_list_label.style.single_line = false
end
if config.poll.enabled then
grid.add {type = 'sprite', sprite = 'item/programmable-speaker'}
local poll = grid.add {type = 'label', caption = {'info.softmods_polls_label'}}
poll.style.font = 'default-listbox'
local poll_label =
grid.add {
type = 'label',
caption = {'info.softmods_polls_text'}
}
poll_label.style.single_line = false
end
if config.tag_group.enabled then
local tag_button = grid.add {type = 'label', caption = 'tag'}
local tag_button_style = tag_button.style
tag_button_style.font = 'default-listbox'
tag_button_style.font_color = Color.black
local tag = grid.add {type = 'label', caption = {'info.softmods_tags_label'}}
tag.style.font = 'default-listbox'
local tag_label =
grid.add {
type = 'label',
caption = {'info.softmods_tags_text'}
}
tag_label.style.single_line = false
end
if config.tasklist.enabled then
grid.add {type = 'sprite', sprite = 'item/repair-pack'}
local task = grid.add {type = 'label', caption = {'info.softmods_tasks_label'}}
task.style.font = 'default-listbox'
local task_label =
grid.add {
type = 'label',
caption = {'info.softmods_tasks_text'}
}
task_label.style.single_line = false
end
if config.blueprint_helper.enabled then
grid.add {type = 'sprite', sprite = 'item/blueprint'}
local blueprint = grid.add {type = 'label', caption = {'info.softmods_bp_label'}}
local blueprint_style = blueprint.style
blueprint_style.font = 'default-listbox'
blueprint_style.single_line = false
blueprint_style.width = 55
local blueprint_label =
grid.add {
type = 'label',
caption = {'info.softmods_bp_text'}
}
blueprint_label.style.single_line = false
end
if config.score.enabled then
grid.add {type = 'sprite', sprite = 'item/rocket-silo'}
local score = grid.add {type = 'label', caption = {'info.softmods_score_label'}}
score.style.font = 'default-listbox'
local score_label =
grid.add {
type = 'label',
caption = {'info.softmods_score_text'}
}
score_label.style.single_line = false
end
end
},
{
tab_button = function(parent)
local button = parent.add {type = 'button', name = tab_button_name, caption = {'info.whats_new_button'}}
return button
end,
content = function(parent, player)
local read_only = not player.admin
header_label(parent, 'New Features')
local new_info_flow = parent.add {name = 'whatsNew_new_info_flow', type = 'flow'}
new_info_flow.style.horizontal_align = 'center'
local new_info_textbox =
new_info_flow.add {
type = 'text-box',
name = editable_textbox_name,
text = editable_info[new_info_key]
}
new_info_textbox.read_only = read_only
local new_info_textbox_style = new_info_textbox.style
new_info_textbox_style.width = 600
new_info_textbox_style.height = 360
new_info_textbox_style.left_margin = 2
Gui.set_data(new_info_textbox, new_info_key)
end
}
}
local function draw_main_frame(center, player)
local frame = center.add {type = 'frame', name = main_frame_name, direction = 'vertical'}
local frame_style = frame.style
frame_style.height = 600
frame_style.width = 650
frame_style.left_padding = 16
frame_style.right_padding = 16
frame_style.top_padding = 16
local top_flow = frame.add {type = 'flow'}
local top_flow_style = top_flow.style
top_flow_style.horizontal_align = 'center'
top_flow_style.top_padding = 8
top_flow_style.horizontally_stretchable = true
local title_grid = top_flow.add {type = 'table', column_count = title_max}
for _, row in ipairs(title) do
for _, char in ipairs(row) do
local ele
if char then
ele = title_grid.add {type = 'sprite', sprite = 'virtual-signal/signal-red'}
ele.style.stretch_image_to_widget_size = true
else
ele = title_grid.add {type = 'label', caption = ' '}
end
local ele_style = ele.style
ele_style.height = 10
ele_style.width = 10
end
end
local title_grid_style = title_grid.style
title_grid_style.vertical_spacing = 0
title_grid_style.horizontal_spacing = 0
title_grid_style.bottom_padding = 8
line_bar(frame)
local tab_buttons = {}
local active_tab = 1
local data = {
tab_buttons = tab_buttons,
active_tab = active_tab
}
local tab_flow = frame.add {type = 'flow', direction = 'horizontal'}
local tab_flow_style = tab_flow.style
tab_flow_style.horizontal_align = 'center'
tab_flow_style.horizontally_stretchable = true
for index, page in ipairs(pages) do
local button_flow = tab_flow.add {type = 'flow'}
local button = page.tab_button(button_flow, player)
local button_style = button.style
button_style.left_padding = 3
button_style.right_padding = 3
Gui.set_data(button, {index = index, data = data})
tab_buttons[index] = button
end
tab_buttons[active_tab].style.font_color = focus_color
line_bar(frame)
local content = frame.add {type = 'frame', direction = 'vertical', style = 'image_frame'}
local content_style = content.style
content_style.horizontally_stretchable = true
content_style.vertically_stretchable = true
content_style.left_padding = 8
content_style.right_padding = 8
content_style.top_padding = 4
pages[active_tab].content(content, player)
data.content = content
local bottom_flow = frame.add {type = 'flow'}
local bottom_flow_style = bottom_flow.style
bottom_flow_style.horizontal_align = 'center'
bottom_flow_style.top_padding = 8
bottom_flow_style.horizontally_stretchable = true
bottom_flow.add {type = 'button', name = main_button_name, caption = {'common.close_button'}}
player.opened = frame
end
local function close_main_frame(frame, player)
upload_changelog(player)
Gui.destroy(frame)
player.gui.top[main_button_name].style = 'icon_button'
end
local function reward_player(player, index, message)
if not config_prewards.enabled or not config_prewards.info_player_reward then
return
end
local player_index = player.index
if not rewarded_players[player_index] then
error('Player with no entry in rewarded_players table')
return false
end
local tab_flag = info_tab_flags[index]
if bit32.band(rewarded_players[player_index], tab_flag) == tab_flag then
return
else
PlayerRewards.give_reward(player, reward_amount, message)
rewarded_players[player_index] = rewarded_players[player_index] + tab_flag
if rewarded_players[player_index] == flags_sum then
rewarded_players[player_index] = nil
end
end
end
local function toggle(event)
local player = event.player
local gui = player.gui
local center = gui.center
local main_frame = center[main_frame_name]
local main_button = gui.top[main_button_name]
if main_frame then
close_main_frame(main_frame, player)
else
main_button.style = 'selected_slot_button'
local style = main_button.style
style.width = 38
style.height = 38
draw_main_frame(center, player)
end
end
local function player_created(event)
local player = game.get_player(event.player_index)
if not player or not player.valid then
return
end
local gui = player.gui
gui.top.add(
{
type = 'sprite-button',
name = main_button_name,
sprite = 'virtual-signal/signal-info',
tooltip = {'info.tooltip'}
}
)
rewarded_players[player.index] = 0
reward_player(player, info_tab_flags[1])
end
--- Sets editable_info[map_extra_info_key] outright or adds info to it.
-- Forbids map_extra_info being explicitly set twice
local function create_map_extra_info(value, set)
if primitives.map_extra_info_lock and set then
error('Cannot set extra info twice, use add instead')
return
elseif primitives.map_extra_info_lock then
return
elseif set then
editable_info[map_extra_info_key] = value
primitives.map_extra_info_lock = true
elseif editable_info[map_extra_info_key] == config_mapinfo.map_extra_info_key then
editable_info[map_extra_info_key] = value
else
editable_info[map_extra_info_key] = format('%s\n%s', editable_info[map_extra_info_key], value)
end
end
Event.add(defines.events.on_player_created, player_created)
Event.add(Server.events.on_server_started, download_changelog)
Server.on_data_set_changed('misc', process_changelog)
Gui.on_click(main_button_name, toggle)
Gui.on_click(
tab_button_name,
function(event)
local button = event.element
local player = event.player
local button_data = Gui.get_data(button)
local index = button_data.index
local data = button_data.data
local active_tab = data.active_tab
if active_tab == index then
return
end
local tab_buttons = data.tab_buttons
local old_button = tab_buttons[active_tab]
old_button.style.font_color = unfocus_color
button.style.font_color = focus_color
data.active_tab = index
local content = data.content
Gui.clear(content)
pages[index].content(content, player)
if rewarded_players[player.index] then
reward_player(player, index, {'info.free_coin_print', reward_amount, reward_token})
end
end
)
Gui.on_text_changed(
editable_textbox_name,
function(event)
local textbox = event.element
local key = Gui.get_data(textbox)
editable_info[key] = textbox.text
primitives.info_edited = true
end
)
Gui.on_custom_close(
main_frame_name,
function(event)
close_main_frame(event.element, event.player)
end
)
Gui.allow_player_to_toggle_top_element_visibility(main_button_name)
local Public = {}
function Public.show_info(player)
toggle({player = player})
end
function Public.get_map_name()
return editable_info[map_name_key]
end
function Public.set_map_name(value)
editable_info[map_name_key] = value
end
function Public.get_map_description()
return editable_info[map_description_key]
end
function Public.set_map_description(value)
editable_info[map_description_key] = value
end
function Public.get_map_extra_info()
return editable_info[map_extra_info_key]
end
--- Adds to existing map_extra_info. Removes default text if it is the only text in place.
function Public.add_map_extra_info(value)
create_map_extra_info(value, false)
end
--- Overrides all info added via add_map_extra_info.
-- This should only be used in maps, never in features/modules.
-- Use case: for maps that know exactly what features they're using and
-- want full control over the info presented.
function Public.set_map_extra_info(value)
create_map_extra_info(value, true)
end
function Public.get_new_info()
return editable_info[new_info_key]
end
function Public.set_new_info(value)
editable_info[new_info_key] = value
end
return Public