mirror of
https://github.com/Refactorio/RedMew.git
synced 2024-12-12 10:04:40 +02:00
96860dc782
* Init Factorio 2.0 update * add credits * fix test module * I know luackeck, I know * Fixes * Fix bad event.player_index handling * Hotfixes * Remove all filter inserters * Migrate removed items * Deprecating spidertron control and landfill features * Small updates and DO preset
409 lines
15 KiB
Lua
409 lines
15 KiB
Lua
local Global = require 'utils.global'
|
|
local Event = require 'utils.event'
|
|
local SA = require 'utils.space_age'
|
|
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 change_for_player = ScoreTracker.change_for_player
|
|
|
|
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'
|
|
local rockets_launched_name = 'rockets-launched'
|
|
local player_units_killed_name = 'player-units-killed' -- biters and spitters
|
|
local player_worms_killed_name = 'player-worms-killed'
|
|
local player_spawners_killed_name = 'player-spawners-killed'
|
|
local player_total_kills_name = 'player-total-kills'
|
|
local player_turrets_killed_name = 'player-turrets-killed'
|
|
local player_entities_built_name = 'player_entities_built'
|
|
local player_fish_eaten_name = 'player_fish_eaten'
|
|
local player_resources_hand_mined_name = 'player_resources_hand_mined'
|
|
local resources_hand_mined_name = 'resources_hand_mined'
|
|
local resources_exhausted_name = 'resources_exhausted'
|
|
|
|
ScoreTracker.register(rocks_smashed_name, {'player_stats.rocks_smashed'}, '[img=entity.huge-rock]')
|
|
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'})
|
|
if not SA.enabled() then
|
|
ScoreTracker.register(satellites_launched_name, {'player_stats.satellites_launched'}, '[img=item.satellite]')
|
|
end
|
|
ScoreTracker.register(rockets_launched_name, {'player_stats.rockets_launched'}, '[img=item.rocket-silo]')
|
|
ScoreTracker.register(player_units_killed_name, {'player_stats.player_units_killed'})
|
|
ScoreTracker.register(player_worms_killed_name, {'player_stats.player_worms_killed'})
|
|
ScoreTracker.register(player_spawners_killed_name, {'player_stats.player_spawners_killed'})
|
|
ScoreTracker.register(player_turrets_killed_name, {'player_stats.player_turrets_killed'})
|
|
ScoreTracker.register(player_total_kills_name, {'player_stats.player_total_kills'})
|
|
ScoreTracker.register(player_entities_built_name, {'player_stats.player_entities_built'})
|
|
ScoreTracker.register(player_fish_eaten_name, {'player_stats.player_fish_eaten'})
|
|
ScoreTracker.register(player_resources_hand_mined_name, {'player_stats.player_resources_hand_mined'})
|
|
ScoreTracker.register(resources_hand_mined_name, {'player_stats.resources_hand_mined'})
|
|
ScoreTracker.register(resources_exhausted_name, {'player_stats.resources_exhausted'})
|
|
|
|
local train_kill_causes = {
|
|
['locomotive'] = true,
|
|
['cargo-wagon'] = true,
|
|
['fluid-wagon'] = true,
|
|
['artillery-wagon'] = true
|
|
}
|
|
|
|
local entity_to_category_map = {
|
|
-- spawners
|
|
['biter-spawner'] = player_spawners_killed_name,
|
|
['spitter-spawner'] = player_spawners_killed_name,
|
|
|
|
-- worms
|
|
['small-worm-turret'] = player_worms_killed_name,
|
|
['medium-worm-turret'] = player_worms_killed_name,
|
|
['big-worm-turret'] = player_worms_killed_name,
|
|
['behemoth-worm-turret'] = player_worms_killed_name,
|
|
|
|
-- units
|
|
['small-biter'] = player_units_killed_name,
|
|
['medium-biter'] = player_units_killed_name,
|
|
['big-biter'] = player_units_killed_name,
|
|
['behemoth-biter'] = player_units_killed_name,
|
|
['small-spitter'] = player_units_killed_name,
|
|
['medium-spitter'] = player_units_killed_name,
|
|
['big-spitter'] = player_units_killed_name,
|
|
['behemoth-spitter'] = player_units_killed_name,
|
|
|
|
-- turrets
|
|
['gun-turret'] = player_turrets_killed_name,
|
|
['laser-turret'] = player_turrets_killed_name,
|
|
['artillery-turret'] = player_turrets_killed_name,
|
|
['flamethrower-turret'] = player_turrets_killed_name,
|
|
|
|
-- others
|
|
['defender'] = false,
|
|
['distractor'] = false,
|
|
['destroyer'] = false
|
|
}
|
|
|
|
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).physical_position
|
|
player_death_causes[index] = {}
|
|
change_for_global(player_count_name, 1)
|
|
end
|
|
|
|
local function get_cause_name(cause)
|
|
if cause then
|
|
local name = cause.name
|
|
if name == 'character' then
|
|
local player = cause.player
|
|
if player and player.valid then
|
|
return player.name
|
|
end
|
|
else
|
|
return name
|
|
end
|
|
end
|
|
return 'player_stats.unknown_death_cause'
|
|
end
|
|
|
|
local function player_died(event)
|
|
local player_index = event.player_index
|
|
local cause = get_cause_name(event.cause)
|
|
|
|
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
|
|
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
|
|
change_for_player(event.player_index, coins_earned_name, stack.count)
|
|
end
|
|
end
|
|
|
|
local function pre_player_mined_item(event)
|
|
local entity = event.entity
|
|
if entity.type == 'simple-entity' then -- Cheap check for rock, may have other side effects
|
|
change_for_global(rocks_smashed_name, 1)
|
|
return
|
|
end
|
|
if entity.type == 'resource' then
|
|
change_for_global(resources_hand_mined_name, 1)
|
|
change_for_player(event.player_index, player_resources_hand_mined_name, 1)
|
|
end
|
|
if entity.type == 'tree' then
|
|
change_for_global(trees_cut_down_name, 1)
|
|
return
|
|
end
|
|
if entity.type == 'container' and entity.operable == false then -- We check the container is not operable as these are used as loot chests in Crash Site and players can't add coins to them.
|
|
local inv = entity.get_inventory(defines.inventory.chest)
|
|
local coin_count = inv.get_item_count("coin")
|
|
if coin_count then
|
|
change_for_player(event.player_index, coins_earned_name, coin_count)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function resource_depleted(event)
|
|
local entity = event.entity
|
|
if entity.amount == 0 then
|
|
change_for_global(resources_exhausted_name, 1)
|
|
end
|
|
end
|
|
|
|
local function player_crafted_item(event)
|
|
local item_stack = event.item_stack
|
|
if not item_stack or not item_stack.valid_for_read then
|
|
return
|
|
end
|
|
|
|
change_for_player(event.player_index, player_items_crafted_name, item_stack.count)
|
|
end
|
|
|
|
local function player_console_chat(event)
|
|
local player_index = event.player_index
|
|
if player_index then
|
|
change_for_player(player_index, player_console_chats_name, 1)
|
|
end
|
|
end
|
|
|
|
local function player_built_entity(event)
|
|
local entity = event.entity
|
|
if not entity or not entity.valid then
|
|
return
|
|
end
|
|
|
|
local player_index = event.player_index
|
|
if entity.is_registered_for_construction() == false then -- When is_registered_for_construction() is true we only register the entity as built once a robot builds it
|
|
change_for_global(built_by_players_name, 1)
|
|
change_for_player(player_index, player_entities_built_name, 1)
|
|
end
|
|
end
|
|
|
|
local function robot_built_entity(event)
|
|
change_for_global(built_by_robots_name, 1)
|
|
local robot = event.robot
|
|
|
|
if not robot.valid then
|
|
return
|
|
end
|
|
|
|
-- When item gets built, add to the total entities built for the player whose robot built the entity NOT for the player who placed the ghost
|
|
local robot_owner = robot.logistic_network.cells[1].owner
|
|
if robot_owner.name == 'character' and robot_owner.player then -- nil if the robot owner is a roboport
|
|
change_for_player(robot_owner.player.index, player_entities_built_name, 1)
|
|
end
|
|
end
|
|
|
|
local function get_player_index_from_cause(cause, event)
|
|
if cause.name == 'character' then
|
|
return cause.player.index
|
|
end
|
|
|
|
local cause_type = cause.type
|
|
if cause_type ~= 'car' and cause_type ~= 'spider-vehicle' then
|
|
return nil
|
|
end
|
|
|
|
local driver = cause.get_driver()
|
|
local passenger = cause.get_passenger()
|
|
if not driver and not passenger then
|
|
return nil -- for empty vehicle
|
|
end
|
|
|
|
local damage_type = event.damage_type.name
|
|
local spidertron_targetting_paramers = false
|
|
if cause_type == 'spider-vehicle' then
|
|
spidertron_targetting_paramers = cause.vehicle_automatic_targeting_parameters.auto_target_with_gunner -- if targetting is automatic then the driver gets the kill unless they're not in the spider
|
|
end
|
|
|
|
if damage_type == 'impact' then -- damage type is impact when a vehicle runs over an entity
|
|
if driver then -- to check if the driver jumped out before the kill
|
|
return driver.player.index
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
if not passenger then
|
|
return driver.player.index
|
|
end
|
|
|
|
if driver and (cause.driver_is_gunner or spidertron_targetting_paramers) then -- the if driver allows autotarget kills to go to the passenger when they're in spidertron
|
|
return driver.player.index
|
|
else
|
|
return passenger.player.index
|
|
end
|
|
end
|
|
|
|
local function entity_died(event)
|
|
local entity = event.entity
|
|
if not entity or not entity.valid or entity.force.name ~= 'enemy' then
|
|
return
|
|
end
|
|
|
|
change_for_global(aliens_killed_name, 1)
|
|
|
|
local cause = event.cause
|
|
if not cause or not cause.valid then
|
|
return
|
|
end
|
|
|
|
-- Only store for players if its an allowed entity (ie not for walls, chests etc)
|
|
local category = entity_to_category_map[entity.name]
|
|
if category == nil then
|
|
return
|
|
end
|
|
|
|
local player_index = get_player_index_from_cause(cause, event)
|
|
if player_index then
|
|
change_for_player(player_index, player_total_kills_name, 1)
|
|
if category then
|
|
change_for_player(player_index, category, 1)
|
|
end
|
|
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
|
|
|
|
change_for_global(rockets_launched_name, 1)
|
|
|
|
local pod = entity.cargo_pod
|
|
if not pod or not pod.valid then
|
|
return
|
|
end
|
|
|
|
local count = 0
|
|
local qualities = prototypes.quality
|
|
for k = 1, pod.get_max_inventory_index() do
|
|
local inventory = pod.get_inventory(k)
|
|
if inventory then
|
|
local add = inventory.get_item_count
|
|
for tier, _ in pairs(qualities) do
|
|
count = count + add({ name = 'satellite', quality = tier })
|
|
end
|
|
end
|
|
end
|
|
|
|
if count == 0 then
|
|
return
|
|
end
|
|
|
|
change_for_global(satellites_launched_name, 1)
|
|
end
|
|
|
|
local function capsule_used(event)
|
|
local item = event.item
|
|
|
|
if not item or not item.valid or item.name ~= 'raw-fish' then
|
|
return
|
|
end
|
|
|
|
change_for_player(event.player_index, player_fish_eaten_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
|
|
local index = p.index
|
|
local last_pos = player_last_position[index]
|
|
local pos = p.physical_position
|
|
|
|
local d_x = last_pos.x - pos.x
|
|
local d_y = last_pos.y - pos.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
|
|
|
|
Event.add(defines.events.on_player_created, player_created)
|
|
Event.add(defines.events.on_player_died, player_died)
|
|
Event.add(defines.events.on_picked_up_item, picked_up_item)
|
|
Event.add(defines.events.on_pre_player_mined_item, pre_player_mined_item)
|
|
Event.add(defines.events.on_player_crafted_item, player_crafted_item)
|
|
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, entity_died)
|
|
Event.add(defines.events.on_rocket_launched, rocket_launched)
|
|
Event.add(defines.events.on_player_used_capsule, capsule_used)
|
|
Event.add(defines.events.on_resource_depleted, resource_depleted)
|
|
|
|
Event.on_nth_tick(62, tick)
|
|
|
|
local Public = {
|
|
rocks_smashed_name = rocks_smashed_name,
|
|
trees_cut_down_name = trees_cut_down_name,
|
|
player_count_name = player_count_name,
|
|
kills_by_trains_name = kills_by_trains_name,
|
|
built_by_robots_name = built_by_robots_name,
|
|
built_by_players_name = built_by_players_name,
|
|
aliens_killed_name = aliens_killed_name,
|
|
coins_spent_name = coins_spent_name,
|
|
coins_earned_name = coins_earned_name,
|
|
player_deaths_name = player_deaths_name,
|
|
player_console_chats_name = player_console_chats_name,
|
|
player_items_crafted_name = player_items_crafted_name,
|
|
player_distance_walked_name = player_distance_walked_name,
|
|
rockets_launched_name = rockets_launched_name,
|
|
satellites_launched_name = satellites_launched_name,
|
|
player_units_killed_name = player_units_killed_name,
|
|
player_worms_killed_name = player_worms_killed_name,
|
|
player_spawners_killed_name = player_spawners_killed_name,
|
|
player_total_kills_name = player_total_kills_name,
|
|
player_turrets_killed_name = player_turrets_killed_name,
|
|
player_entities_built_name = player_entities_built_name,
|
|
player_fish_eaten_name = player_fish_eaten_name,
|
|
player_resources_hand_mined_name = player_resources_hand_mined_name,
|
|
resources_hand_mined_name = resources_hand_mined_name,
|
|
resources_exhausted_name = resources_exhausted_name
|
|
}
|
|
|
|
-- Returns a dictionary of cause_name -> count
|
|
function Public.get_all_death_causes_by_player(player_index)
|
|
return player_death_causes[player_index] or {}
|
|
end
|
|
|
|
return Public
|