Read ammo slots on join so the first shot is logged

Clearing the slots on leave meant nothing was known about a player's ammo
until it changed, so the first shot after rejoining was missed. The slots
are now read when a player joins and when they respawn, since a new
character starts empty and a stale single round would otherwise count as
a shot. The change handler reads the slots the same way and compares them
with what was stored.
This commit is contained in:
bbassie
2026-09-06 00:45:53 +00:00
parent ce7a6ae1bf
commit 397033e8a6
@@ -148,34 +148,42 @@ Storage.register(ammo_slots, function(tbl)
ammo_slots = tbl ammo_slots = tbl
end) end)
--- Log a shot, there is no fired event so a slot losing one of the same ammo is taken as a shot --- Read the ammo slots of a player, empty while they have no character
--- @param event EventData.on_player_ammo_inventory_changed --- @param player LuaPlayer
local function on_player_ammo_inventory_changed(event) --- @return table<uint, ExpScenario_DeconstructionLog.AmmoSlot>
local player = get_log_player(event) local function read_ammo_slots(player)
if not player or not player.character then return end local slots = {}
if not player.character then return slots end
local slots = ammo_slots[player.index]
if not slots then
slots = {}
ammo_slots[player.index] = slots
end
local character_ammo = assert(player.get_inventory(defines.inventory.character_ammo)) local character_ammo = assert(player.get_inventory(defines.inventory.character_ammo))
for index = 1, #character_ammo do for index = 1, #character_ammo do
local stack = character_ammo[index --[[@as uint]]] local stack = character_ammo[index --[[@as uint]]]
local previous = slots[index]
local fired = nil --- @type string?
if stack.valid_for_read then 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 } slots[index] = { name = stack.name, count = stack.count }
else end
if previous and previous.count == 1 then end
fired = previous.name 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 end
slots[index] = nil elseif previous.count == 1 then
fired = previous.name
end end
if fired and logged_ammo[fired] then if fired and logged_ammo[fired] then
@@ -184,13 +192,19 @@ local function on_player_ammo_inventory_changed(event)
end end
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 --- @param event EventData.on_player_left_game
local function on_player_left_game(event) local function on_player_left_game(event)
ammo_slots[event.player_index] = nil ammo_slots[event.player_index] = nil
end end
local e = defines.events local e = defines.events
local events = { local events = {
[e.on_multiplayer_init] = clear_log, [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 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_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 events[e.on_player_left_game] = on_player_left_game
end end