#define CRYO_DESTROY 0 #define CRYO_PRESERVE 1 #define CRYO_OBJECTIVE 2 /* * Cryogenic refrigeration unit. Basically a despawner. * Stealing a lot of concepts/code from sleepers due to massive laziness. * The despawn tick will only fire if it's been more than time_till_despawned ticks * since time_entered, which is world.time when the occupant moves in. * ~ Zuhayr */ //Main cryopod console. /obj/machinery/computer/cryopod name = "cryogenic oversight console" desc = "An interface between crew and the cryogenic storage oversight systems." icon = 'icons/obj/cryogenic2.dmi' icon_state = "cellconsole" circuit = /obj/item/circuitboard/cryopodcontrol density = FALSE interact_offline = TRUE req_one_access = list(ACCESS_HEADS, ACCESS_ARMORY) //Heads of staff or the warden can go here to claim recover items from their department that people went were cryodormed with. resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF flags = NODECONSTRUCT flags_2 = NO_MALF_EFFECT_2 var/mode = null icon_screen = "cellconsole_on" //Used for logging people entering cryosleep and important items they are carrying. var/list/frozen_crew = list() var/list/frozen_items = list() // Used for containing rare items traitors need to steal, so it's not // game-over if they get iced var/list/objective_items = list() // A cache of theft datums so you don't have to re-create them for // each item check var/list/theft_cache = list() var/storage_type = "crewmembers" var/storage_name = "Cryogenic Oversight Control" var/allow_items = TRUE /obj/machinery/computer/cryopod/Initialize(mapload) . = ..() for(var/T in GLOB.potential_theft_objectives) theft_cache += new T /obj/machinery/computer/cryopod/attack_ai(mob/user) return attack_hand(user) /obj/machinery/computer/cryopod/attack_ghost(mob/user) ui_interact(user) /obj/machinery/computer/cryopod/attack_hand(mob/user) if(..()) return TRUE add_fingerprint(user) ui_interact(user) /obj/machinery/computer/cryopod/ui_state(mob/user) return GLOB.default_state /obj/machinery/computer/cryopod/ui_interact(mob/user, datum/tgui/ui = null) ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "CryopodConsole", name) ui.open() /obj/machinery/computer/cryopod/ui_data(mob/user) var/list/data = list() data["allow_items"] = allow_items data["frozen_crew"] = frozen_crew data["frozen_items"] = list() if(allow_items) data["frozen_items"] = frozen_items if(!ishuman(user)) return data var/obj/item/card/id/id_card var/mob/living/carbon/human/person = user id_card = person.get_idcard() if(id_card?.registered_name) data["account_name"] = id_card.registered_name return data /obj/machinery/computer/cryopod/ui_act(action, params, datum/tgui/ui) if(..()) return if(stat & (NOPOWER|BROKEN)) return var/mob/user = ui.user add_fingerprint(user) if(!allowed(user)) to_chat(user, SPAN_WARNING("Access Denied.")) return if(!allow_items) return switch(action) if("one_item") if(!params["item"]) return var/obj/item/item = locateUID(params["item"]) if(!item || item.loc != src) to_chat(user, SPAN_NOTICE("[item] is no longer in storage.")) return visible_message(SPAN_NOTICE("[src] beeps happily as it dispenses [item].")) dispense_item(item) if("all_items") visible_message(SPAN_NOTICE("[src] beeps happily as it dispenses the desired objects.")) for(var/list/frozen_item in frozen_items) var/obj/item/item = locateUID(frozen_item["uid"]) dispense_item(item) return TRUE /obj/machinery/computer/cryopod/proc/freeze_item(obj/item/I, preserve_status) var/list/item = list() item["uid"] = I.UID() item["name"] = I.name frozen_items += list(item) if(preserve_status == CRYO_OBJECTIVE || istype(I, /obj/item/card/id/captains_spare)) objective_items += I I.forceMove(src) RegisterSignal(I, COMSIG_MOVABLE_MOVED, PROC_REF(item_got_removed)) /obj/machinery/computer/cryopod/proc/item_got_removed(obj/item/I) objective_items -= I for(var/list/sublist in frozen_items) if(sublist["uid"] != I.UID()) continue frozen_items -= list(sublist) UnregisterSignal(I, COMSIG_MOVABLE_MOVED) /obj/machinery/computer/cryopod/proc/dispense_item(obj/item/I) I.forceMove(get_turf(src)) // Will call item_got_removed due to the signal being registered to COMSIG_MOVABLE_MOVED /obj/machinery/computer/cryopod/emag_act(mob/user) user.changeNext_move(CLICK_CD_MELEE) if(!length(objective_items)) visible_message(SPAN_WARNING("The console buzzes in an annoyed manner.")) playsound(src, 'sound/machines/buzz-sigh.ogg', 30, 1) return visible_message(SPAN_WARNING("The console sparks, and some items fall out!")) do_sparks(5, TRUE, src) for(var/obj/item/I in objective_items) dispense_item(I) return TRUE /obj/item/circuitboard/cryopodcontrol board_name = "Cryogenic Oversight Console" build_path = "/obj/machinery/computer/cryopod" origin_tech = "programming=1" /obj/item/circuitboard/robotstoragecontrol board_name = "Robotic Storage Console" build_path = "/obj/machinery/computer/cryopod/robot" origin_tech = "programming=1" //Cryopods themselves. /obj/machinery/cryopod name = "cryogenic freezer" desc = "A man-sized pod for entering suspended animation." icon = 'icons/obj/cryogenic2.dmi' icon_state = "bodyscanner-open" density = TRUE anchored = TRUE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF flags = NODECONSTRUCT flags_2 = NO_MALF_EFFECT_2 dir = WEST base_icon_state = "bodyscanner-open" var/occupied_icon_state = "bodyscanner" var/on_store_message = "has entered long-term storage." var/on_store_name = "Cryogenic Oversight" var/on_enter_occupant_message = "You feel cool air surround you. You go numb as your senses turn inward." var/allow_occupant_types = list(/mob/living/carbon/human) var/disallow_occupant_types = list() var/mob/living/occupant = null // Person waiting to be despawned. var/obj/effect/occupant_overlay = null // 15 minutes-ish safe period before being despawned. var/time_till_despawn = 9000 // This is reduced by 90% if a player manually enters cryo var/willing_time_divisor = 10 var/time_entered = 0 // Used to keep track of the safe period. var/obj/item/radio/intercom/announce var/silent = FALSE var/console_type = /obj/machinery/computer/cryopod // The type of control console it should link itself to var/obj/machinery/computer/cryopod/control_computer var/last_no_computer_message = 0 // These items are preserved when the process() despawn proc occurs. var/list/preserve_items = list( /obj/item/hand_tele, /obj/item/card/id/captains_spare, /obj/item/aicard, /obj/item/mmi, /obj/item/paicard, /obj/item/gun, /obj/item/pinpointer, /obj/item/clothing/shoes/magboots, /obj/item/areaeditor/blueprints, /obj/item/clothing/head/helmet/space, /obj/item/clothing/suit/space, /obj/item/clothing/suit/armor, /obj/item/defibrillator/compact, /obj/item/reagent_containers/hypospray/cmo, /obj/item/clothing/accessory/medal/gold/captain, /obj/item/clothing/gloves/color/black/krav_maga/sec, /obj/item/nullrod, /obj/item/key, /obj/item/door_remote, /obj/item/autopsy_scanner, /obj/item/holosign_creator/atmos, /obj/item/clothing/gloves/color/black/forensics, /obj/item/mod/control, /obj/item/stamp, /obj/item/melee/knuckleduster/nanotrasen, /obj/item/melee/saber, /obj/item/storage/belt/sheath/saber, /obj/item/nuke_core, /obj/item/nuke_core_container, /obj/item/documents, /obj/item/clothing/gloves/color/black/krav_maga ) // These items will NOT be preserved var/list/do_not_preserve_items = list ( /obj/item/mmi/robotic_brain, /obj/item/card/id/captains_spare/assigned, /obj/item/gun/energy/laser/mounted, /obj/item/gun/energy/gun/advtaser/mounted, /obj/item/gun/magic/grapple, ) /obj/machinery/cryopod/right dir = EAST /obj/machinery/cryopod/Initialize(mapload) . = ..() announce = new /obj/item/radio/intercom(src) announce.follow_target = src icon_state = base_icon_state find_control_computer() /obj/machinery/cryopod/proc/find_control_computer(urgent=0) var/area/our_area = get_area(src) for(var/obj/machinery/computer/cryopod/C in our_area) if(C.type == console_type) control_computer = C break // Don't send messages unless we *need* the computer, and less than five minutes have passed since last time we messaged if(!control_computer && urgent && last_no_computer_message + 5*60*10 < world.time) log_admin("Cryopod in [loc.loc] could not find control computer!") message_admins("Cryopod in [loc.loc] could not find control computer!") last_no_computer_message = world.time return control_computer != null // So the user can use movement keys to get out of the cryopod /obj/machinery/cryopod/relaymove(mob/user) if(user.incapacitated()) return FALSE go_out() /obj/machinery/cryopod/proc/check_occupant_allowed(mob/M) var/correct_type = 0 for(var/type in allow_occupant_types) if(istype(M, type)) correct_type = 1 break if(!correct_type) return 0 for(var/type in disallow_occupant_types) if(istype(M, type)) return 0 return 1 //Lifted from Unity stasis.dm and refactored. ~Zuhayr /obj/machinery/cryopod/process() if(occupant) // Eject dead people if(occupant.stat == DEAD) go_out() return // Allow a gap between entering the pod and actually despawning. if(world.time - time_entered < time_till_despawn) return if(!occupant.client && occupant.stat<2) //Occupant is living and has no client. if(!control_computer) if(!find_control_computer(urgent=1)) return despawn_occupant() /obj/machinery/cryopod/proc/should_preserve_item(obj/item/I) for(var/datum/theft_objective/T in control_computer.theft_cache) if(istype(I, T.typepath) && T.check_special_completion(I)) return CRYO_OBJECTIVE for(var/T in preserve_items) if(istype(I, T) && !(I.type in do_not_preserve_items)) return CRYO_PRESERVE return CRYO_DESTROY /obj/machinery/cryopod/proc/handle_contents(obj/item/I) if(length(I.contents)) //Make sure we catch anything not handled by qdel() on the items. if(should_preserve_item(I) != CRYO_DESTROY) // Don't remove the contents of things that need preservation return for(var/obj/item/O in I.contents) if(istype(O, /obj/item/tank)) //Stop eating pockets, you fuck! continue handle_contents(O) O.forceMove(src) /obj/machinery/cryopod/proc/despawn_occupant() //Drop all items into the pod. for(var/obj/item/I in occupant) occupant.transfer_item_to(I, src) handle_contents(I) //Delete all items not on the preservation list. var/list/items = contents items -= occupant // Don't delete the occupant // this fucking nullspaces the occupant btw, i fuckin hate old code items -= announce // or the autosay radio. ADD_TRAIT(occupant, TRAIT_CRYO_DESPAWNING, TRAIT_GENERIC) for(var/obj/item/I in items) if(istype(I, /obj/item/pda)) var/obj/item/pda/P = I P.id = null qdel(P) continue if(istype(I, /obj/item/storage/backpack/modstorage)) //Best place for me to put it. var/obj/item/storage/backpack/modstorage/M = I M.forceMove(M.source) continue var/preserve = should_preserve_item(I) if(preserve == CRYO_DESTROY) qdel(I) else if(control_computer && control_computer.allow_items) control_computer.freeze_item(I, preserve) else I.forceMove(loc) // Find a new sacrifice target if needed, if unable allow summoning if(IS_SACRIFICE_TARGET(occupant.mind)) SSticker.mode.cult_team.find_new_sacrifice_target() SSticker.mode.on_mob_cryo(occupant, src) //Update any existing objectives involving this mob. if(occupant.mind) if(occupant.mind.initial_account) GLOB.station_money_database.delete_user_account(occupant.mind.initial_account.account_number, "NAS Trurl Financial Services", FALSE) for(var/datum/objective/O in GLOB.all_objectives) if(O.target != occupant.mind) continue O.on_target_cryo() occupant.mind.remove_all_antag_datums(handle_target_cryo = TRUE) // i wish cryo used signals, this is scuffed if(occupant.mind && occupant.mind.assigned_role) //Handle job slot/tater cleanup. var/job = occupant.mind.assigned_role SSjobs.FreeRole(job) if(occupant.mind.objective_holder.clear()) occupant.mind.special_role = null // Delete them from datacore. var/announce_rank = null if(length(GLOB.PDA_Manifest)) GLOB.PDA_Manifest.Cut() for(var/datum/data/record/R in GLOB.data_core.medical) if(R.fields["name"] == occupant.real_name) qdel(R) for(var/datum/data/record/T in GLOB.data_core.security) if(T.fields["name"] == occupant.real_name) qdel(T) for(var/datum/data/record/G in GLOB.data_core.general) if(G.fields["name"] == occupant.real_name) announce_rank = G.fields["rank"] qdel(G) GLOB.crew_list -= occupant.real_name icon_state = base_icon_state //Make an announcement and log the person entering storage + their rank var/list/crew_member = list() crew_member["name"] = occupant.real_name if(announce_rank) crew_member["rank"] = announce_rank else crew_member["rank"] = "N/A" control_computer.frozen_crew += list(crew_member) if(!silent) var/list/ailist = list() for(var/thing in GLOB.ai_list) var/mob/living/silicon/ai/AI = thing if(AI.stat) continue ailist += AI if(length(ailist)) var/mob/living/silicon/ai/announcer = pick(ailist) if(announce_rank) announcer.say(";[occupant.real_name] ([announce_rank]) [on_store_message]", ignore_languages = TRUE, automatic = TRUE) else announcer.say(";[occupant.real_name] [on_store_message]", ignore_languages = TRUE, automatic = TRUE) else if(announce_rank) announce.autosay("[occupant.real_name] ([announce_rank]) [on_store_message]", "[on_store_name]") else if(announce_rank) announce.autosay("[occupant.real_name] ([announce_rank]) [on_store_message]", "[on_store_name]") else announce.autosay("[occupant.real_name] [on_store_message]", "[on_store_name]") visible_message(SPAN_NOTICE("[src] hums and hisses as it moves [occupant.real_name] into storage.")) // Ghost and delete the mob. if(!occupant.get_ghost(TRUE)) if(TOO_EARLY_TO_GHOST) occupant.ghostize(GHOST_FLAGS_OBSERVE_ONLY) // Players despawned too early may not re-enter the game else occupant.ghostize() QDEL_NULL(occupant) name = initial(name) update_icon(UPDATE_OVERLAYS) /obj/machinery/cryopod/item_interaction(mob/living/user, obj/item/used, list/modifiers) var/obj/item/grab/G = used if(!istype(G)) return ..() if(occupant) to_chat(user, SPAN_NOTICE("[src] is in use.")) return ITEM_INTERACT_COMPLETE if(!ismob(G.affecting)) return ITEM_INTERACT_COMPLETE if(!check_occupant_allowed(G.affecting)) return ITEM_INTERACT_COMPLETE var/willing = null //We don't want to allow people to be forced into despawning. var/mob/living/M = G.affecting time_till_despawn = initial(time_till_despawn) if(!istype(M) || M.stat == DEAD) to_chat(user, SPAN_NOTICE("Dead people can not be put into cryo.")) return ITEM_INTERACT_COMPLETE if(M.client) if(tgui_alert(M, "Would you like to enter long-term storage?", "Cryosleep", list("Yes", "No")) == "Yes") if(!M || !G || !G.affecting) return ITEM_INTERACT_COMPLETE willing = willing_time_divisor else willing = 1 if(willing) visible_message("[user] starts putting [G.affecting.name] into [src].") if(do_after(user, 20, target = G.affecting)) if(!M || !G || !G.affecting) return ITEM_INTERACT_COMPLETE if(occupant) to_chat(user, SPAN_BOLDNOTICE("[src] is in use.")) return ITEM_INTERACT_COMPLETE take_occupant(M, willing) else //because why the fuck would you keep going if the mob isn't in the pod to_chat(user, SPAN_NOTICE("You stop putting [M] into the cryopod.")) return ITEM_INTERACT_COMPLETE icon_state = occupied_icon_state M.throw_alert("cryopod", /atom/movable/screen/alert/ghost/cryo) to_chat(M, SPAN_NOTICE("[on_enter_occupant_message]")) to_chat(M, SPAN_BOLDNOTICE("If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.")) take_occupant(M, willing) return ITEM_INTERACT_COMPLETE /obj/machinery/cryopod/MouseDrop_T(atom/movable/O as mob|obj, mob/user as mob) if(O.loc == user) //no you can't pull things out of your ass return if(user.incapacitated()) //are you cuffed, dying, lying, stunned or other return if(get_dist(user, src) > 1 || get_dist(user, O) > 1 || user.contents.Find(src)) // is the mob anchored, too far away from you, or are you too far away from the source return if(!ismob(O)) //humans only return if(!check_occupant_allowed(O)) return if(!ishuman(user) && !isrobot(user)) //No ghosts or mice putting people into the sleeper return if(user.loc==null) // just in case someone manages to get a closet into the blue light dimension, as unlikely as that seems return if(!isturf(user.loc) || !isturf(O.loc)) // are you in a container/closet/pod/etc? return if(occupant) to_chat(user, SPAN_BOLDNOTICE("The cryo pod is already occupied!")) return TRUE var/mob/living/L = O if(!istype(L) || L.buckled) return if(L.stat == DEAD) to_chat(user, SPAN_NOTICE("Dead people can not be put into cryo.")) return TRUE if(L.has_buckled_mobs()) //mob attached to us to_chat(user, SPAN_WARNING("[L] will not fit into [src] because [L.p_they()] [L.p_have()] a slime latched onto [L.p_their()] head.")) INVOKE_ASYNC(src, TYPE_PROC_REF(/obj/machinery/cryopod, put_in), user, L) return TRUE /obj/machinery/cryopod/proc/put_in(mob/user, mob/living/L) // need this proc to use INVOKE_ASYNC in other proc. You're not recommended to use that one var/willing = null //We don't want to allow people to be forced into despawning. time_till_despawn = initial(time_till_despawn) if(L.client) if(tgui_alert(L, "Would you like to enter cryosleep?", "Cryosleep", list("Yes", "No")) == "Yes") if(!L) return willing = willing_time_divisor else willing = 1 if(willing) if(!Adjacent(L) && !Adjacent(user)) to_chat(user, SPAN_BOLDNOTICE("You're not close enough to [src].")) return TRUE if(L == user) visible_message("[user] starts climbing into the cryo pod.") else visible_message("[user] starts putting [L] into the cryo pod.") if(do_after(user, 20, target = L)) if(!L) return TRUE if(occupant) to_chat(user, SPAN_BOLDNOTICE("\The [src] is in use.")) return TRUE take_occupant(L, willing) else to_chat(user, SPAN_NOTICE("You stop [L == user ? "climbing into the cryo pod." : "putting [L] into the cryo pod."]")) /obj/machinery/cryopod/proc/take_occupant(mob/living/carbon/E, willing_factor = 1) if(occupant) return if(!E) return QDEL_LIST_CONTENTS(E.grabbed_by) E.forceMove(src) time_till_despawn = initial(time_till_despawn) / willing_factor icon_state = occupied_icon_state to_chat(E, SPAN_NOTICE("[on_enter_occupant_message]")) to_chat(E, SPAN_BOLDNOTICE("If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.")) E.throw_alert("cryopod", /atom/movable/screen/alert/ghost/cryo) occupant = E name = "[name] ([occupant.name])" time_entered = world.time if(findtext("[E.key]","@",1,2)) var/FT = replacetext(E.key, "@", "") for(var/mob/dead/observer/Gh in GLOB.player_list) //this may not be foolproof but it seemed like a better option than 'in world' if(Gh.key == FT) if(Gh.client && Gh.client.holder) //just in case someone has a byond name with @ at the start, which I don't think is even possible but whatever to_chat(Gh, "Warning: Your body has entered cryostorage.") log_admin("[key_name(E)] entered a stasis pod.") if(SSticker.mode.tdm_gamemode) SSblackbox.record_feedback("nested tally", "TDM_quitouts", 1, list(SSticker.mode.name, "TDM Cryopods")) occupant.create_log(MISC_LOG, "entered a stasis pod") message_admins("[key_name_admin(E)] entered a stasis pod. (JMP)") add_fingerprint(E) playsound(src, 'sound/machines/podclose.ogg', 5) update_icon(UPDATE_OVERLAYS) /obj/machinery/cryopod/proc/go_out() if(!occupant) return occupant.forceMove(get_turf(src)) occupant.clear_alert("cryopod") log_admin("[key_name(occupant)] exited a stasis pod.") occupant.create_log(MISC_LOG, "exited a stasis pod") if(isAntag(occupant)) message_admins("[key_name_admin(occupant)] antag exited a stasis pod after [round((world.time - time_entered )/(1 MINUTES), 0.2)] minutes inside [ADMIN_JMP(src)]" ) occupant = null icon_state = base_icon_state name = initial(name) playsound(src, 'sound/machines/podopen.ogg', 5) update_icon(UPDATE_OVERLAYS) /obj/machinery/cryopod/update_overlays() . = ..() if(occupant_overlay) QDEL_NULL(occupant_overlay) if(!occupant) return occupant_overlay = new(get_turf(src)) occupant_overlay.icon = occupant.icon occupant_overlay.icon_state = occupant.icon_state occupant_overlay.overlays = occupant.overlays occupant_overlay.dir = dir occupant_overlay.layer = layer + 0.01 var/matrix/MA = matrix(transform) if(dir == NORTH) MA.TurnTo(0, 180) occupant_overlay.dir = SOUTH // trust me if(dir == EAST) MA.TurnTo(0, 270) occupant_overlay.pixel_y = -8 if(dir == WEST) MA.TurnTo(0 , 90) occupant_overlay.pixel_y = -8 MA.Scale(0.66, 0.66) occupant_overlay.transform = MA var/mutable_appearance/rim = mutable_appearance(icon = icon, icon_state = "bodyscanner_first_overlay", layer = occupant_overlay.layer + 0.01) var/mutable_appearance/lid = mutable_appearance(icon = icon, icon_state = "bodyscanner-lid-nodetail", layer = rim.layer + 0.01, alpha = 140) . += rim . += lid //Attacks/effects. /obj/machinery/cryopod/blob_act() return //Sorta gamey, but we don't really want these to be destroyed. /obj/machinery/cryopod/force_eject_occupant(mob/target) go_out() /obj/machinery/cryopod/offstation // Won't announce when used for cryoing. silent = TRUE /obj/machinery/cryopod/offstation/right dir = EAST /obj/machinery/computer/cryopod/robot name = "robotic storage console" desc = "An interface between crew and the robotic storage systems." icon = 'icons/obj/robot_storage.dmi' icon_state = "console" circuit = /obj/item/circuitboard/robotstoragecontrol storage_type = "cyborgs" storage_name = "Robotic Storage Control" allow_items = FALSE /obj/machinery/cryopod/robot name = "robotic storage unit" desc = "A storage unit for robots." icon = 'icons/obj/robot_storage.dmi' icon_state = "pod_0" base_icon_state = "pod_0" occupied_icon_state = "pod_1" on_store_message = "has entered robotic storage." on_store_name = "Robotic Storage Oversight" on_enter_occupant_message = "The storage unit broadcasts a sleep signal to you. Your systems start to shut down, and you enter low-power mode." console_type = /obj/machinery/computer/cryopod/robot allow_occupant_types = list(/mob/living/silicon/robot) disallow_occupant_types = list(/mob/living/silicon/robot/drone) /obj/machinery/cryopod/robot/offstation //For offstation cyborgs silent = TRUE /obj/machinery/cryopod/robot/despawn_occupant() var/mob/living/silicon/robot/R = occupant if(!istype(R)) return ..() QDEL_NULL(R.mmi) for(var/obj/item/I in R.module) // the tools the borg has; metal, glass, guns etc for(var/obj/item/O in I) // the things inside the tools, if anything; mainly for janiborg trash bags O.loc = R qdel(I) if(R.module) R.module.remove_subsystems_and_actions(R) qdel(R.module) return ..() /// Teleport an SSD human inside a cryopod, or a robot to a robot storage unit, but do not despawn them. /proc/cryo_ssd(mob/living/person_to_cryo) if(istype(person_to_cryo.loc, /obj/machinery/cryopod)) return FALSE if(isobj(person_to_cryo.loc)) var/obj/O = person_to_cryo.loc O.force_eject_occupant(person_to_cryo) var/list/free_cryopods = list() for(var/obj/machinery/cryopod/P in SSmachines.get_by_type(/obj/machinery/cryopod)) if(P.occupant) continue if((ishuman(person_to_cryo) && istype(get_area(P), /area/station/public/sleep)) || istype(P, /obj/machinery/cryopod/robot)) free_cryopods += P var/obj/machinery/cryopod/target_cryopod = null if(length(free_cryopods)) target_cryopod = safepick(free_cryopods) if(target_cryopod.check_occupant_allowed(person_to_cryo)) var/turf/T = get_turf(person_to_cryo) var/obj/effect/portal/SP = new /obj/effect/portal(T, null, null, 40, create_sparks = FALSE) SP.name = "NT SSD Teleportation Portal" target_cryopod.take_occupant(person_to_cryo, 1) return TRUE return FALSE /// Immeditely teleport a human or robot to cryo and then despawn them. /proc/force_cryo(mob/living/person_to_cryo) if(!ishuman(person_to_cryo) && !isrobot(person_to_cryo)) return if(!istype(person_to_cryo.loc, /obj/machinery/cryopod)) cryo_ssd(person_to_cryo) if(istype(person_to_cryo.loc, /obj/machinery/cryopod)) var/obj/machinery/cryopod/P = person_to_cryo.loc P.despawn_occupant() #undef CRYO_DESTROY #undef CRYO_PRESERVE #undef CRYO_OBJECTIVE