GLOBAL_VAR(scoreboard) // Variable to save the scoreboard string once it's been generated
//Thresholds for Score Ratings
#define SINGULARITY_DESERVES_BETTER -3500
#define SINGULARITY_FODDER -3000
#define ALL_FIRED -2500
#define WASTE_OF_OXYGEN -2000
#define HEAP_OF_SCUM -1500
#define LAB_MONKEYS -1000
#define UNDESIREABLES -500
#define SERVANTS_OF_SCIENCE 500
#define GOOD_BUNCH 1000
#define MACHINE_THIRTEEN 1500
#define PROMOTIONS_FOR_EVERYONE 2000
#define AMBASSADORS_OF_DISCOVERY 3000
#define PRIDE_OF_SCIENCE 4000
#define NANOTRASEN_FINEST 5000
/datum/scoreboard
/// Overall combined score for the whole round.
var/crewscore = 0
/// How many useful items have cargo shipped out?
var/score_things_shipped = 0
/// How many harvests have hydroponics done?
var/score_things_harvested = 0
/// How much ore has been mined on the mining z level?
var/score_ore_mined = 0
/// How much research was done by science?
var/score_research_done = 0
/// How many random events did the station survive?
var/score_events_endured = 0
/// How many APCs have poor charge?
var/score_power_loss = 0
/// How many people got out alive?
var/score_escapees = 0
/// How many people /didn't/ get out alive?
var/score_dead_crew = 0
/// How much blood, puke, stains etc went uncleaned?
var/score_mess = 0
/// How many meals were made?
var/score_meals = 0
/// How many rampant, uncured diseases are on board the station?
var/score_disease = 0
/// How many command members died? (Revolution)
var/score_dead_command = 0
/// How many antagonists are alive in the brig? (Nuke ops & Revolution)
var/score_arrested = 0
/// How many operatives were killed? (Nuke ops & Revolution)
var/score_ops_killed = 0
/// How much noms were had by the crew?
var/score_food_eaten = 0
/// How many times was the clown punched, struck, or otherwise maligned?
var/score_clown_abuse = 0
// Booleans //
/// Were the antagonists successful?
var/score_greentext = FALSE
/// Did the crew catch all of the antags alive?
var/all_arrested = FALSE
/// Is the NAD safe and secure?
var/disc_secure = FALSE
// Points penalties/bonuses //
/// If all APCs on the station are running optimally, big bonus.
var/power_bonus = FALSE
/// If there are no messes on the station anywhere, huge bonus.
var/mess_bonus = FALSE
/// If the AI is dead, big points penalty.
var/dead_ai = FALSE
/// Was the station blown into little bits?
var/nuked = FALSE
/// Points penalty for being blown to little bits.
var/nuked_penalty = 0
// Player Stats //
/// What was the name of the richest person on the shuttle?
var/richest_name = ""
/// What was the ckey of the richest person on the shuttle?
var/richest_key = ""
/// What was the job of the richest person on the shuttle?
var/richest_job = ""
/// How much money did the richest person on the shuttle have?
var/richest_cash = 0
/// What was the name of the most injured person on the shuttle?
var/damaged_name
/// What was the ckey of the most injured person on the shuttle?
var/damaged_key
/// What was the job of the most injured person on the shuttle?
var/damaged_job
/// How damaged was the most injured person on the shuttle?
var/damaged_health
/datum/scoreboard/proc/scoreboard()
// Print a list of antagonists to the server log.
log_antags()
for(var/_I in GLOB.mob_list)
var/mob/M = _I
if(is_station_level(M.z))
check_station_player(M)
else if(!M.loc)
stack_trace("[M] ended up without a location!")
else if(SSshuttle.emergency.mode >= SHUTTLE_ENDGAME && istype(get_area(M), SSshuttle.emergency.areaInstance))
check_shuttle_player(M)
check_apc_power()
check_cleanables()
generate_scoreboard()
/datum/scoreboard/proc/log_antags()
var/list/total_antagonists = list()
// Look into all mobs in the world, dead or alive
for(var/mind in SSticker.minds)
var/datum/mind/M = mind
var/role = M.special_role
// If they're an antagonist of some sort.
if(role)
if(total_antagonists[role]) // If the role exists already, add the name to it.
total_antagonists[role] += ", [M.name]([M.key])"
else // If the role doesn't exist in the list, create it and add the mob
total_antagonists[role] += ": [M.name]([M.key])"
// Now print them all into the log!
log_game("Antagonists at round end were...")
for(var/I in total_antagonists)
log_game("[I]s[total_antagonists[I]].")
/datum/scoreboard/proc/check_station_player(mob/M)
if(!is_station_level(M.z) || M.stat != DEAD)
return
if(isAI(M))
dead_ai = TRUE
score_dead_crew++
else if(ishuman(M))
score_dead_crew++
/datum/scoreboard/proc/check_shuttle_player(mob/M)
if(!M.mind || M.stat == DEAD || !ishuman(M))
return
var/mob/living/carbon/human/H = M
score_escapees++
var/cash_score = get_score_person_worth(H)
if(cash_score > richest_cash)
richest_cash = cash_score
richest_name = H.real_name
richest_job = H.job
richest_key = (H.client?.prefs.toggles2 & PREFTOGGLE_2_ANON) ? "Anon" : H.key
var/damage_score = H.getBruteLoss() + H.getFireLoss() + H.getToxLoss() + H.getOxyLoss()
if(damage_score > damaged_health)
damaged_health = damage_score
damaged_name = H.real_name
damaged_job = H.job
damaged_key = (H.client?.prefs.toggles2 & PREFTOGGLE_2_ANON) ? "Anon" : H.key
/// A function to determine the cash plus the account balance of the wealthiest escapee
/datum/scoreboard/proc/get_score_person_worth(mob/living/carbon/human/H)
if(!H.mind)
return // if they have no mind, we don't care
// return value of space cash on the person + whatever balance they currently have in their original money account
return get_score_container_worth(H) + H.mind.initial_account?.credit_balance
/// A recursive function to properly determine the cash on the wealthiest escapee
/datum/scoreboard/proc/get_score_container_worth(atom/C, level = 0)
. = 0
if(level >= 5) // in case the containers recurse or something
return 0
for(var/obj/item/stack/spacecash/cash in C.contents)
. += cash.amount
for(var/obj/item/storage/S in C.contents)
. += .(S, level + 1)
/datum/scoreboard/proc/check_apc_power()
for(var/_A in GLOB.apcs)
var/obj/machinery/power/apc/A = _A
if(!is_station_level(A.z))
continue
var/obj/item/stock_parts/cell/C = A.cell
if(!C || C.charge < 2300)
score_power_loss++ //200 charge leeway
/datum/scoreboard/proc/check_cleanables()
for(var/obj/effect/decal/cleanable/C in world)
if(!is_station_level(C.z))
continue
if(istype(C, /obj/effect/decal/cleanable/blood/gibs))
score_mess += 3
else if(istype(C, /obj/effect/decal/cleanable/blood))
score_mess += 1
else if(istype(C, /obj/effect/decal/cleanable/vomit))
score_mess += 1
/datum/scoreboard/proc/generate_scoreboard()
// Point modifiers
var/points_events_endured = score_events_endured * 50
var/points_research_done = score_research_done * 30
var/points_disease = score_disease * 30
var/points_dead_crew = score_dead_crew * 25
var/points_escapees = score_escapees * 25
var/points_power_loss = score_power_loss * 20
var/points_things_harvested = score_things_harvested * 5
var/points_things_shipped = score_things_shipped * 5
var/points_meals = score_meals * 5
var/points_ore_mined = score_ore_mined * 2
// Bonuses
crewscore += points_events_endured
crewscore += points_research_done
crewscore += points_escapees
crewscore += points_things_harvested
crewscore += points_things_shipped
crewscore += points_meals
crewscore += points_ore_mined
if(!score_power_loss)
crewscore += 2500
power_bonus = TRUE
if(!score_mess)
crewscore += 1500
mess_bonus = TRUE
if(all_arrested) // This only seems to be implemented for Rev and Nukies. -DaveKorhal
crewscore *= 3 // This needs to be here for the bonus to be applied properly
// Penalties
crewscore -= points_dead_crew
crewscore -= points_power_loss
crewscore -= points_disease
crewscore -= score_mess
if(dead_ai)
crewscore -= 250
// Generate the score panel
var/list/dat = list("Round Statistics and Score