diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 222002f512..65c7145d8f 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -444,12 +444,8 @@ candidates -= M /proc/pollGhostCandidates(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, ignore_category = null, flashwindow = TRUE) - var/list/candidates = list() - - for(var/mob/dead/observer/G in GLOB.player_list) - if(G.can_reenter_round(TRUE)) - candidates += G - + var/datum/element/ghost_role_eligibility/eligibility = SSdcs.GetElement(/datum/element/ghost_role_eligibility) + var/list/candidates = eligibility.get_all_ghost_role_eligible() return pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category, flashwindow, candidates) /proc/pollCandidates(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, ignore_category = null, flashwindow = TRUE, list/group = null) diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index af31e2b5a5..ec3593ee9d 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -23,6 +23,8 @@ GLOBAL_VAR_INIT(bsa_unlock, FALSE) //BSA unlocked by head ID swipes GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details +GLOBAL_LIST_EMPTY(clientless_round_timeouts) // ckey -> time that ckey can rejoin round + // All religion stuff GLOBAL_VAR(religion) GLOBAL_VAR(deity) diff --git a/code/datums/elements/ghost_role_eligibility.dm b/code/datums/elements/ghost_role_eligibility.dm new file mode 100644 index 0000000000..8ecb579bc8 --- /dev/null +++ b/code/datums/elements/ghost_role_eligibility.dm @@ -0,0 +1,54 @@ +/datum/element/ghost_role_eligibility + element_flags = ELEMENT_DETACH + var/list/timeouts = list() + var/list/mob/eligible_mobs = list() + +/datum/element/ghost_role_eligibility/Attach(datum/target,penalize = FALSE) + . = ..() + if(!ismob(target)) + return ELEMENT_INCOMPATIBLE + var/mob/M = target + if(!(M in eligible_mobs)) + eligible_mobs += M + if(penalize) //penalizing them from making a ghost role / midround antag comeback right away. + var/penalty = CONFIG_GET(number/suicide_reenter_round_timer) MINUTES + var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES + if(world.time < roundstart_quit_limit) //add up the time difference to their antag rolling penalty if they quit before half a (ingame) hour even passed. + penalty += roundstart_quit_limit - world.time + if(penalty) + penalty += world.realtime + if(penalty - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime) + penalty = CANT_REENTER_ROUND + if(!(M.ckey in timeouts)) + timeouts += M.ckey + timeouts[M.ckey] = 0 + timeouts[M.ckey] = max(timeouts[M.ckey],penalty) + +/datum/element/ghost_role_eligibility/Detach(mob/M) + . = ..() + if(M in eligible_mobs) + eligible_mobs -= M + +/datum/element/ghost_role_eligibility/proc/get_all_ghost_role_eligible(silent = FALSE) + var/list/candidates = list() + for(var/m in eligible_mobs) + var/mob/M = m + if(M.can_reenter_round(TRUE)) + candidates += M + return candidates + +/mob/proc/can_reenter_round(silent = FALSE) + var/datum/element/ghost_role_eligibility/eli = SSdcs.GetElement(/datum/element/ghost_role_eligibility) + return eli.can_reenter_round(src,silent) + +/datum/element/ghost_role_eligibility/proc/can_reenter_round(var/mob/M,silent = FALSE) + if(!(M in eligible_mobs)) + return FALSE + if(!(M.ckey in timeouts)) + return TRUE + var/timeout = timeouts[M.ckey] + if(timeout != CANT_REENTER_ROUND && timeout <= world.realtime) + return TRUE + if(!silent && M.client) + to_chat(M, "You are unable to reenter the round[timeout != CANT_REENTER_ROUND ? " yet. Your ghost role blacklist will expire in [DisplayTimeText(timeout - world.realtime)]" : ""].") + return FALSE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 91ac73d142..32c076b69a 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -17,10 +17,10 @@ var/list/living_antags = list() var/list/dead_players = list() var/list/list_observers = list() + var/list/ghost_eligible = list() /datum/dynamic_ruleset/midround/from_ghosts weight = 0 - required_type = /mob/dead/observer /// Whether the ruleset should call generate_ruleset_body or not. var/makeBody = TRUE @@ -34,6 +34,8 @@ living_players = trim_list(mode.current_players[CURRENT_LIVING_PLAYERS]) living_antags = trim_list(mode.current_players[CURRENT_LIVING_ANTAGS]) list_observers = trim_list(mode.current_players[CURRENT_OBSERVERS]) + var/datum/element/ghost_role_eligibility/eligibility = SSdcs.GetElement(/datum/element/ghost_role_eligibility) + ghost_eligible = trim_list(eligibility.get_all_ghost_role_eligible()) /datum/dynamic_ruleset/midround/proc/trim_list(list/L = list()) var/list/trimmed_list = L.Copy() @@ -70,6 +72,25 @@ continue return trimmed_list +/datum/dynamic_ruleset/midround/from_ghosts/trim_list(list/L = list()) + var/list/trimmed_list = L.Copy() + for(var/mob/M in trimmed_list) + if (!M.client) // Are they connected? + trimmed_list.Remove(M) + continue + if(!mode.check_age(M.client, minimum_required_age)) + trimmed_list.Remove(M) + continue + if(antag_flag_override) + if(!(antag_flag_override in M.client.prefs.be_special) || jobban_isbanned(M.ckey, antag_flag_override)) + trimmed_list.Remove(M) + continue + else + if(!(antag_flag in M.client.prefs.be_special) || jobban_isbanned(M.ckey, antag_flag)) + trimmed_list.Remove(M) + continue + return trimmed_list + // You can then for example prompt dead players in execute() to join as strike teams or whatever // Or autotator someone @@ -91,11 +112,15 @@ return FALSE return TRUE +/datum/dynamic_ruleset/midround/from_ghosts/ready(forced = FALSE) + if (required_candidates > ghost_eligible.len) + SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts") + return FALSE + return ..() + + /datum/dynamic_ruleset/midround/from_ghosts/execute() - var/list/possible_candidates = list() - possible_candidates.Add(dead_players) - possible_candidates.Add(list_observers) - var/application_successful = send_applications(possible_candidates) + var/application_successful = send_applications(ghost_eligible) return assigned.len > 0 && application_successful /// This sends a poll to ghosts if they want to be a ghost spawn from a ruleset. @@ -292,9 +317,6 @@ var/datum/mind/wizard /datum/dynamic_ruleset/midround/from_ghosts/wizard/ready(forced = FALSE) - if (required_candidates > (dead_players.len + list_observers.len)) - SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts") - return FALSE if(GLOB.wizardstart.len == 0) log_admin("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") message_admins("Cannot accept Wizard ruleset. Couldn't find any wizard spawn points.") @@ -354,12 +376,6 @@ required_candidates = operative_cap[indice_pop] return ..() -/datum/dynamic_ruleset/midround/from_ghosts/nuclear/ready(forced = FALSE) - if (required_candidates > (dead_players.len + list_observers.len)) - SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts") - return FALSE - return ..() - /datum/dynamic_ruleset/midround/from_ghosts/nuclear/finish_setup(mob/new_character, index) new_character.mind.special_role = "Nuclear Operative" new_character.mind.assigned_role = "Nuclear Operative" @@ -391,12 +407,6 @@ high_population_requirement = 50 repeatable = TRUE -/datum/dynamic_ruleset/midround/from_ghosts/blob/ready(forced = FALSE) - if (required_candidates > (dead_players.len + list_observers.len)) - SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts") - return FALSE - return ..() - /datum/dynamic_ruleset/midround/from_ghosts/blob/generate_ruleset_body(mob/applicant) var/body = applicant.become_overmind() return body @@ -423,12 +433,6 @@ repeatable = TRUE var/list/vents = list() -/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/ready(forced = FALSE) - if (required_candidates > (dead_players.len + list_observers.len)) - SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts") - return FALSE - return ..() - /datum/dynamic_ruleset/midround/from_ghosts/xenomorph/execute() // 50% chance of being incremented by one required_candidates += prob(50) @@ -523,12 +527,6 @@ requirements = list(30,30,20,20,15,10,10,10,10,5) // yes, it can even happen in "extended"! high_population_requirement = 5 -/datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/ready(forced = FALSE) - if (required_candidates > (dead_players.len + list_observers.len)) - SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts") - return FALSE - return ..() - /datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/generate_ruleset_body(mob/applicant) var/mob/camera/disease/virus = new /mob/camera/disease(SSmapping.get_station_center()) applicant.transfer_ckey(virus, FALSE) @@ -563,9 +561,6 @@ deadMobs++ if(deadMobs < REVENANT_SPAWN_THRESHOLD) return FALSE - if(required_candidates > (dead_players.len + list_observers.len)) - SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts") - return FALSE for(var/mob/living/L in GLOB.dead_mob_list) //look for any dead bodies var/turf/T = get_turf(L) if(T && is_station_level(T.z)) @@ -611,9 +606,6 @@ var/list/spawn_locs = list() /datum/dynamic_ruleset/midround/from_ghosts/slaughter_demon/ready(forced = FALSE) - if(required_candidates > (dead_players.len + list_observers.len)) - SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts") - return FALSE for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list) if(isturf(L.loc)) spawn_locs += L.loc @@ -663,9 +655,6 @@ repeatable = TRUE /datum/dynamic_ruleset/midround/from_ghosts/abductors/ready(forced = FALSE) - if(required_candidates > (dead_players.len + list_observers.len)) - SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts") - return FALSE team = new /datum/team/abductor_team if(team.team_number > ABDUCTOR_MAX_TEAMS) return FALSE @@ -703,9 +692,6 @@ var/spawn_loc /datum/dynamic_ruleset/midround/from_ghosts/ninja/ready(forced = FALSE) - if(required_candidates > (dead_players.len + list_observers.len)) - SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough ghosts") - return FALSE if(!spawn_loc) var/list/spawn_locs = list() for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list) diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index 7a83893f8b..c6c5547e54 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -479,10 +479,10 @@ possessed = TRUE - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the spirit of [user.real_name]'s blade?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_POSSESSED_BLADE) + var/list/mob/candidates = pollGhostCandidates("Do you want to play as the spirit of [user.real_name]'s blade?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_POSSESSED_BLADE) if(LAZYLEN(candidates)) - var/mob/dead/observer/C = pick(candidates) + var/mob/C = pick(candidates) var/mob/living/simple_animal/shade/S = new(src) S.real_name = name S.name = name diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm index fdc85475fb..8ee6981fa4 100644 --- a/code/game/objects/structures/ghost_role_spawners.dm +++ b/code/game/objects/structures/ghost_role_spawners.dm @@ -618,6 +618,8 @@ O.equip(new_spawn, FALSE, new_spawn.client) SSjob.equip_loadout(null, new_spawn, FALSE) SSquirks.AssignQuirks(new_spawn, new_spawn.client, TRUE, TRUE, null, FALSE, new_spawn) + new_spawn.AddElement(/datum/element/ghost_role_eligibility) + ADD_TRAIT(new_spawn, TRAIT_SIXTHSENSE, "Ghost Cafe") /datum/outfit/ghostcafe name = "ID, jumpsuit and shoes" diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index 09a8f692d8..7675f858ee 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -137,9 +137,9 @@ /datum/admins/proc/makeWizard() - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for the position of a Wizard Foundation 'diplomat'?", ROLE_WIZARD, null) + var/list/mob/candidates = pollGhostCandidates("Do you wish to be considered for the position of a Wizard Foundation 'diplomat'?", ROLE_WIZARD, null) - var/mob/dead/observer/selected = pick_n_take(candidates) + var/mob/selected = pick_n_take(candidates) var/mob/living/carbon/human/new_character = makeBody(selected) new_character.mind.make_Wizard() @@ -214,9 +214,9 @@ /datum/admins/proc/makeNukeTeam() var/datum/game_mode/nuclear/temp = new - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for a nuke team being sent in?", ROLE_OPERATIVE, temp) - var/list/mob/dead/observer/chosen = list() - var/mob/dead/observer/theghost = null + var/list/mob/candidates = pollGhostCandidates("Do you wish to be considered for a nuke team being sent in?", ROLE_OPERATIVE, temp) + var/list/mob/chosen = list() + var/mob/theghost = null if(candidates.len) var/numagents = 5 @@ -378,7 +378,7 @@ ertemplate.enforce_human = prefs["enforce_human"]["value"] == "Yes" ? TRUE : FALSE ertemplate.opendoors = prefs["open_armory"]["value"] == "Yes" ? TRUE : FALSE - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for [ertemplate.polldesc] ?", "deathsquad", null) + var/list/mob/candidates = pollGhostCandidates("Do you wish to be considered for [ertemplate.polldesc] ?", "deathsquad", null) var/teamSpawned = FALSE if(candidates.len > 0) @@ -404,7 +404,7 @@ numagents-- continue // This guy's unlucky, not enough spawn points, we skip him. var/spawnloc = spawnpoints[numagents] - var/mob/dead/observer/chosen_candidate = pick(candidates) + var/mob/chosen_candidate = pick(candidates) candidates -= chosen_candidate if(!chosen_candidate.key) continue diff --git a/code/modules/antagonists/blob/blob/powers.dm b/code/modules/antagonists/blob/blob/powers.dm index e49d186362..76c9c6f482 100644 --- a/code/modules/antagonists/blob/blob/powers.dm +++ b/code/modules/antagonists/blob/blob/powers.dm @@ -156,7 +156,7 @@ if(!can_buy(40)) return - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as a [blob_reagent_datum.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50) //players must answer rapidly + var/list/mob/candidates = pollGhostCandidates("Do you want to play as a [blob_reagent_datum.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50) //players must answer rapidly if(LAZYLEN(candidates)) //if we got at least one candidate, they're a blobbernaut now. B.max_integrity = initial(B.max_integrity) * 0.25 //factories that produced a blobbernaut have much lower health B.obj_integrity = min(B.obj_integrity, B.max_integrity) @@ -171,7 +171,7 @@ blobber.update_icons() blobber.adjustHealth(blobber.maxHealth * 0.5) blob_mobs += blobber - var/mob/dead/observer/C = pick(candidates) + var/mob/C = pick(candidates) C.transfer_ckey(blobber) SEND_SOUND(blobber, sound('sound/effects/blobattack.ogg')) SEND_SOUND(blobber, sound('sound/effects/attackblob.ogg')) diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index ae9932e96f..361b2a7517 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -80,7 +80,3 @@ var/next_keysend_reset = 0 var/next_keysend_trip_reset = 0 var/keysend_tripped = FALSE - - // stops players from coming back through ghost/midround roles after suicide/cryo - // for a duration set by CONFIG_GET(number/suicide_reenter_round_timer) and CONFIG_GET(number/roundstart_suicide_time_limit) - var/reenter_round_timeout = 0 diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm index 65d96ad150..ea63ee611f 100644 --- a/code/modules/events/holiday/xmas.dm +++ b/code/modules/events/holiday/xmas.dm @@ -75,7 +75,7 @@ /datum/round_event/santa/start() var/list/candidates = pollGhostCandidates("Santa is coming to town! Do you want to be Santa?", poll_time=150) if(LAZYLEN(candidates)) - var/mob/dead/observer/C = pick(candidates) + var/mob/C = pick(candidates) santa = new /mob/living/carbon/human(pick(GLOB.blobstart)) C.transfer_ckey(santa, FALSE) diff --git a/code/modules/mob/dead/observer/login.dm b/code/modules/mob/dead/observer/login.dm index bf86a97574..1b328dbc69 100644 --- a/code/modules/mob/dead/observer/login.dm +++ b/code/modules/mob/dead/observer/login.dm @@ -18,6 +18,3 @@ update_icon(preferred_form) updateghostimages() - - client.reenter_round_timeout = max(client.reenter_round_timeout, clientless_round_timeout) - clientless_round_timeout = client.reenter_round_timeout diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 499236e8ac..72d68c6721 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -19,7 +19,6 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) hud_type = /datum/hud/ghost movement_type = GROUND | FLYING var/can_reenter_corpse - var/clientless_round_timeout = 0 //mobs will lack a client as long as their player is disconnected. See client_defines.dm "reenter_round_timeout" var/datum/hud/living/carbon/hud = null // hud var/bootime = 0 var/started_as_observer //This variable is set to 1 when you enter the game as an observer. @@ -135,7 +134,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) AA.onNewMob(src) . = ..() - + AddElement(/datum/element/ghost_role_eligibility) grant_all_languages() /mob/dead/observer/get_photo_description(obj/item/camera/camera) @@ -270,20 +269,9 @@ Works together with spawning an observer, noted above. var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc. SStgui.on_transfer(src, ghost) // Transfer NanoUIs. ghost.can_reenter_corpse = can_reenter_corpse - if(penalize) //penalizing them from making a ghost role / midround antag comeback right away. - var/penalty = CONFIG_GET(number/suicide_reenter_round_timer) MINUTES - var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES - if(world.time < roundstart_quit_limit) //add up the time difference to their antag rolling penalty if they quit before half a (ingame) hour even passed. - penalty += roundstart_quit_limit - world.time - if(penalty) - penalty += world.realtime - if(penalty - SSshuttle.realtimeofstart > SSshuttle.auto_call + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime) - penalty = CANT_REENTER_ROUND - if(client) - client.reenter_round_timeout = penalty - else //A disconnected player (quite likely for cryopods) - ghost.clientless_round_timeout = penalty transfer_ckey(ghost, FALSE) + ghost.AddElement(/datum/element/ghost_role_eligibility,penalize) // technically already run earlier, but this adds the penalty + // needs to be done AFTER the ckey transfer, too return ghost /* @@ -340,15 +328,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return ghostize(0, penalize = TRUE) -/mob/dead/observer/proc/can_reenter_round(silent = FALSE) - var/timeout = clientless_round_timeout - if(client) - timeout = client.reenter_round_timeout - if(timeout != CANT_REENTER_ROUND && timeout <= world.realtime) - return TRUE - if(!silent && client) - to_chat(src, "You are unable to reenter the round[timeout != CANT_REENTER_ROUND ? " yet. Your ghost role blacklist will expire in [DisplayTimeText(timeout - world.realtime)]" : ""].") - return FALSE + /mob/dead/observer/Move(NewLoc, direct) if(updatedir) diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index 1bd434b233..62c8588ac8 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -424,9 +424,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians var/mob/living/simple_animal/hostile/guardian/G = input(src, "Pick the guardian you wish to reset", "Guardian Reset") as null|anything in guardians if(G) to_chat(src, "You attempt to reset [G.real_name]'s personality...") - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as [src.real_name]'s [G.real_name]?", ROLE_PAI, null, FALSE, 100) + var/list/mob/candidates = pollGhostCandidates("Do you want to play as [src.real_name]'s [G.real_name]?", ROLE_PAI, null, FALSE, 100) if(LAZYLEN(candidates)) - var/mob/dead/observer/C = pick(candidates) + var/mob/C = pick(candidates) to_chat(G, "Your user reset you, and your body was taken over by a ghost. Looks like they weren't happy with your performance.") to_chat(src, "Your [G.real_name] has been successfully reset.") message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(G)])") @@ -498,10 +498,10 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians return used = TRUE to_chat(user, "[use_message]") - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the [mob_name] of [user.real_name]?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_HOLOPARASITE) + var/list/mob/candidates = pollGhostCandidates("Do you want to play as the [mob_name] of [user.real_name]?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_HOLOPARASITE) if(LAZYLEN(candidates)) - var/mob/dead/observer/C = pick(candidates) + var/mob/C = pick(candidates) spawn_guardian(user, C.key) else to_chat(user, "[failure_message]") diff --git a/tgstation.dme b/tgstation.dme index 5526e5eaf0..9348e2e131 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -467,6 +467,7 @@ #include "code\datums\elements\_element.dm" #include "code\datums\elements\cleaning.dm" #include "code\datums\elements\earhealing.dm" +#include "code\datums\elements\ghost_role_eligibility.dm" #include "code\datums\helper_datums\events.dm" #include "code\datums\helper_datums\getrev.dm" #include "code\datums\helper_datums\icon_snapshot.dm"