diff --git a/exp_scenario/module/control/deconstruction_log.lua b/exp_scenario/module/control/deconstruction_log.lua index 7688e5d5..325bb3f8 100644 --- a/exp_scenario/module/control/deconstruction_log.lua +++ b/exp_scenario/module/control/deconstruction_log.lua @@ -148,34 +148,42 @@ Storage.register(ammo_slots, function(tbl) ammo_slots = tbl end) ---- Log a shot, there is no fired event so a slot losing one of the same ammo is taken as a shot ---- @param event EventData.on_player_ammo_inventory_changed -local function on_player_ammo_inventory_changed(event) - local player = get_log_player(event) - if not player or not player.character then return end - - local slots = ammo_slots[player.index] - if not slots then - slots = {} - ammo_slots[player.index] = slots - end +--- Read the ammo slots of a player, empty while they have no character +--- @param player LuaPlayer +--- @return table +local function read_ammo_slots(player) + local slots = {} + if not player.character then return slots end local character_ammo = assert(player.get_inventory(defines.inventory.character_ammo)) for index = 1, #character_ammo do local stack = character_ammo[index --[[@as uint]]] - local previous = slots[index] - local fired = nil --- @type string? - if stack.valid_for_read then - if previous and previous.name == stack.name and previous.count == stack.count + 1 then - fired = stack.name - end slots[index] = { name = stack.name, count = stack.count } - else - if previous and previous.count == 1 then - fired = previous.name + end + end + return slots +end + +--- Log a shot, there is no fired event so a slot losing one of the same ammo is taken as a shot +--- @param event EventData.on_player_ammo_inventory_changed +local function on_player_ammo_inventory_changed(event) + local player = get_log_player(event) + if not player then return end + + local previous_slots = ammo_slots[player.index] or {} + local slots = read_ammo_slots(player) + ammo_slots[player.index] = slots + + for index, previous in pairs(previous_slots) do + local current = slots[index] + local fired = nil --- @type string? + if current then + if previous.name == current.name and previous.count == current.count + 1 then + fired = current.name end - slots[index] = nil + elseif previous.count == 1 then + fired = previous.name end if fired and logged_ammo[fired] then @@ -184,13 +192,19 @@ local function on_player_ammo_inventory_changed(event) end end ---- Forget the ammo of a player who left, their slots are read again on the next change +--- Read the ammo of a player when they join or get a new character, so the first shot afterwards is seen +--- @param event EventData.on_player_joined_game | EventData.on_player_respawned +local function on_player_character_changed(event) + local player = assert(game.get_player(event.player_index)) + ammo_slots[player.index] = read_ammo_slots(player) +end + +--- Forget the ammo of a player who left --- @param event EventData.on_player_left_game local function on_player_left_game(event) ammo_slots[event.player_index] = nil end - local e = defines.events local events = { [e.on_multiplayer_init] = clear_log, @@ -210,6 +224,8 @@ end if config.fired_rocket or config.fired_explosive_rocket or config.fired_nuke then events[e.on_player_ammo_inventory_changed] = on_player_ammo_inventory_changed + events[e.on_player_joined_game] = on_player_character_changed + events[e.on_player_respawned] = on_player_character_changed events[e.on_player_left_game] = on_player_left_game end