diff --git a/config.lua b/config.lua index 11e0f24d..6f68345a 100644 --- a/config.lua +++ b/config.lua @@ -85,7 +85,19 @@ global.config = { }, -- enables score and tracking thereof score = { - enabled = true + enabled = true, + + -- the global score trackers to show + global_to_show = { + 'satellites-launched', + 'aliens-killed', + 'built-by-players', + 'built-by-robots', + 'trees-cut', + 'rocks-smashed', + 'kills-by-trains', + 'coins-spent' + } }, -- adds a paint brush paint = { diff --git a/features/gui/player_list.lua b/features/gui/player_list.lua index 647f902f..8bfca61c 100644 --- a/features/gui/player_list.lua +++ b/features/gui/player_list.lua @@ -331,7 +331,7 @@ local column_builders = { local player_index = player.index return { count = PlayerStats.get_death_count(player_index), - causes = PlayerStats.get_all_death_counts_by_cause(player_index) + causes = PlayerStats.get_all_death_causes_by_player(player_index) } end, sort = function(a, b) diff --git a/features/gui/score.lua b/features/gui/score.lua index 66ed4230..464968c0 100644 --- a/features/gui/score.lua +++ b/features/gui/score.lua @@ -1,26 +1,80 @@ +local Global = require 'utils.global' local Event = require 'utils.event' -local PlayerStats = require 'features.player_stats' +local Token = require 'utils.token' +local Schedule = require 'utils.task' local Gui = require 'utils.gui' local Color = require 'resources.color_presets' -local Server = require('features.server') - -local concat = table.concat - +local Server = require 'features.server' +local ScoreTracker = require 'utils.score_tracker' +local pairs = pairs +local scores_to_show = global.config.score.global_to_show +local set_timeout_in_ticks = Schedule.set_timeout_in_ticks local main_frame_name = Gui.uid_name() local main_button_name = Gui.uid_name() -local descriptions = { - {disc = 'Satellites launched', icon = '[img=item.satellite]'}, - {disc = 'Biters liberated', icon = '[img=entity.medium-biter]'}, - {disc = 'Buildings by hand', icon = '[img=utility.hand]'}, - {disc = 'Buildings by robots', icon = '[img=item.construction-robot]'}, - {disc = 'Trees chopped', icon = '[img=entity.tree-02]'}, - {disc = 'Rocks smashed', icon = '[img=entity.rock-huge]'}, - {disc = 'Kills by train', icon = '[img=item.locomotive]'}, - {disc = 'Coins spent', icon = '[img=item.coin]'}, +local memory = { + redraw_score_scheduled = false, + player_last_position = {}, + player_death_causes = {} } -local function create_score_gui(event) +Global.register(memory, function(tbl) memory = tbl end) + +---Creates a map of score name => {captain, tooltip} +local function get_global_score_labels() + local metadata = ScoreTracker.get_score_metadata() + local scores = {} + + for index = 1, #scores_to_show do + local score_name = scores_to_show[index] + local score_metadata = metadata[score_name] + if score_metadata then + local icon = score_metadata.icon + local label_text = '' + if icon then + label_text = icon .. ' ' + end + + scores[score_name] = { + caption = label_text .. ScoreTracker.get_for_global(score_name), + tooltip = score_metadata.localised_string + } + end + end + + return scores +end + +local do_redraw_score = Token.register(function() + local players = game.connected_players + local scores = get_global_score_labels() + + for i = 1, #players do + local player = players[i] + local frame = player.gui.top[main_frame_name] + + if frame and frame.valid then + local score_table = frame.score_table + for score_name, textual_display in pairs(scores) do + score_table[score_name].caption = textual_display.caption + end + end + end + + memory.redraw_score_scheduled = false +end) + +local function schedule_redraw_score() + if memory.redraw_score_scheduled then + return + end + + -- throttle redraws + set_timeout_in_ticks(30, do_redraw_score) + memory.redraw_score_scheduled = true +end + +local function player_joined_game(event) local player = game.get_player(event.player_index) if not player then return @@ -38,37 +92,6 @@ local function create_score_gui(event) end end -local function refresh_score() - local players = game.connected_players - local count = game.forces.player.get_item_launched('satellite') - - local satellites_launched = concat {descriptions[1].icon .. ' ', count, ' '} - local biters_liberated = concat {descriptions[2].icon .. ' ', PlayerStats.get_total_biter_kills(), ' '} - local buildings_by_hand = concat {descriptions[3].icon .. ' ', PlayerStats.get_total_player_built_entities(), ' '} - local buildings_by_robot = concat {descriptions[4].icon .. ' ', PlayerStats.get_total_robot_built_entities(), ' '} - local trees_chopped = concat {descriptions[5].icon .. ' ', PlayerStats.get_total_player_trees_mined(), ' '} - local rocks_smashed = concat {descriptions[6].icon .. ' ', PlayerStats.get_total_player_rocks_mined(), ' '} - local kills_by_train = concat {descriptions[7].icon .. ' ', PlayerStats.get_total_train_kills(), ' '} - local coins_spent = concat {descriptions[8].icon .. ' ', PlayerStats.get_total_coins_spent(), ' '} - - for i = 1, #players do - local player = players[i] - local frame = player.gui.top[main_frame_name] - - if frame and frame.valid then - local score_table = frame.score_table - score_table.label_satellites_launched.caption = satellites_launched - score_table.label_biters_killed.caption = biters_liberated - score_table.label_player_built_entities.caption = buildings_by_hand - score_table.label_robot_built_entities.caption = buildings_by_robot - score_table.label_player_mined_trees.caption = trees_chopped - score_table.label_player_mined_stones.caption = rocks_smashed - score_table.label_kills_by_train.caption = kills_by_train - score_table.label_coins_spent.caption = coins_spent - end - end -end - local function score_label_style(label, color) local style = label.style style.font = 'default-bold' @@ -76,105 +99,43 @@ local function score_label_style(label, color) end local function score_show(top) - local count = game.forces.player.get_item_launched('satellite') - + local scores = get_global_score_labels() local frame = top.add {type = 'frame', name = main_frame_name} local score_table = frame.add {type = 'table', name = 'score_table', column_count = 8} local style = score_table.style style.vertical_spacing = 4 style.horizontal_spacing = 16 - local label = - score_table.add { - type = 'label', - name = 'label_satellites_launched', - caption = concat {descriptions[1].icon .. ' ', count, ' '}, - tooltip = descriptions[1].disc - } - score_label_style(label, Color.white) - - label = - score_table.add { - type = 'label', - name = 'label_biters_killed', - caption = concat {descriptions[2].icon .. ' ', PlayerStats.get_total_biter_kills(), ' '}, - tooltip = descriptions[2].disc - } - score_label_style(label, Color.white) - - label = - score_table.add { - type = 'label', - name = 'label_player_built_entities', - caption = concat {descriptions[3].icon .. ' ', PlayerStats.get_total_player_built_entities(), ' '}, - tooltip = descriptions[3].disc - } - score_label_style(label, Color.white) - - label = - score_table.add { - type = 'label', - name = 'label_robot_built_entities', - caption = concat {descriptions[4].icon .. ' ', PlayerStats.get_total_robot_built_entities(), ' '}, - tooltip = descriptions[4].disc - } - score_label_style(label, Color.white) - - label = - score_table.add { - type = 'label', - name = 'label_player_mined_trees', - caption = concat {descriptions[5].icon .. ' ', PlayerStats.get_total_player_trees_mined(), ' '}, - tooltip = descriptions[5].disc - } - score_label_style(label, Color.white) - - label = - score_table.add { - type = 'label', - name = 'label_player_mined_stones', - caption = concat {descriptions[6].icon .. ' ', PlayerStats.get_total_player_rocks_mined(), ' '}, - tooltip = descriptions[6].disc - } - score_label_style(label, Color.white) - - label = - score_table.add { - type = 'label', - name = 'label_kills_by_train', - caption = concat {descriptions[7].icon .. ' ', PlayerStats.get_total_train_kills(), ' '}, - tooltip = descriptions[7].disc - } - score_label_style(label, Color.white) - - label = - score_table.add { - type = 'label', - name = 'label_coins_spent', - caption = concat {descriptions[8].icon .. ' ', PlayerStats.get_total_coins_spent(), ' '}, - tooltip = descriptions[8].disc - } - score_label_style(label, Color.white) + for score_name, textual_display in pairs(scores) do + local label = score_table.add({ + type = 'label', + name = score_name, + caption = textual_display.caption, + tooltip = textual_display.tooltip + }) + score_label_style(label, Color.white) + end end -local function rocket_launched(event) - local entity = event.rocket +local function global_score_changed(event) + local found = false + for index = 1, #scores_to_show do + if scores_to_show[index] then + found = true + end + end - if not entity or not entity.valid or not entity.force == 'player' then + if not found then return end - local inventory = entity.get_inventory(defines.inventory.rocket) - if not inventory or not inventory.valid then + schedule_redraw_score() + + if event.score_name ~= 'satellites-launched' then return end - local count = inventory.get_item_count('satellite') - if count == 0 then - return - end - - count = game.forces.player.get_item_launched('satellite') + local count = ScoreTracker.get_for_global('satellites-launched') if (count < 10) or ((count < 50) and ((count % 5) == 0)) or ((count % 25) == 0) then local message = 'A satellite has been launched! Total count: ' .. count @@ -182,8 +143,6 @@ local function rocket_launched(event) game.print(message) Server.to_discord_bold(message) end - - refresh_score() end Gui.on_click( @@ -204,6 +163,5 @@ Gui.on_click( Gui.allow_player_to_toggle_top_element_visibility(main_button_name) -Event.add(defines.events.on_player_joined_game, create_score_gui) -Event.add(defines.events.on_rocket_launched, rocket_launched) -Event.on_nth_tick(300, refresh_score) +Event.add(defines.events.on_player_joined_game, player_joined_game) +Event.add(ScoreTracker.events.on_global_score_changed, global_score_changed) diff --git a/features/player_stats.lua b/features/player_stats.lua index 0b50b712..3bb768c4 100644 --- a/features/player_stats.lua +++ b/features/player_stats.lua @@ -1,24 +1,43 @@ -local Event = require 'utils.event' local Global = require 'utils.global' +local Event = require 'utils.event' +local ScoreTracker = require 'utils.score_tracker' require 'utils.table' local pairs = pairs local sqrt = math.sqrt +local change_for_global = ScoreTracker.change_for_global +local get_for_global = ScoreTracker.get_for_global +local change_for_player = ScoreTracker.change_for_player +local get_for_player = ScoreTracker.get_for_player -local player_last_position = {} -local player_walk_distances = {} -local player_coin_earned = {} -local player_coin_spent = {} -local player_crafted_items = {} -local player_console_chats = {} -local player_deaths = {} -local total_players = {0} -local total_train_kills = {0} -local total_player_trees_mined = {0} -local total_player_rocks_mined = {0} -local total_robot_built_entities = {0} -local total_player_built_entities = {0} -local total_biter_kills = {0} -local total_coins_spent = {0} +local rocks_smashed_name = 'rocks-smashed' +local trees_cut_down_name = 'trees-cut' +local player_count_name = 'player-count' +local kills_by_trains_name = 'kills-by-trains' +local built_by_robots_name = 'built-by-robots' +local built_by_players_name = 'built-by-players' +local aliens_killed_name = 'aliens-killed' +local coins_spent_name = 'coins-spent' +local coins_earned_name = 'coins-earned' +local player_deaths_name = 'player-deaths' +local player_console_chats_name = 'player-console-chats' +local player_items_crafted_name = 'player-items-crafted' +local player_distance_walked_name = 'player-distance-walked' +local satellites_launched_name = 'satellites-launched' + +ScoreTracker.register(rocks_smashed_name, {'player_stats.rocks_smashed'}, '[img=entity.rock-huge]') +ScoreTracker.register(trees_cut_down_name, {'player_stats.trees_cut_down'}, '[img=entity.tree-02]') +ScoreTracker.register(player_count_name, {'player_stats.player_count'}) +ScoreTracker.register(kills_by_trains_name, {'player_stats.kills_by_trains'}, '[img=item.locomotive]') +ScoreTracker.register(built_by_players_name, {'player_stats.built_by_players'}, '[img=utility.hand]') +ScoreTracker.register(built_by_robots_name, {'player_stats.built_by_robots'}, '[img=item.construction-robot]') +ScoreTracker.register(aliens_killed_name, {'player_stats.aliens_killed'}, '[img=entity.medium-biter]') +ScoreTracker.register(coins_earned_name, {'player_stats.coins_earned'}, '[img=item.coin]') +ScoreTracker.register(coins_spent_name, {'player_stats.coins_spent'}, '[img=item.coin]') +ScoreTracker.register(player_deaths_name, {'player_stats.player_deaths'}) +ScoreTracker.register(player_console_chats_name, {'player_stats.player_console_chats'}) +ScoreTracker.register(player_items_crafted_name, {'player_stats.player_items_crafted'}) +ScoreTracker.register(player_distance_walked_name, {'player_stats.player_distance_walked'}) +ScoreTracker.register(satellites_launched_name, {'player_stats.satellites_launched'}, '[img=item.satellite]') local train_kill_causes = { ['locomotive'] = true, @@ -27,55 +46,25 @@ local train_kill_causes = { ['artillery-wagon'] = true } -Global.register( - { - player_last_position = player_last_position, - player_walk_distances = player_walk_distances, - player_coin_earned = player_coin_earned, - player_coin_spent = player_coin_spent, - player_deaths = player_deaths, - total_players = total_players, - total_train_kills = total_train_kills, - total_player_trees_mined = total_player_trees_mined, - total_player_rocks_mined = total_player_rocks_mined, - player_crafted_items = player_crafted_items, - player_console_chats = player_console_chats, - total_robot_built_entities = total_robot_built_entities, - total_player_built_entities = total_player_built_entities, - total_biter_kills = total_biter_kills, - total_coins_spent = total_coins_spent - }, - function(tbl) - player_last_position = tbl.player_last_position - player_walk_distances = tbl.player_walk_distances - player_coin_earned = tbl.player_coin_earned - player_coin_spent = tbl.player_coin_spent - player_deaths = tbl.player_deaths - total_players = tbl.total_players - total_train_kills = tbl.total_train_kills - total_player_trees_mined = tbl.total_player_trees_mined - total_player_rocks_mined = tbl.total_player_rocks_mined - player_crafted_items = tbl.player_crafted_items - player_console_chats = tbl.player_console_chats - total_robot_built_entities = tbl.total_robot_built_entities - total_player_built_entities = tbl.total_player_built_entities - total_biter_kills = tbl.total_biter_kills - total_coins_spent = tbl.total_coins_spent - end -) +local player_last_position = {} +local player_death_causes = {} + +Global.register({ + player_last_position = player_last_position, + player_death_causes = player_death_causes +}, function(tbl) + player_last_position = tbl.player_last_position + player_death_causes = tbl.player_death_causes +end) + --- When the player first logs on, initialize their stats and pull their former playtime local function player_created(event) local index = event.player_index player_last_position[index] = game.get_player(index).position - player_walk_distances[index] = 0 - player_coin_earned[index] = 0 - player_coin_spent[index] = 0 - player_crafted_items[index] = 0 - player_console_chats[index] = 0 - player_deaths[index] = {causes = {}, count = 0} - total_players[1] = total_players[1] + 1 + player_death_causes[index] = {} + change_for_global(player_count_name, 1) end local function get_cause_name(cause) @@ -90,70 +79,85 @@ local function get_cause_name(cause) return name end end - return 'No cause' + return 'unspecified' end local function player_died(event) local player_index = event.player_index local cause = get_cause_name(event.cause) - local data = player_deaths[player_index] - data.count = data.count + 1 - - local causes = data.causes + local causes = player_death_causes[player_index] local cause_count = causes[cause] or 0 causes[cause] = cause_count + 1 + change_for_player(player_index, player_deaths_name, 1) if train_kill_causes[cause] then - total_train_kills[1] = total_train_kills[1] + 1 + change_for_global(kills_by_trains_name, 1) end end local function picked_up_item(event) local stack = event.item_stack if stack.name == 'coin' then - local player_index = event.player_index - player_coin_earned[player_index] = player_coin_earned[player_index] + stack.count + change_for_player(event.player_index, coins_earned_name, stack.count) end end local function player_mined_item(event) if event.entity.type == 'simple-entity' then -- Cheap check for rock, may have other side effects - total_player_rocks_mined[1] = total_player_rocks_mined[1] + 1 + change_for_global(rocks_smashed_name, 1) return end if event.entity.type == 'tree' then - total_player_trees_mined[1] = total_player_trees_mined[1] + 1 + change_for_global(trees_cut_down_name, 1) end end local function player_crafted_item(event) - local stack = event.item_stack - local player_index = event.player_index - player_crafted_items[player_index] = player_crafted_items[player_index] + stack.count + change_for_player(event.player_index, player_items_crafted_name, event.item_stack.count) end local function player_console_chat(event) local player_index = event.player_index if player_index then - player_console_chats[player_index] = player_console_chats[player_index] + 1 + change_for_player(player_index, player_console_chats_name, 1) end end local function player_built_entity() - total_player_built_entities[1] = total_player_built_entities[1] + 1 + change_for_global(built_by_players_name, 1) end local function robot_built_entity() - total_robot_built_entities[1] = total_robot_built_entities[1] + 1 + change_for_global(built_by_robots_name, 1) end local function biter_kill_counter(event) if event.entity.force.name == 'enemy' then - total_biter_kills[1] = total_biter_kills[1] + 1 + change_for_global(aliens_killed_name, 1) end end +local function rocket_launched(event) + local entity = event.rocket + + if not entity or not entity.valid or not entity.force == 'player' then + return + end + + local inventory = entity.get_inventory(defines.inventory.rocket) + if not inventory or not inventory.valid then + return + end + + local count = inventory.get_item_count('satellite') + if count == 0 then + return + end + + change_for_global(satellites_launched_name, 1) +end + local function tick() for _, p in pairs(game.connected_players) do if (p.afk_time < 30 or p.walking_state.walking) and p.vehicle == nil then @@ -164,8 +168,8 @@ local function tick() local d_x = last_pos.x - pos.x local d_y = last_pos.y - pos.y - player_walk_distances[index] = player_walk_distances[index] + sqrt(d_x * d_x + d_y * d_y) player_last_position[index] = pos + change_for_player(index, player_distance_walked_name, sqrt(d_x * d_x + d_y * d_y)) end end end @@ -180,91 +184,80 @@ Event.add(defines.events.on_console_chat, player_console_chat) Event.add(defines.events.on_built_entity, player_built_entity) Event.add(defines.events.on_robot_built_entity, robot_built_entity) Event.add(defines.events.on_entity_died, biter_kill_counter) +Event.add(defines.events.on_rocket_launched, rocket_launched) Event.on_nth_tick(62, tick) local Public = {} function Public.get_walk_distance(player_index) - return player_walk_distances[player_index] + return get_for_player(player_index, player_distance_walked_name) end function Public.get_coin_earned(player_index) - return player_coin_earned[player_index] -end - -function Public.set_coin_earned(player_index, value) - player_coin_earned[player_index] = value + return get_for_player(player_index, coins_earned_name) end function Public.change_coin_earned(player_index, amount) - player_coin_earned[player_index] = player_coin_earned[player_index] + amount + change_for_player(player_index, coins_earned_name, amount) end function Public.get_coin_spent(player_index) - return player_coin_spent[player_index] -end - -function Public.set_coin_spent(player_index, value) - local old_value = player_coin_spent[player_index] - player_coin_spent[player_index] = value - - local diff = value - old_value - total_coins_spent[1] = total_coins_spent[1] + diff + return get_for_player(player_index, coins_spent_name) end function Public.change_coin_spent(player_index, amount) - player_coin_spent[player_index] = player_coin_spent[player_index] + amount - total_coins_spent[1] = total_coins_spent[1] + amount + change_for_player(player_index, coins_spent_name, amount) + change_for_global(coins_spent_name, amount) end function Public.get_death_count(player_index) - return player_deaths[player_index].count + return get_for_player(player_index, player_deaths_name) end function Public.get_crafted_item(player_index) - return player_crafted_items[player_index] + return get_for_player(player_index, player_items_crafted_name) end function Public.get_console_chat(player_index) - return player_console_chats[player_index] + return get_for_player(player_index, player_console_chats_name) end -- Returns a dictionary of cause_name -> count -function Public.get_all_death_counts_by_cause(player_index) - return player_deaths[player_index].causes or {} +function Public.get_all_death_causes_by_player(player_index) + return player_death_causes[player_index] or {} end function Public.get_total_player_count() - return total_players[1] + return get_for_global(player_count_name) end function Public.get_total_train_kills() - return total_train_kills[1] + return get_for_global(kills_by_trains_name) end function Public.get_total_player_trees_mined() - return total_player_trees_mined[1] + return get_for_global(trees_cut_down_name) end function Public.get_total_player_rocks_mined() - return total_player_rocks_mined[1] + return get_for_global(rocks_smashed_name) end function Public.get_total_robot_built_entities() - return total_robot_built_entities[1] + return get_for_global(built_by_robots_name) end function Public.get_total_player_built_entities() - return total_player_built_entities[1] + return get_for_global(built_by_players_name) end function Public.get_total_biter_kills() - return total_biter_kills[1] + return get_for_global(aliens_killed_name) end function Public.get_total_coins_spent() - return total_coins_spent[1] + return get_for_global(coins_spent_name) end return Public diff --git a/features/redmew_settings_sync.lua b/features/redmew_settings_sync.lua index 6b6a82d2..3b6bd47d 100644 --- a/features/redmew_settings_sync.lua +++ b/features/redmew_settings_sync.lua @@ -26,7 +26,6 @@ Public.events = { on_synced_from_server = Event.generate_event_name('on_synced_from_server'), } - local memory = { -- when already scheduled, no new schedules have to be added sync_scheduled = {}, @@ -35,18 +34,9 @@ local memory = { locked = false, } -local do_sync_settings_to_server -- token - Global.register(memory, function (tbl) memory = tbl end) -local function schedule_sync_to_server(player_index) - set_timeout_in_ticks(1, do_sync_settings_to_server, { - player_index = player_index - }) - memory.sync_scheduled[player_index] = true -end - -do_sync_settings_to_server = Token.register(function(params) +local do_sync_settings_to_server = Token.register(function(params) local player_index = params.player_index; local player = game.get_player(player_index) if not player or not player.valid then @@ -67,6 +57,13 @@ do_sync_settings_to_server = Token.register(function(params) }) end) +local function schedule_sync_to_server(player_index) + set_timeout_in_ticks(1, do_sync_settings_to_server, { + player_index = player_index + }) + memory.sync_scheduled[player_index] = true +end + local function setting_set(event) local player_index = event.player_index if memory.locked or memory.sync_scheduled[player_index] then diff --git a/locale/en/redmew_features.cfg b/locale/en/redmew_features.cfg index b88ffec5..970fdbb9 100644 --- a/locale/en/redmew_features.cfg +++ b/locale/en/redmew_features.cfg @@ -122,3 +122,18 @@ load_bars=Attempting to load bars from server... delete_bars=Saved data has been removed from the server. incompatible_item=Incompatible item found in saved date and will not be loaded: __1__ +[player_stats] +rocks_smashed=Rocks smashed +trees_cut_down=Trees cut down +player_count=Total players +kills_by_trains=Kills by trains +built_by_players=Built by hand +built_by_robots=Built by robots +aliens_killed=Aliens liberated +coins_earned=Coins earned +coins_spent=Coins spent +player_deaths=Player deaths +player_console_chats=Player console chats +player_items_crafted=Player items crafted +player_distance_walked=Distance walked +satellites_launched=satellites launched diff --git a/locale/en/redmew_maps.cfg b/locale/en/redmew_maps.cfg index 3ce6312b..effed9e5 100644 --- a/locale/en/redmew_maps.cfg +++ b/locale/en/redmew_maps.cfg @@ -29,9 +29,6 @@ gui_buff_other=+__1__ __2__ gui_experience_button_tip=Diggy leveling progress gui_close_btn=Close -gui_coin_button_tip=Diggy scoretable -gui_coin_sent=sent __1__ coins into space! The space station is now holding __2__ coins. - toast_new_level=Your team has reached level __1__! cave_collapse=Cave collapsed! @@ -42,6 +39,10 @@ night_time_warning=Placing solar panels underground does not seem\nto have an ef cracking_sound_1=R U N, Y O U F O O L S ! cracking_sound_2=C R A C K +score_cave_collapses=Cave collapses +score_mine_size=Mine size +score_experience_lost=Experience lost + # locale linked to the quadrants scenario [quadrants] on=ON diff --git a/map_gen/maps/diggy/feature/coin_gathering.lua b/map_gen/maps/diggy/feature/coin_gathering.lua index 6b19f771..97796a99 100644 --- a/map_gen/maps/diggy/feature/coin_gathering.lua +++ b/map_gen/maps/diggy/feature/coin_gathering.lua @@ -1,105 +1,20 @@ --[[-- info - Provides the ability to collect coins and send them to space. + Provides the ability to collect coins. ]] -- dependencies local Event = require 'utils.event' -local ScoreTable = require 'map_gen.maps.diggy.score_table' local Debug = require 'map_gen.maps.diggy.debug' local Template = require 'map_gen.maps.diggy.template' local Perlin = require 'map_gen.shared.perlin_noise' local random = math.random local ceil = math.ceil local pairs = pairs -local Gui = require 'utils.gui' -local utils = require 'utils.core' -- this local CoinGathering = {} --- some GUI stuff -local function redraw_table(data) - local list = data.list - Gui.clear(list) - - data.frame.caption = 'Scoretable' - - for name, value in pairs(ScoreTable.all()) do - local table = list.add({type = 'table', column_count = 2}) - - local key = table.add({type = 'label', name = 'Diggy.CoinGathering.Frame.List.Key', caption = name}) - key.style.minimal_width = 175 - - local val = table.add({type = 'label', name = 'Diggy.CoinGathering.Frame.List.Val', caption = utils.comma_value(value)}) - val.style.minimal_width = 225 - end -end - - -local function toggle(event) - local player = event.player - local center = player.gui.left - local frame = center['Diggy.CoinGathering.Frame'] - - if (frame and event.trigger == nil) then - Gui.destroy(frame) - return - elseif (frame) then - local data = Gui.get_data(frame) - redraw_table(data) - return - end - - frame = center.add({name = 'Diggy.CoinGathering.Frame', type = 'frame', direction = 'vertical'}) - - local scroll_pane = frame.add({type = 'scroll-pane'}) - scroll_pane.style.maximal_height = 400 - - frame.add({type = 'button', name = 'Diggy.CoinGathering.Button', caption = 'Close'}) - - local data = { - frame = frame, - list = scroll_pane - } - - redraw_table(data) - - Gui.set_data(frame, data) -end - -local function on_player_created(event) - game.get_player(event.player_index).gui.top.add({ - name = 'Diggy.CoinGathering.Button', - type = 'sprite-button', - sprite = 'item/coin', - tooltip = {'diggy.gui_coin_button_tip'} - }) -end - -Gui.allow_player_to_toggle_top_element_visibility('Diggy.CoinGathering.Button') - -Gui.on_click('Diggy.CoinGathering.Button', toggle) -Gui.on_custom_close('Diggy.CoinGathering.Frame', function (event) - event.element.destroy() -end) - -function CoinGathering.update_gui() - for _, p in pairs(game.connected_players) do - local frame = p.gui.left['Diggy.CoinGathering.Frame'] - - if frame and frame.valid then - local data = {player = p, trigger = 'update_gui'} - toggle(data) - end - end -end - function CoinGathering.register(config) - Event.add(defines.events.on_player_created, on_player_created) - Event.on_nth_tick(61, CoinGathering.update_gui) - - ScoreTable.reset('Coins sent to space') - local seed local noise_variance = config.noise_variance local function get_noise(surface, x, y) @@ -109,14 +24,6 @@ function CoinGathering.register(config) local distance_required = config.minimal_treasure_chest_distance * config.minimal_treasure_chest_distance - Event.add(defines.events.on_rocket_launched, function (event) - local coins = event.rocket.get_inventory(defines.inventory.rocket).get_item_count('coin') - if coins > 0 then - local sum = ScoreTable.add('Coins sent to space', coins) - game.print({'diggy.gui_coin_sent', coins, sum}) - end - end) - local treasure_chest_noise_threshold = config.treasure_chest_noise_threshold Event.add(Template.events.on_void_removed, function (event) local position = event.position diff --git a/map_gen/maps/diggy/feature/diggy_cave_collapse.lua b/map_gen/maps/diggy/feature/diggy_cave_collapse.lua index b6856b05..0c43f301 100644 --- a/map_gen/maps/diggy/feature/diggy_cave_collapse.lua +++ b/map_gen/maps/diggy/feature/diggy_cave_collapse.lua @@ -4,7 +4,7 @@ -- dependencies local Event = require 'utils.event' local Template = require 'map_gen.maps.diggy.template' -local ScoreTable = require 'map_gen.maps.diggy.score_table' +local ScoreTracker = require 'utils.score_tracker' local Debug = require 'map_gen.maps.diggy.debug' local Task = require 'utils.task' local Token = require 'utils.token' @@ -12,13 +12,11 @@ local Global = require 'utils.global' local CreateParticles = require 'features.create_particles' local RS = require 'map_gen.shared.redmew_surface' local table = require 'utils.table' - local random = math.random local floor = math.floor local pairs = pairs local pcall = pcall local is_diggy_rock = Template.is_diggy_rock -local increment_score = ScoreTable.increment local template_insert = Template.insert local raise_event = script.raise_event local set_timeout = Task.set_timeout @@ -27,6 +25,7 @@ local ceiling_crumble = CreateParticles.ceiling_crumble local clear_table = table.clear_table local collapse_rocks = Template.diggy_rocks local collapse_rocks_size = #collapse_rocks +local cave_collapses_name = 'cave-collapses' -- this local DiggyCaveCollapse = {} @@ -173,7 +172,7 @@ local function collapse(args) template_insert(surface, {}, create_collapse_template(positions, surface)) raise_event(DiggyCaveCollapse.events.on_collapse, args) - increment_score('Cave collapse') + ScoreTracker.change_for_global(cave_collapses_name, 1) end local on_collapse_timeout_finished = Token.register(collapse) @@ -336,6 +335,11 @@ end @param global_config Table {@see Diggy.Config}. ]] function DiggyCaveCollapse.register(cfg) + ScoreTracker.register(cave_collapses_name, {'diggy.score_cave_collapses'}, '[img=entity.assembler-wreck]') + + local global_to_show = global.config.score.global_to_show + global_to_show[#global_to_show + 1] = cave_collapses_name + config = cfg support_beam_entities = config.support_beam_entities @@ -361,8 +365,6 @@ function DiggyCaveCollapse.register(cfg) support_beam_entities['refined-hazard-concrete-right'] = nil end - ScoreTable.reset('Cave collapse') - Event.add(DiggyCaveCollapse.events.on_collapse_triggered, on_collapse_triggered) Event.add(defines.events.on_robot_built_entity, on_built_entity) Event.add( diff --git a/map_gen/maps/diggy/feature/diggy_hole.lua b/map_gen/maps/diggy/feature/diggy_hole.lua index 5f9f5719..17d2b9d4 100644 --- a/map_gen/maps/diggy/feature/diggy_hole.lua +++ b/map_gen/maps/diggy/feature/diggy_hole.lua @@ -7,7 +7,7 @@ local Event = require 'utils.event' local Global = require 'utils.global' local Template = require 'map_gen.maps.diggy.template' -local ScoreTable = require 'map_gen.maps.diggy.score_table' +local ScoreTracker = require 'utils.score_tracker' local Command = require 'utils.command' local CreateParticles = require 'features.create_particles' local Ranks = require 'resources.ranks' @@ -17,8 +17,8 @@ local pairs = pairs local is_diggy_rock = Template.is_diggy_rock local destroy_rock = CreateParticles.destroy_rock local mine_rock = CreateParticles.mine_rock -local increment_score = ScoreTable.increment local raise_event = script.raise_event +local mine_size_name = 'mine-size' -- this local DiggyHole = {} @@ -51,8 +51,6 @@ local function update_robot_mining_damage() -- add the new active modifier to the non-buffed modifier robot_mining.damage = old_modifier + robot_mining.active_modifier - - ScoreTable.set('Robot mining damage', robot_mining.damage) end ---Triggers a diggy diggy hole for a given sand-rock-big, rock-big or rock-huge. @@ -152,10 +150,13 @@ end) Registers all event handlers. ]] function DiggyHole.register(cfg) + ScoreTracker.register(mine_size_name, {'diggy.score_mine_size'}, '[img=tile.out-of-map]') + + local global_to_show = global.config.score.global_to_show + global_to_show[#global_to_show + 1] = mine_size_name + config = cfg robot_mining.damage = cfg.robot_initial_mining_damage - ScoreTable.set('Robot mining damage', robot_mining.damage) - ScoreTable.reset('Mine size') Event.add(defines.events.on_entity_died, function (event) local entity = event.entity @@ -239,7 +240,7 @@ function DiggyHole.register(cfg) end) Event.add(Template.events.on_void_removed, function () - increment_score('Mine size') + ScoreTracker.change_for_global(mine_size_name, 1) end) local robot_damage_per_mining_prod_level = cfg.robot_damage_per_mining_prod_level diff --git a/map_gen/maps/diggy/feature/experience.lua b/map_gen/maps/diggy/feature/experience.lua index 4e9bd571..f12d0177 100644 --- a/map_gen/maps/diggy/feature/experience.lua +++ b/map_gen/maps/diggy/feature/experience.lua @@ -4,12 +4,11 @@ local Game = require 'utils.game' local Global = require 'utils.global' local Toast = require 'features.gui.toast' local ForceControl = require 'features.force_control' -local ScoreTable = require 'map_gen.maps.diggy.score_table' +local ScoreTracker = require 'utils.score_tracker' local Retailer = require 'features.retailer' local Gui = require 'utils.gui' local Utils = require 'utils.core' local Color = require 'resources.color_presets' - local floor = math.floor local log = math.log local max = math.max @@ -23,6 +22,7 @@ local get_force_data = ForceControl.get_force_data local set_item = Retailer.set_item local disable_item = Retailer.disable_item local enable_item = Retailer.enable_item +local experience_lost_name = 'experience-lost' -- this local Experience = {} @@ -336,7 +336,7 @@ local function on_player_respawned(event) for _, p in pairs(game.connected_players) do print_player_floating_text_position(p.index, text, lose_xp_color, -1, -0.5) end - ScoreTable.add('Experience lost', exp) + ScoreTracker.change_for_global(experience_lost_name, exp) end local function redraw_title(data) @@ -580,9 +580,12 @@ local function update_gui() end function Experience.register(cfg) - config = cfg + ScoreTracker.register(experience_lost_name, {'diggy.score_experience_lost'}, '[img=recipe.artillery-targeting-remote]') - ScoreTable.reset('Experience lost') + local global_to_show = global.config.score.global_to_show + global_to_show[#global_to_show + 1] = experience_lost_name + + config = cfg --Adds the function on how to calculate level caps (When to level up) local ForceControlBuilder = ForceControl.register(level_up_formula) diff --git a/map_gen/maps/diggy/score_table.lua b/map_gen/maps/diggy/score_table.lua deleted file mode 100644 index 86ea4451..00000000 --- a/map_gen/maps/diggy/score_table.lua +++ /dev/null @@ -1,58 +0,0 @@ --- dependencies -local Global = require 'utils.global' - --- this -local ScoreTable = {} - -local scores = {} - -Global.register({ - scores = scores, -}, function (tbl) - scores = tbl.scores -end) - ----Resets the score 0 for the given name ----@param name string -function ScoreTable.reset(name) - scores[name] = 0 -end - ----Adds score. ----@param name string ----@param value number the sum for the score added by name ----@return number the sum for the score added by the name -function ScoreTable.add(name, value) - local new = (scores[name] or 0) + value - scores[name] = new - return new -end - ----Sets score. ----@param name string ----@param value number the sum for the score added by name -function ScoreTable.set(name, value) - scores[name] = value -end - ----Increments the score by 1 for name. ----@param name string ----@return number the sum for the score incremented by name -function ScoreTable.increment(name) - return ScoreTable.add(name, 1) -end - ----Returns the score for a single key. ----@param name string ----@return number the sum for the score by name -function ScoreTable.get(name) - return scores[name] or 0 -end - ----Returns all scores. ----@return table {[string] = int} -function ScoreTable.all() - return scores -end - -return ScoreTable diff --git a/map_gen/shared/hail_hydra.lua b/map_gen/shared/hail_hydra.lua index d8ef70a1..29481978 100644 --- a/map_gen/shared/hail_hydra.lua +++ b/map_gen/shared/hail_hydra.lua @@ -4,11 +4,11 @@ local CreateParticles = require 'features.create_particles' local Token = require 'utils.token' local Global = require 'utils.global' local table = require 'utils.table' - local random = math.random local floor = math.floor local ceil = math.ceil local pairs = pairs +local type = type local clear_table = table.clear_table local compound = defines.command.compound local logical_or = defines.compound_command.logical_or diff --git a/utils/score_tracker.lua b/utils/score_tracker.lua new file mode 100644 index 00000000..48e2057c --- /dev/null +++ b/utils/score_tracker.lua @@ -0,0 +1,156 @@ +local Global = require 'utils.global' +local Event = require 'utils.event' +local error = error +local format = string.format +local raise_event = script.raise_event + +local score_metadata = {} + +local memory_players = {} +local memory_global = {} + +Global.register({ + memory_players = memory_players, + memory_global = memory_global +}, function (tbl) + memory_players = tbl.memory_players + memory_global = tbl.memory_global +end) + +local Public = {} + +Public.events = { + -- Event { + -- score_name = score_name + -- player_index = player_index + -- } + on_player_score_changed = Event.generate_event_name('on_player_score_changed'), + -- Event { + -- score_name = score_name + -- } + on_global_score_changed = Event.generate_event_name('on_global_score_changed'), +} + +local on_player_score_changed = Public.events.on_player_score_changed +local on_global_score_changed = Public.events.on_global_score_changed + +---Register a specific score. +--- +--- This function must be called in the control stage, i.e. not inside an event. +--- +---@param name string +---@param localisation_string table +---@param icon string +function Public.register(name, localisation_string, icon) + if _LIFECYCLE ~= _STAGE.control then + error(format('You can only register score types in the control stage, i.e. not inside events. Tried setting "%s".', name), 2) + end + + if score_metadata[name] then + error(format('Trying to register score type for "%s" while it has already been registered.', name), 2) + end + + local score = { + name = name, + icon = icon, + localised_string = localisation_string + } + + score_metadata[name] = score + + return score +end + +---Sets a setting to a specific value for a player. +--- +---@param player_index number +---@param score_name string +---@param value number to subtract or add +function Public.change_for_player(player_index, score_name, value) + if value == 0 then + return + end + + local setting = score_metadata[score_name] + if not setting then + if _DEBUG then + error(format('Trying to change score "%s" while it has was never registered.', score_name), 2) + end + return + end + + local player_score = memory_players[player_index] + if not player_score then + player_score = {} + memory_players[player_index] = player_score + end + + player_score[score_name] = (player_score[score_name] or 0) + value + + raise_event(on_player_score_changed, { + score_name = score_name, + player_index = player_index + }) +end + +---Sets a setting to a specific value for a player. +--- +---@param score_name string +---@param value number to subtract or add +function Public.change_for_global(score_name, value) + if value == 0 then + return + end + + local setting = score_metadata[score_name] + if not setting then + if _DEBUG then + error(format('Trying to change score "%s" while it has was never registered.', score_name), 2) + end + return + end + + memory_global[score_name] = (memory_global[score_name] or 0) + value + + raise_event(on_global_score_changed, { + score_name = score_name + }) +end + +---Returns the value for this player of a specific score. +--- +---@param player_index number +---@param score_name string +function Public.get_for_player(player_index, score_name) + local setting = score_metadata[score_name] + if not setting then + return nil + end + + local player_scores = memory_players[player_index] + if not player_scores then + return 0 + end + + return player_scores[score_name] or 0 +end + +---Returns the value of the game score. +--- +---@param score_name string +function Public.get_for_global(score_name) + local setting = score_metadata[score_name] + if not setting then + return 0 + end + + return memory_global[score_name] or 0 +end + +---Returns the full score metadata, note that this is a reference, do not modify +---this data unless you know what you're doing! +function Public.get_score_metadata() + return score_metadata +end + +return Public