--[[-- Gui Module - Bonus @gui Bonus @alias bonus_container ]] 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 config = require("modules.exp_legacy.config.bonus") --- @dep config.bonus local vlayer = require("modules.exp_legacy.modules.control.vlayer") local format_number = require("util").format_number --- @dep util local bonus_container local function bonus_gui_pts_needed(player) local frame = Gui.get_left_element(player, bonus_container) local disp = frame.container['bonus_st_2'].disp.table local total = 0 for k, v in pairs(config.conversion) do total = total + (disp['bonus_display_' .. k .. '_slider'].slider_value / config.player_bonus[v].cost_scale * config.player_bonus[v].cost) end total = total + (disp['bonus_display_personal_battery_recharge_slider'].slider_value / config.player_special_bonus['personal_battery_recharge'].cost_scale * config.player_special_bonus['personal_battery_recharge'].cost) return total end local function apply_bonus(player) if not Roles.player_allowed(player, 'gui/bonus') then for k, v in pairs(config.player_bonus) do player[k] = 0 if v.combined_bonus then for i=1, #v.combined_bonus do player[v.combined_bonus[i]] = 0 end end end return end if not player.character then return end local frame = Gui.get_left_element(player, bonus_container) local disp = frame.container['bonus_st_2'].disp.table for k, v in pairs(config.conversion) do player[v] = disp['bonus_display_' .. k .. '_slider'].slider_value if config.player_bonus[v].combined_bonus then for i=1, #config.player_bonus[v].combined_bonus do player[config.player_bonus[v].combined_bonus[i]] = disp['bonus_display_' .. k .. '_slider'].slider_value end end end end local function apply_periodic_bonus(player) if not Roles.player_allowed(player, 'gui/bonus') then return end if not player.character then return end local frame = Gui.get_left_element(player, bonus_container) local disp = frame.container['bonus_st_2'].disp.table if vlayer.get_statistics()['energy_sustained'] > 0 then local armor = player.get_inventory(defines.inventory.character_armor)[1].grid if armor then local slider = disp['bonus_display_personal_battery_recharge_slider'].slider_value * 100000 * config.player_special_bonus_rate / 6 for i=1, #armor.equipment do if armor.equipment[i].energy < armor.equipment[i].max_energy then local energy_required = math.min(math.floor(armor.equipment[i].max_energy - armor.equipment[i].energy), vlayer.get_statistics()['energy_storage'], slider) armor.equipment[i].energy = armor.equipment[i].energy + energy_required vlayer.energy_changed(- energy_required) slider = slider - energy_required end end end end end --- Control label for the bonus points available -- @element bonus_gui_control_pts_a local bonus_gui_control_pts_a = Gui.element{ type = 'label', name = 'bonus_control_pts_a', caption = {'bonus.control-pts-a'}, style = 'heading_2_label' }:style{ width = config.gui_display_width['half'] } local bonus_gui_control_pts_a_count = Gui.element{ type = 'label', name = 'bonus_control_pts_a_count', caption = config.pts.base, style = 'heading_2_label' }:style{ width = config.gui_display_width['half'] } --- Control label for the bonus points needed -- @element bonus_gui_control_pts_n local bonus_gui_control_pts_n = Gui.element{ type = 'label', name = 'bonus_control_pts_n', caption = {'bonus.control-pts-n'}, style = 'heading_2_label' }:style{ width = config.gui_display_width['half'] } local bonus_gui_control_pts_n_count = Gui.element{ type = 'label', name = 'bonus_control_pts_n_count', caption = '0', style = 'heading_2_label' }:style{ width =config.gui_display_width['half'] } --- Control label for the bonus points remaining -- @element bonus_gui_control_pts_r local bonus_gui_control_pts_r = Gui.element{ type = 'label', name = 'bonus_control_pts_r', caption = {'bonus.control-pts-r'}, style = 'heading_2_label' }:style{ width = config.gui_display_width['half'] } local bonus_gui_control_pts_r_count = Gui.element{ type = 'label', name = 'bonus_control_pts_r_count', caption = '0', style = 'heading_2_label' }:style{ width = config.gui_display_width['half'] } --- A button used for pts calculations -- @element bonus_gui_control_refresh local bonus_gui_control_reset = Gui.element{ type = 'button', name = Gui.unique_static_name, caption = {'bonus.control-reset'} }:style{ width = config.gui_display_width['half'] }:on_click(function(player, element, _) local frame = Gui.get_left_element(player, bonus_container) local disp = frame.container['bonus_st_2'].disp.table for k, v in pairs(config.conversion) do local s = 'bonus_display_' .. k .. '_slider' disp[s].slider_value = config.player_bonus[v].value if config.player_bonus[v].is_percentage then disp[disp[s].tags.counter].caption = format_number(disp[s].slider_value * 100) .. ' %' else disp[disp[s].tags.counter].caption = format_number(disp[s].slider_value) end end local slider = disp['bonus_display_personal_battery_recharge_slider'] slider.slider_value = config.player_special_bonus['personal_battery_recharge'].value disp[slider.tags.counter].caption = format_number(slider.slider_value) local r = bonus_gui_pts_needed(player) element.parent[bonus_gui_control_pts_n_count.name].caption = r element.parent[bonus_gui_control_pts_r_count.name].caption = tonumber(element.parent[bonus_gui_control_pts_a_count.name].caption) - r end) --- A button used for pts apply -- @element bonus_gui_control_apply local bonus_gui_control_apply = Gui.element{ type = 'button', name = Gui.unique_static_name, caption = {'bonus.control-apply'} }:style{ width = config.gui_display_width['half'] }:on_click(function(player, element, _) local n = bonus_gui_pts_needed(player) element.parent[bonus_gui_control_pts_n_count.name].caption = n local r = tonumber(element.parent[bonus_gui_control_pts_a_count.name].caption) - n element.parent[bonus_gui_control_pts_r_count.name].caption = r if r >= 0 then apply_bonus(player) end end) --- A vertical flow containing all the bonus control -- @element bonus_control_set local bonus_control_set = Gui.element(function(_, parent, name) local bonus_set = parent.add{type='flow', direction='vertical', name=name} local disp = Gui.scroll_table(bonus_set, config.gui_display_width['half'] * 2, 2, 'disp') bonus_gui_control_pts_a(disp) bonus_gui_control_pts_a_count(disp) bonus_gui_control_pts_n(disp) bonus_gui_control_pts_n_count(disp) bonus_gui_control_pts_r(disp) bonus_gui_control_pts_r_count(disp) bonus_gui_control_reset(disp) bonus_gui_control_apply(disp) return bonus_set end) --- Display group -- @element bonus_gui_slider local bonus_gui_slider = Gui.element(function(_definition, parent, name, caption, tooltip, bonus) local label = parent.add{ type = 'label', caption = caption, tooltip = tooltip, style = 'heading_2_label' } label.style.width = config.gui_display_width['label'] local value = bonus.value if bonus.is_percentage then value = format_number(value * 100) .. ' %' else value = format_number(value) end local slider = parent.add{ type = 'slider', name = name .. '_slider', value = bonus.value, maximum_value = bonus.max, value_step = bonus.scale, discrete_values = true, style = 'notched_slider', tags = { counter = name .. '_count', is_percentage = bonus.is_percentage } } slider.style.width = config.gui_display_width['slider'] slider.style.horizontally_stretchable = true local count = parent.add{ type = 'label', name = name .. '_count', caption = value, style = 'heading_2_label', } count.style.width = config.gui_display_width['count'] return slider end) :on_value_changed(function(player, element, _event) if element.tags.is_percentage then element.parent[element.tags.counter].caption = format_number(element.slider_value * 100) .. ' %' else element.parent[element.tags.counter].caption = format_number(element.slider_value) end local r = bonus_gui_pts_needed(player) local frame = Gui.get_left_element(player, bonus_container) local disp = frame.container['bonus_st_1'].disp.table disp[bonus_gui_control_pts_n_count.name].caption = r disp[bonus_gui_control_pts_r_count.name].caption = tonumber(disp[bonus_gui_control_pts_a_count.name].caption) - r end) --- A vertical flow containing all the bonus data -- @element bonus_data_set local bonus_data_set = Gui.element(function(_, parent, name) local bonus_set = parent.add{type='flow', direction='vertical', name=name} local disp = Gui.scroll_table(bonus_set, config.gui_display_width['half'] * 2, 3, 'disp') for k, v in pairs(config.conversion) do bonus_gui_slider(disp, 'bonus_display_' .. k, {'bonus.display-' .. k}, {'bonus.display-' .. k .. '-tooltip'}, config.player_bonus[v]) end bonus_gui_slider(disp, 'bonus_display_personal_battery_recharge', {'bonus.display-personal-battery-recharge'}, {'bonus.display-personal-battery-recharge-tooltip'}, config.player_special_bonus['personal_battery_recharge']) return bonus_set end) --- The main container for the bonus gui -- @element bonus_container bonus_container = Gui.element(function(definition, parent) local player = Gui.get_player_from_element(parent) local container = Gui.container(parent, definition.name, config.gui_display_width['half'] * 2) bonus_control_set(container, 'bonus_st_1') bonus_data_set(container, 'bonus_st_2') local frame = Gui.get_left_element(player, bonus_container) local disp = frame.container['bonus_st_1'].disp.table local n = bonus_gui_pts_needed(player) disp[bonus_gui_control_pts_n_count.name].caption = n local r = tonumber(disp[bonus_gui_control_pts_a_count.name].caption) - n disp[bonus_gui_control_pts_r_count.name].caption = r apply_bonus(player) return container.parent end) :static_name(Gui.unique_static_name) :add_to_left_flow() --- Button on the top flow used to toggle the bonus container -- @element toggle_left_element Gui.left_toolbar_button('item/exoskeleton-equipment', {'bonus.main-tooltip'}, bonus_container, function(player) return Roles.player_allowed(player, 'gui/bonus') end) Event.add(defines.events.on_player_created, function(event) if event.player_index ~= 1 then return end for k, v in pairs(config.force_bonus) do game.players[event.player_index].force[k] = v.value end for k, v in pairs(config.surface_bonus) do game.players[event.player_index].surface[k] = v.value end end) Event.add(Roles.events.on_role_assigned, function(event) apply_bonus(game.players[event.player_index]) end) Event.add(Roles.events.on_role_unassigned, function(event) apply_bonus(game.players[event.player_index]) end) --- When a player respawns re-apply bonus Event.add(defines.events.on_player_respawned, function(event) local player = game.players[event.player_index] local frame = Gui.get_left_element(player, bonus_container) local disp = frame.container['bonus_st_1'].disp.table local n = bonus_gui_pts_needed(player) disp[bonus_gui_control_pts_n_count.name].caption = n local r = tonumber(disp[bonus_gui_control_pts_a_count.name].caption) - n disp[bonus_gui_control_pts_r_count.name].caption = r if r >= 0 then apply_bonus(player) end end) --- When a player dies allow them to have instant respawn Event.add(defines.events.on_player_died, function(event) local player = game.players[event.player_index] if Roles.player_has_flag(player, 'instant-respawn') then player.ticks_to_respawn = 120 end end) Event.on_nth_tick(config.player_special_bonus_rate, function(_) for _, player in pairs(game.connected_players) do apply_periodic_bonus(player) end end)