#define AHELP_FIRST_MESSAGE "Please adminhelp before leaving the round, even if there are no administrators online!" /* * 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 */ GLOBAL_LIST_EMPTY(cryopod_computers) //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_1" icon_keyboard = null circuit = /obj/item/circuitboard/cryopodcontrol density = FALSE interaction_flags_machine = INTERACT_MACHINE_OFFLINE 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. var/mode = null // Used for logging people entering cryosleep and important items they are carrying. var/list/frozen_crew = list() var/list/stored_packages = list() /// Does this console store items? if NOT, will dump all items when the user cryo's instead var/allow_items = TRUE var/storage_type = "crewmembers" var/storage_name = "Cryogenic Oversight Control" /obj/machinery/computer/cryopod/deconstruct() . = ..() for(var/i in stored_packages) var/obj/O = i O.forceMove(drop_location()) /obj/machinery/computer/cryopod/Initialize() . = ..() GLOB.cryopod_computers += src /obj/machinery/computer/cryopod/Destroy() GLOB.cryopod_computers -= src return ..() /obj/machinery/computer/cryopod/update_icon_state() if(stat & (NOPOWER|BROKEN)) icon_state = "cellconsole" return ..() icon_state = "cellconsole_1" return ..() /obj/machinery/computer/cryopod/ui_interact(mob/user, datum/tgui/ui) if(stat & (NOPOWER|BROKEN)) return add_fingerprint(user) 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["frozen_crew"] = frozen_crew var/list/item_meta = list() for(var/obj/item/storage/box/blue/cryostorage_items/O as anything in stored_packages) item_meta += list(list("name" = O.real_name, "ref" = REF(O))) // i am truely livid about byond lists data["item_meta"] = item_meta var/obj/item/card/id/id_card var/datum/bank_account/current_user if(isliving(user)) var/mob/living/person = user id_card = person.get_idcard() if(id_card?.registered_account) current_user = id_card.registered_account if(current_user) data["account_name"] = current_user.account_holder // i do not know why but this uses budget? return data /obj/machinery/computer/cryopod/ui_act(action, params) if(..()) return if(action == "item") if(!allowed(usr) && !(obj_flags & EMAGGED)) to_chat(usr, "Access Denied.") playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) return if(!allow_items) return if(stored_packages.len == 0) to_chat(usr, "There is nothing to recover from storage.") playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) return var/obj/I = locate(params["item"]) playsound(src, "terminal_type", 25, 0) if(!I) return if(!(I in stored_packages)) to_chat(usr, "\The [I] is no longer in storage.") playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) return visible_message("The console beeps happily as it disgorges \the [I].") playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) I.forceMove(drop_location()) if(usr && Adjacent(usr) && usr.can_hold_items()) usr.put_in_hands(I) stored_packages -= I // Cryopods themselves. /obj/machinery/cryopod name = "cryogenic freezer" desc = "Suited for Cyborgs and Humanoids, the pod is a safe place for personnel affected by the Space Sleep Disorder to get some rest." icon = 'icons/obj/cryogenic2.dmi' icon_state = "cryopod-open" density = TRUE anchored = TRUE state_open = TRUE var/on_store_message = "has entered long-term storage." var/on_store_name = "Cryogenic Oversight" /// Time until despawn when a mob enters a cryopod. You can cryo other people in pods. var/time_till_despawn = 30 SECONDS /// Cooldown for when it's now safe to try an despawn the player. COOLDOWN_DECLARE(despawn_world_time) ///Weakref to our controller var/datum/weakref/control_computer_weakref COOLDOWN_DECLARE(last_no_computer_message) /obj/machinery/cryopod/Initialize() ..() return INITIALIZE_HINT_LATELOAD //Gotta populate the cryopod computer GLOB first /obj/machinery/cryopod/LateInitialize() update_icon() find_control_computer() // This is not a good situation /obj/machinery/cryopod/Destroy() control_computer_weakref = null return ..() /obj/machinery/cryopod/proc/find_control_computer(urgent = FALSE) for(var/cryo_console as anything in GLOB.cryopod_computers) var/obj/machinery/computer/cryopod/console = cryo_console if(get_area(console) == get_area(src)) control_computer_weakref = WEAKREF(console) 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_weakref && urgent && COOLDOWN_FINISHED(src, last_no_computer_message)) COOLDOWN_START(src, last_no_computer_message, 5 MINUTES) log_admin("Cryopod in [get_area(src)] could not find control computer!") message_admins("Cryopod in [get_area(src)] could not find control computer!") last_no_computer_message = world.time return control_computer_weakref != null /obj/machinery/cryopod/close_machine(atom/movable/target) if(!control_computer_weakref) find_control_computer(TRUE) if((isnull(target) || isliving(target)) && state_open && !panel_open) ..(target) var/mob/living/mob_occupant = occupant investigate_log("Cryogenics machine closed with occupant [key_name(occupant)] by user [key_name(target)].", INVESTIGATE_CRYOGENICS) if(mob_occupant && mob_occupant.stat != DEAD) to_chat(occupant, span_notice("You feel cool air surround you. You go numb as your senses turn inward.")) COOLDOWN_START(src, despawn_world_time, time_till_despawn) icon_state = "cryopod" /obj/machinery/cryopod/open_machine() if(occupant) investigate_log("Cryogenics machine opened with occupant [key_name(occupant)] inside.", INVESTIGATE_CRYOGENICS) ..() icon_state = "cryopod-open" density = TRUE name = initial(name) /obj/machinery/cryopod/container_resist(mob/living/user) investigate_log("Cryogenics machine container resisted by [key_name(user)] with occupant [key_name(occupant)].", INVESTIGATE_CRYOGENICS) visible_message(span_notice("[occupant] emerges from [src]!"), span_notice("You climb out of [src]!")) open_machine() /obj/machinery/cryopod/relaymove(mob/user) container_resist(user) /obj/machinery/cryopod/process() if(!occupant) return var/mob/living/mob_occupant = occupant if(mob_occupant.stat == DEAD) open_machine() if(!mob_occupant.client && COOLDOWN_FINISHED(src, despawn_world_time)) if(!control_computer_weakref) find_control_computer(urgent = TRUE) despawn_occupant() /obj/machinery/cryopod/proc/handle_objectives() var/mob/living/mob_occupant = occupant // Update any existing objectives involving this mob. for(var/datum/objective/objective in GLOB.objectives) // We don't want revs to get objectives that aren't for heads of staff. Letting // them win or lose based on cryo is silly so we remove the objective. if(istype(objective,/datum/objective/mutiny) && objective.target == mob_occupant.mind) objective.team.objectives -= objective qdel(objective) for(var/datum/mind/mind in objective.team.members) to_chat(mind.current, "
[span_userdanger("Your target is no longer within reach. Objective removed!")]") mind.announce_objectives() else if(istype(objective.target) && objective.target == mob_occupant.mind) if(istype(objective, /datum/objective/contract)) var/datum/antagonist/traitor/affected_traitor = objective.owner.has_antag_datum(/datum/antagonist/traitor) var/datum/contractor_hub/affected_contractor_hub = affected_traitor.contractor_hub for(var/datum/syndicate_contract/affected_contract as anything in affected_contractor_hub.assigned_contracts) if(affected_contract.contract == objective) affected_contract.generate(affected_contractor_hub.assigned_targets) affected_contractor_hub.assigned_targets.Add(affected_contract.contract.target) to_chat(objective.owner.current, "
[span_userdanger("Contract target out of reach. Contract rerolled.")]") break else var/old_target = objective.target objective.target = null if(!objective) return objective.find_target() if(!objective.target && objective.owner) to_chat(objective.owner.current, "
[span_userdanger("Your target is no longer within reach. Objective removed!")]") for(var/datum/antagonist/antag in objective.owner.antag_datums) antag.objectives -= objective if (!objective.team) objective.update_explanation_text() objective.owner.announce_objectives() to_chat(objective.owner.current, "
[span_userdanger("You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!")]") else var/list/objectivestoupdate for(var/datum/mind/objective_owner in objective.get_owners()) to_chat(objective_owner.current, "
[span_userdanger("You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!")]") for(var/datum/objective/update_target_objective in objective_owner.get_all_objectives()) LAZYADD(objectivestoupdate, update_target_objective) objectivestoupdate += objective.team.objectives for(var/datum/objective/update_objective in objectivestoupdate) if(update_objective.target != old_target || !istype(update_objective,objective.type)) continue update_objective.target = objective.target update_objective.update_explanation_text() to_chat(objective.owner.current, "
[span_userdanger("You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!")]") update_objective.owner.announce_objectives() qdel(objective) /obj/machinery/cryopod/proc/should_preserve_item(obj/item/item) for(var/datum/objective_item/steal/possible_item in GLOB.possible_items) if(istype(item, possible_item.targetitem)) return TRUE return FALSE // This function can not be undone; do not call this unless you are sure /obj/machinery/cryopod/proc/despawn_occupant() var/mob/living/mob_occupant = occupant var/list/crew_member = list() crew_member["name"] = mob_occupant.real_name if(mob_occupant.mind) // Handle job slot/tater cleanup. var/job = mob_occupant.mind.assigned_role crew_member["job"] = job SSjob.FreeRole(job) // if(LAZYLEN(mob_occupant.mind.objectives)) // mob_occupant.mind.objectives.Cut() mob_occupant.mind.special_role = null else crew_member["job"] = "N/A" // Delete them from datacore. var/announce_rank = null for(var/datum/data/record/medical_record as anything in GLOB.data_core.medical) if(medical_record.fields["name"] == mob_occupant.real_name) qdel(medical_record) for(var/datum/data/record/security_record as anything in GLOB.data_core.security) if(security_record.fields["name"] == mob_occupant.real_name) qdel(security_record) for(var/datum/data/record/general_record as anything in GLOB.data_core.general) if(general_record.fields["name"] == mob_occupant.real_name) announce_rank = general_record.fields["rank"] qdel(general_record) var/obj/machinery/computer/cryopod/control_computer = control_computer_weakref?.resolve() if(!control_computer) control_computer_weakref = null else control_computer.frozen_crew += list(crew_member) // Make an announcement and log the person entering storage. if(GLOB.announcement_systems.len) var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems) announcer.announce("CRYOSTORAGE", mob_occupant.real_name, announce_rank, list()) visible_message(span_notice("[src] hums and hisses as it moves [mob_occupant.real_name] into storage.")) /* ============================= */ var/list/obj/item/storing = list() var/list/obj/item/destroying = list() var/list/obj/item/destroy_later = list() var/drop_to_ground = !istype(control_computer, /obj/machinery/computer/cryopod) || !control_computer.allow_items var/mind_identity = mob_occupant.mind?.name var/occupant_identity = mob_occupant.real_name if(iscyborg(mob_occupant)) var/mob/living/silicon/robot/R = mob_occupant if(R.mmi?.brain) destroy_later += R.mmi destroy_later += R.mmi.brain for(var/i in R.module) if(!isitem(i)) destroying += i continue var/obj/item/I = i // let's be honest we only care about the trash bag don't beat around the bush if(SEND_SIGNAL(I, COMSIG_CONTAINS_STORAGE)) storing += I.contents for(var/atom/movable/AM in I.contents) AM.forceMove(src) R.module.remove_module(I, TRUE) else if(ishuman(mob_occupant)) var/mob/living/carbon/human/H = mob_occupant if(H.mind && H.client && H.client.prefs && H == H.mind.original_character) H.SaveTCGCards() var/list/gear = list() if(iscarbon(mob_occupant)) // sorry simp-le-mobs deserve no mercy var/mob/living/carbon/C = mob_occupant gear = C.get_all_gear() for(var/obj/item/item_content as anything in gear) if(!istype(item_content) || HAS_TRAIT(item_content, TRAIT_NODROP)) destroying += item_content continue if(item_content.item_flags & (DROPDEL | ABSTRACT)) destroying += item_content continue // destroying stays in mob for a bit item_content.forceMove(src) // WEE WOO SNOWFLAKE TIME if(istype(item_content, /obj/item/pda)) var/obj/item/pda/P = item_content if((P.owner == mind_identity) || (P.owner == occupant_identity)) destroying += P else storing += P else if(istype(item_content, /obj/item/card/id)) var/obj/item/card/id/idcard = item_content if((idcard.registered_name == mind_identity) || (idcard.registered_name == occupant_identity)) destroying += idcard else storing += idcard else storing += item_content // get rid of mobs for(var/mob/living/L in mob_occupant.GetAllContents() - mob_occupant) L.forceMove(drop_location()) if(storing.len) var/obj/item/storage/box/blue/cryostorage_items/O = new /obj/item/storage/box/blue/cryostorage_items O.name = "cryogenic retrieval package: [mob_occupant.real_name]" O.real_name = mob_occupant.real_name for(var/i in storing) var/obj/item/I = i I.forceMove(O) O.forceMove(drop_to_ground ? control_computer.drop_location() : control_computer) if((control_computer == control_computer) && !drop_to_ground) control_computer.stored_packages += O /* ============================= */ // Ghost and delete the mob. // they already did ghost verb var/mob/dead/observer/G = mob_occupant.get_ghost(TRUE) if(G) G.voluntary_ghosted = TRUE // they did not ghost verb else mob_occupant.ghostize(FALSE, penalize = TRUE, voluntary = TRUE, cryo = TRUE) QDEL_LIST(destroying) handle_objectives() QDEL_NULL(occupant) QDEL_LIST(destroy_later) open_machine() name = initial(name) /obj/machinery/cryopod/MouseDrop_T(mob/living/target, mob/user) if(!istype(target) || !can_interact(user) || !target.Adjacent(user) || !ismob(target) || isanimal(target) || !istype(user.loc, /turf) || target.buckled) return if(occupant) to_chat(user, span_notice("[src] is already occupied!")) return if(target.stat == DEAD) to_chat(user, span_notice("Dead people can not be put into cryo.")) return if(user != target && target.client) if(iscyborg(target)) to_chat(user, span_danger("You can't put [target] into [src]. [target.p_theyre(capitalized = TRUE)] online.")) else to_chat(user, span_danger("You can't put [target] into [src]. [target.p_theyre(capitalized = TRUE)] conscious.")) return else if(target.client) // mob has client if(tgalert(target, "Would you like to enter cryosleep?", "Enter Cryopod?", "Yes", "No") != "Yes") return if(target == user && world.time - target.client.cryo_warned > 5 MINUTES) var/list/caught_string var/addendum = "" if(target.mind.assigned_role in GLOB.command_positions) LAZYADD(caught_string, "Head of Staff") addendum = " Be sure to put your locker items back into your locker!" if(iscultist(target) || is_servant_of_ratvar(target)) LAZYADD(caught_string, "Cultist") if(is_devil(target)) LAZYADD(caught_string, "Devil") if(target.mind.has_antag_datum(/datum/antagonist/gang)) LAZYADD(caught_string, "Gangster") if(target.mind.has_antag_datum(/datum/antagonist/rev/head)) LAZYADD(caught_string, "Head Revolutionary") if(target.mind.has_antag_datum(/datum/antagonist/rev)) LAZYADD(caught_string, "Revolutionary") if(caught_string) tgui_alert(target, "You're a [english_list(caught_string)]! [AHELP_FIRST_MESSAGE][addendum]") target.client.cryo_warned = world.time if(!istype(target) || !can_interact(user) || !target.Adjacent(user) || !ismob(target) || isanimal(target) || !istype(user.loc, /turf) || target.buckled) return // rerun the checks in case of shenanigans if(occupant) to_chat(user, span_notice("[src] is already occupied!")) return if(target == user) visible_message("[user] starts climbing into the cryo pod.") else visible_message("[user] starts putting [target] into the cryo pod.") to_chat(target, span_warning("If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.")) log_admin("[key_name(target)] entered a stasis pod.") message_admins("[key_name_admin(target)] entered a stasis pod. [ADMIN_JMP(src)]") add_fingerprint(target) close_machine(target) name = "[name] ([target.name])" // Attacks/effects. /obj/machinery/cryopod/blob_act() return // Sorta gamey, but we don't really want these to be destroyed. #undef AHELP_FIRST_MESSAGE /obj/item/circuitboard/cryopodcontrol name = "Circuit board (Cryogenic Oversight Console)" build_path = /obj/machinery/computer/cryopod /obj/machinery/computer/cryopod/contents_explosion() return /obj/machinery/computer/cryopod/contents_explosion() return //don't blow everyone's shit up. /// The box /obj/item/storage/box/blue/cryostorage_items w_class = WEIGHT_CLASS_HUGE var/real_name = "fire coderbus"