2018-06-27 15:48:04 +02:00
local Global = require ' utils.global '
2019-05-30 21:57:43 +02:00
local Event = require ' utils.event '
2024-10-22 21:22:35 +02:00
local SA = require ' utils.space_age '
2019-05-30 20:22:21 +02:00
local ScoreTracker = require ' utils.score_tracker '
2018-12-15 22:28:53 +02:00
require ' utils.table '
2021-02-09 19:36:54 +02:00
2018-12-10 22:06:39 +02:00
local pairs = pairs
local sqrt = math.sqrt
2019-05-31 19:11:36 +02:00
local change_for_global = ScoreTracker.change_for_global
local change_for_player = ScoreTracker.change_for_player
2018-06-27 15:48:04 +02:00
2019-05-30 20:22:21 +02:00
local rocks_smashed_name = ' rocks-smashed '
2019-05-30 21:57:43 +02:00
local trees_cut_down_name = ' trees-cut '
2019-05-30 20:22:21 +02:00
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 '
2019-05-30 21:57:43 +02:00
local player_distance_walked_name = ' player-distance-walked '
local satellites_launched_name = ' satellites-launched '
2024-10-22 21:22:35 +02:00
local rockets_launched_name = ' rockets-launched '
2020-12-31 20:11:03 +02:00
local player_units_killed_name = ' player-units-killed ' -- biters and spitters
2020-12-31 12:01:07 +02:00
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 '
2021-01-08 14:34:51 +02:00
local player_entities_built_name = ' player_entities_built '
2021-02-09 20:08:03 +02:00
local player_fish_eaten_name = ' player_fish_eaten '
2022-04-01 13:22:33 +02:00
local player_resources_hand_mined_name = ' player_resources_hand_mined '
local resources_hand_mined_name = ' resources_hand_mined '
local resources_exhausted_name = ' resources_exhausted '
2019-05-30 21:57:43 +02:00
2024-10-22 21:22:35 +02:00
ScoreTracker.register ( rocks_smashed_name , { ' player_stats.rocks_smashed ' } , ' [img=entity.huge-rock] ' )
2019-05-30 21:57:43 +02:00
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 ' } )
2024-10-22 21:22:35 +02:00
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] ' )
2020-12-31 12:01:07 +02:00
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 ' } )
2021-01-08 14:34:51 +02:00
ScoreTracker.register ( player_entities_built_name , { ' player_stats.player_entities_built ' } )
2021-02-09 20:08:03 +02:00
ScoreTracker.register ( player_fish_eaten_name , { ' player_stats.player_fish_eaten ' } )
2022-04-01 13:22:33 +02:00
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 ' } )
2018-12-15 22:28:53 +02:00
local train_kill_causes = {
2019-01-01 23:26:57 +02:00
[ ' locomotive ' ] = true ,
[ ' cargo-wagon ' ] = true ,
[ ' fluid-wagon ' ] = true ,
[ ' artillery-wagon ' ] = true
2018-12-15 22:28:53 +02:00
}
2018-06-27 15:48:04 +02:00
2020-12-31 20:11:03 +02:00
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
2020-12-31 12:01:07 +02:00
}
2019-05-31 19:11:36 +02:00
local player_last_position = { }
local player_death_causes = { }
2020-12-31 20:11:03 +02:00
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 )
2018-06-27 15:48:04 +02:00
2018-12-15 22:28:53 +02:00
--- When the player first logs on, initialize their stats and pull their former playtime
2018-06-27 15:48:04 +02:00
local function player_created ( event )
local index = event.player_index
2024-10-22 21:22:35 +02:00
player_last_position [ index ] = game.get_player ( index ) . physical_position
2019-05-31 19:11:36 +02:00
player_death_causes [ index ] = { }
change_for_global ( player_count_name , 1 )
2018-06-27 15:48:04 +02:00
end
local function get_cause_name ( cause )
if cause then
local name = cause.name
2019-05-02 17:29:55 +02:00
if name == ' character ' then
2018-06-28 15:49:22 +02:00
local player = cause.player
2018-06-27 15:48:04 +02:00
if player and player.valid then
return player.name
end
else
return name
end
end
2019-06-01 00:12:41 +02:00
return ' player_stats.unknown_death_cause '
2018-06-27 15:48:04 +02:00
end
local function player_died ( event )
local player_index = event.player_index
local cause = get_cause_name ( event.cause )
2019-05-31 19:11:36 +02:00
local causes = player_death_causes [ player_index ]
2018-06-27 15:48:04 +02:00
local cause_count = causes [ cause ] or 0
causes [ cause ] = cause_count + 1
2018-12-15 22:28:53 +02:00
2019-05-31 19:11:36 +02:00
change_for_player ( player_index , player_deaths_name , 1 )
2019-01-01 23:26:57 +02:00
if train_kill_causes [ cause ] then
2019-05-31 19:11:36 +02:00
change_for_global ( kills_by_trains_name , 1 )
2018-12-15 22:28:53 +02:00
end
2018-06-27 15:48:04 +02:00
end
2018-06-29 01:44:20 +02:00
local function picked_up_item ( event )
local stack = event.item_stack
2018-08-01 17:35:48 +02:00
if stack.name == ' coin ' then
2019-05-31 19:11:36 +02:00
change_for_player ( event.player_index , coins_earned_name , stack.count )
2018-06-29 01:44:20 +02:00
end
end
2021-02-18 15:43:50 +02:00
local function pre_player_mined_item ( event )
2021-02-19 15:33:13 +02:00
local entity = event.entity
if entity.type == ' simple-entity ' then -- Cheap check for rock, may have other side effects
2019-05-31 19:11:36 +02:00
change_for_global ( rocks_smashed_name , 1 )
2018-12-15 22:28:53 +02:00
return
end
2022-04-01 13:22:33 +02:00
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
2021-02-19 15:33:13 +02:00
if entity.type == ' tree ' then
2019-05-31 19:11:36 +02:00
change_for_global ( trees_cut_down_name , 1 )
2021-02-19 15:33:13 +02:00
return
2018-12-15 22:28:53 +02:00
end
2021-02-19 15:33:13 +02:00
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 )
2021-02-18 15:43:50 +02:00
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
2018-12-15 22:28:53 +02:00
end
2022-04-01 13:22:33 +02:00
local function resource_depleted ( event )
local entity = event.entity
if entity.amount == 0 then
change_for_global ( resources_exhausted_name , 1 )
end
end
2018-12-15 22:28:53 +02:00
local function player_crafted_item ( event )
2020-09-02 16:04:03 +02:00
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 )
2018-12-15 22:28:53 +02:00
end
local function player_console_chat ( event )
local player_index = event.player_index
if player_index then
2019-05-31 19:11:36 +02:00
change_for_player ( player_index , player_console_chats_name , 1 )
2018-12-15 22:28:53 +02:00
end
end
2021-01-08 14:34:51 +02:00
local function player_built_entity ( event )
2024-10-22 21:22:35 +02:00
local entity = event.entity
2021-03-17 23:33:05 +02:00
if not entity or not entity.valid then
return
end
2021-01-08 14:34:51 +02:00
local player_index = event.player_index
2021-03-17 23:33:05 +02:00
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
2021-02-09 19:36:54 +02:00
change_for_global ( built_by_players_name , 1 )
2021-01-08 14:34:51 +02:00
change_for_player ( player_index , player_entities_built_name , 1 )
end
2018-12-15 22:28:53 +02:00
end
2021-01-08 14:34:51 +02:00
local function robot_built_entity ( event )
2019-05-31 19:11:36 +02:00
change_for_global ( built_by_robots_name , 1 )
2021-02-09 19:36:54 +02:00
local robot = event.robot
2021-02-11 13:25:39 +02:00
if not robot.valid then
2021-02-10 00:30:33 +02:00
return
end
2021-02-09 19:36:54 +02:00
-- 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
2021-02-13 19:47:34 +02:00
local robot_owner = robot.logistic_network . cells [ 1 ] . owner
2021-02-14 12:51:06 +02:00
if robot_owner.name == ' character ' and robot_owner.player then -- nil if the robot owner is a roboport
2021-02-09 19:36:54 +02:00
change_for_player ( robot_owner.player . index , player_entities_built_name , 1 )
2021-01-08 14:34:51 +02:00
end
2018-12-15 22:28:53 +02:00
end
2021-01-02 13:35:28 +02:00
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
2020-12-31 20:11:03 +02:00
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
2021-01-01 20:00:48 +02:00
if not cause or not cause.valid then
2020-12-31 20:11:03 +02:00
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
2021-01-02 13:35:28 +02:00
local player_index = get_player_index_from_cause ( cause , event )
2021-01-01 20:00:48 +02:00
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
2018-12-15 22:28:53 +02:00
end
end
2019-05-30 21:57:43 +02:00
local function rocket_launched ( event )
local entity = event.rocket
if not entity or not entity.valid or not entity.force == ' player ' then
return
end
2024-10-22 21:22:35 +02:00
change_for_global ( rockets_launched_name , 1 )
local inventory = entity.get_inventory ( defines.inventory . rocket_silo_rocket )
2019-05-30 21:57:43 +02:00
if not inventory or not inventory.valid then
return
end
local count = inventory.get_item_count ( ' satellite ' )
if count == 0 then
return
end
2019-05-31 19:11:36 +02:00
change_for_global ( satellites_launched_name , 1 )
2019-05-30 21:57:43 +02:00
end
2021-02-09 20:08:03 +02:00
local function capsule_used ( event )
local item = event.item
2021-02-10 00:34:01 +02:00
if not item or not item.valid or item.name ~= ' raw-fish ' then
2021-02-09 20:08:03 +02:00
return
end
change_for_player ( event.player_index , player_fish_eaten_name , 1 )
end
2018-06-27 15:48:04 +02:00
local function tick ( )
2018-12-10 22:06:39 +02:00
for _ , p in pairs ( game.connected_players ) do
2018-06-27 15:48:04 +02:00
if ( p.afk_time < 30 or p.walking_state . walking ) and p.vehicle == nil then
local index = p.index
2019-05-31 19:11:36 +02:00
local last_pos = player_last_position [ index ]
2024-10-22 21:22:35 +02:00
local pos = p.physical_position
2018-06-27 15:48:04 +02:00
local d_x = last_pos.x - pos.x
local d_y = last_pos.y - pos.y
2019-05-31 19:11:36 +02:00
player_last_position [ index ] = pos
change_for_player ( index , player_distance_walked_name , sqrt ( d_x * d_x + d_y * d_y ) )
2018-06-27 15:48:04 +02:00
end
end
end
Event.add ( defines.events . on_player_created , player_created )
Event.add ( defines.events . on_player_died , player_died )
2018-06-29 01:44:20 +02:00
Event.add ( defines.events . on_picked_up_item , picked_up_item )
2021-02-18 15:43:50 +02:00
Event.add ( defines.events . on_pre_player_mined_item , pre_player_mined_item )
2018-12-15 22:28:53 +02:00
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 )
2020-12-31 20:11:03 +02:00
Event.add ( defines.events . on_entity_died , entity_died )
2019-05-30 21:57:43 +02:00
Event.add ( defines.events . on_rocket_launched , rocket_launched )
2021-02-09 20:08:03 +02:00
Event.add ( defines.events . on_player_used_capsule , capsule_used )
2022-04-01 13:22:33 +02:00
Event.add ( defines.events . on_resource_depleted , resource_depleted )
2018-12-15 22:28:53 +02:00
2018-06-27 15:48:04 +02:00
Event.on_nth_tick ( 62 , tick )
2021-01-02 14:00:21 +02:00
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 ,
2024-10-22 21:22:35 +02:00
rockets_launched_name = rockets_launched_name ,
2021-01-02 14:00:21 +02:00
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 ,
2021-01-08 14:34:51 +02:00
player_turrets_killed_name = player_turrets_killed_name ,
2021-02-09 20:08:03 +02:00
player_entities_built_name = player_entities_built_name ,
2022-04-01 13:22:33 +02:00
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
2021-01-02 14:00:21 +02:00
}
2018-06-27 15:48:04 +02:00
2018-12-06 13:18:52 +02:00
-- Returns a dictionary of cause_name -> count
2019-06-07 11:25:24 +02:00
function Public . get_all_death_causes_by_player ( player_index )
return player_death_causes [ player_index ] or { }
2018-06-27 15:48:04 +02:00
end
2019-06-07 11:25:24 +02:00
2018-06-27 15:48:04 +02:00
return Public