From 37eff4b3e93a51a1dce9249fe4ce87ae11713ade Mon Sep 17 00:00:00 2001 From: bbassie <17990055+bbassie@users.noreply.github.com> Date: Sat, 5 Sep 2026 20:53:56 +0000 Subject: [PATCH] Count kills and damage dealt from vehicles The statistics only credited damage and kills when the cause was a character, so anything done from a car, tank, spidertron or locomotive was lost. The cause is now resolved to a player through the vehicle's driver, or passenger when there is no driver, and turrets, remotes and uncrewed trains still count for nobody. Fixes #219 --- exp_legacy/module/modules/data/statistics.lua | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/exp_legacy/module/modules/data/statistics.lua b/exp_legacy/module/modules/data/statistics.lua index 08bcb7d5..ac844387 100644 --- a/exp_legacy/module/modules/data/statistics.lua +++ b/exp_legacy/module/modules/data/statistics.lua @@ -113,16 +113,47 @@ if config.MachinesRemoved or config.TreesDestroyed or config.OreMined then Event.add(defines.events.on_player_mined_entity, on_event) end +--- Vehicles which credit their driver, or failing that their passenger, with what they hit +local crewed_vehicles = { car = true, ["spider-vehicle"] = true, locomotive = true } + +--- Get the connected player behind the cause of damage or a death, nil for turrets, trains without a crew and the like +--- @param cause LuaEntity? +--- @return LuaPlayer? +local function get_cause_player(cause) + if not cause or not cause.valid then return nil end + + local occupant = cause --- @type LuaEntity | LuaPlayer + if crewed_vehicles[cause.type] then + local crew = cause.get_driver() or cause.get_passenger() + if not crew then return nil end + occupant = crew + end + + local player --- @type LuaPlayer? + if occupant.object_name == "LuaPlayer" then + player = occupant --[[@as LuaPlayer]] + elseif occupant.type == "character" then + player = occupant.player + end + + if not player or not player.valid or not player.connected then return nil end + return player +end + +--- Check that damage or a death counts against an entity, it must be hostile to the player +--- @param entity LuaEntity +--- @param player LuaPlayer +--- @return boolean +local function is_hostile(entity, player) + return entity.valid and entity.force ~= player.force and entity.force.name ~= "neutral" +end + --- Add DamageDealt if it is enabled if config.DamageDealt then local stat = Statistics:combine("DamageDealt") Event.add(defines.events.on_entity_damaged, function(event) - local character = event.cause -- Check character is valid - if not character or not character.valid or character.type ~= "character" then return end - local player = character.player -- Check player is valid - if not player.valid or not player.connected then return end - local entity = event.entity -- Check entity is valid - if not entity.valid or entity.force == player.force or entity.force.name == "neutral" then return end + local player = get_cause_player(event.cause) + if not player or not is_hostile(event.entity, player) then return end stat:increment(player, floor(event.final_damage_amount)) end) end @@ -131,12 +162,8 @@ end if config.Kills then local stat = Statistics:combine("Kills") Event.add(defines.events.on_entity_died, function(event) - local character = event.cause -- Check character is valid - if not character or not character.valid or character.type ~= "character" then return end - local player = character.player -- Check player is valid - if not player or not player.valid or not player.connected then return end - local entity = event.entity -- Check entity is valid - if not entity.valid or entity.force == player.force or entity.force.name == "neutral" then return end + local player = get_cause_player(event.cause) + if not player or not is_hostile(event.entity, player) then return end stat:increment(player) end) end