/* * 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_1" 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/menu = 1 //Which menu screen to display //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/allow_items = TRUE /obj/machinery/computer/cryopod/attack_ai() attack_hand() /obj/machinery/computer/cryopod/ui_interact(mob/user = usr) if(!is_operational()) return user.set_machine(src) add_fingerprint(user) var/dat = "" dat += "

Welcome, [user.real_name].


" dat += "

" switch(src.menu) if(1) dat += "View crew storage log

" if(allow_items) dat += "View objects storage log

" dat += "Recover object

" dat += "Recover all objects
" if(2) dat += "<< Back

" dat += "

Recently stored Crew




" if(!frozen_crew.len) dat += "There has been no storage usage at this terminal.
" else for(var/person in frozen_crew) dat += "[person]
" dat += "
" if(3) dat += "<< Back

" dat += "

Recently stored objects




" if(!frozen_items.len) dat += "There has been no storage usage at this terminal.
" else for(var/obj/item/I in frozen_items) dat += "[I.name]
" dat += "
" var/datum/browser/popup = new(user, "cryopod_console", "Cryogenic System Control") popup.set_content(dat) popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) popup.open() /obj/machinery/computer/cryopod/Topic(href, href_list) if(..()) return TRUE var/mob/user = usr add_fingerprint(user) if(href_list["item"]) if(!allowed(user)) to_chat(user, "Access Denied.") playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) updateUsrDialog() return if(!allow_items) return if(frozen_items.len == 0) to_chat(user, "There is nothing to recover from storage.") playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) updateUsrDialog() return var/obj/item/I = input(user, "Please choose which object to retrieve.","Object recovery",null) as null|anything in frozen_items playsound(src, "terminal_type", 25, 0) if(!I) return if(!(I in frozen_items)) to_chat(user, "\The [I] is no longer in storage.") playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) updateUsrDialog() 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(user && Adjacent(user) && !issiliconoradminghost(user)) user.put_in_hands(I) frozen_items -= I updateUsrDialog() else if(href_list["allitems"]) playsound(src, "terminal_type", 25, 0) if(!allowed(user)) to_chat(user, "Access Denied.") playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) updateUsrDialog() return if(!allow_items) return if(frozen_items.len == 0) to_chat(user, "There is nothing to recover from storage.") playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) return visible_message("The console beeps happily as it disgorges the desired objects.") playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) for(var/obj/item/I in frozen_items) I.forceMove(drop_location()) frozen_items -= I updateUsrDialog() else if (href_list["menu"]) src.menu = text2num(href_list["menu"]) playsound(src, "terminal_type", 25, 0) updateUsrDialog() ui_interact(usr) updateUsrDialog() return /obj/item/circuitboard/cryopodcontrol name = "Circuit board (Cryogenic Oversight Console)" build_path = "/obj/machinery/computer/cryopod" /obj/machinery/computer/cryopod/contents_explosion() return //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" // 15 minutes-ish safe period before being despawned. var/time_till_despawn = 15 * 600 // This is reduced by 90% if a player manually enters cryo var/despawn_world_time = null // Used to keep track of the safe period. var/obj/machinery/computer/cryopod/control_computer var/last_no_computer_message = 0 // These items are preserved when the process() despawn proc occurs. var/static/list/preserve_items = typecacheof(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/krav_maga, /obj/item/nullrod, /obj/item/tank/jetpack, /obj/item/documents, /obj/item/nuke_core_container )) // These items will NOT be preserved var/static/list/do_not_preserve_items = typecacheof(list( /obj/item/mmi/posibrain, /obj/item/gun/energy/laser/mounted, /obj/item/gun/energy/e_gun/advtaser/mounted, /obj/item/gun/ballistic/revolver/grenadelauncher/cyborg, /obj/item/gun/energy/disabler/cyborg, /obj/item/gun/energy/e_gun/advtaser/cyborg, /obj/item/gun/energy/printer, /obj/item/gun/energy/kinetic_accelerator/cyborg, /obj/item/gun/energy/laser/cyborg )) /obj/machinery/cryopod/Initialize(mapload) . = ..() update_icon() find_control_computer(mapload) /obj/machinery/cryopod/proc/find_control_computer(urgent = FALSE) for(var/obj/machinery/computer/cryopod/C in get_area(src)) control_computer = C if(C) return 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 [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 != null /obj/machinery/cryopod/close_machine(mob/user) if(!control_computer) find_control_computer(TRUE) if((isnull(user) || istype(user)) && state_open && !panel_open) ..(user) var/mob/living/mob_occupant = occupant if(mob_occupant && mob_occupant.stat != DEAD) to_chat(occupant, "You feel cool air surround you. You go numb as your senses turn inward.") if(mob_occupant.client)//if they're logged in despawn_world_time = world.time + (time_till_despawn * 0.1) else despawn_world_time = world.time + time_till_despawn icon_state = "cryopod" /obj/machinery/cryopod/open_machine() ..() icon_state = "cryopod-open" density = TRUE name = initial(name) /obj/machinery/cryopod/container_resist(mob/living/user) visible_message("[occupant] emerges from [src]!", "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) // Eject dead people if(mob_occupant.stat == DEAD) open_machine() if(!(world.time > despawn_world_time + 100))//+ 10 seconds return if(!mob_occupant.client && mob_occupant.stat < 2) //Occupant is living and has no client. if(!control_computer) find_control_computer(urgent = TRUE)//better hope you found it this time despawn_occupant() #define CRYO_DESTROY 0 #define CRYO_PRESERVE 1 #define CRYO_OBJECTIVE 2 #define CRYO_IGNORE 3 /obj/machinery/cryopod/proc/should_preserve_item(obj/item/I) for(var/datum/objective_item/steal/T in control_computer.theft_cache) if(istype(I, T.targetitem) && T.check_special_completion(I)) return CRYO_OBJECTIVE if(preserve_items[I] && !do_not_preserve_items[I]) return CRYO_PRESERVE return CRYO_DESTROY // This function can not be undone; do not call this unless you are sure /obj/machinery/cryopod/proc/despawn_occupant() if(!control_computer) find_control_computer() var/mob/living/mob_occupant = occupant var/list/obj/item/cryo_items = list() //Handle Borg stuff first if(iscyborg(mob_occupant)) var/mob/living/silicon/robot/R = mob_occupant if(R.mmi?.brain) cryo_items[R.mmi] = CRYO_IGNORE cryo_items[R.mmi.brain] = CRYO_IGNORE 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 cryo_items[O] = should_preserve_item(O) O.forceMove(src) R.module.remove_module(I, TRUE) //delete the module itself so it doesn't transfer over. //Drop all items into the pod. for(var/obj/item/I in mob_occupant) if(cryo_items[I] == CRYO_IGNORE) continue cryo_items[I] = should_preserve_item(I) mob_occupant.transferItemToLoc(I, src, TRUE) if(I.contents.len) //Make sure we catch anything not handled by qdel() on the items. if(cryo_items[I] != CRYO_DESTROY) // Don't remove the contents of things that need preservation continue for(var/obj/item/O in I.contents) cryo_items[O] = should_preserve_item(O) O.forceMove(src) for(var/A in cryo_items) var/obj/item/I = A if(QDELETED(I)) //edge cases and DROPDEL. continue var/preserve = cryo_items[I] if(preserve == CRYO_IGNORE) continue else if(preserve == CRYO_DESTROY) qdel(I) else if(control_computer?.allow_items) control_computer.frozen_items += I if(preserve == CRYO_OBJECTIVE) control_computer.objective_items += I I.moveToNullspace() else I.forceMove(loc) //Update any existing objectives involving this mob. for(var/datum/objective/O 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(O,/datum/objective/mutiny) && O.target == mob_occupant.mind) qdel(O) else if(O.target && istype(O.target, /datum/mind)) if(O.target == mob_occupant.mind) if(O.owner && O.owner.current) to_chat(O.owner.current, "
You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!") O.target = null spawn(10) //This should ideally fire after the occupant is deleted. if(!O) return O.find_target() O.update_explanation_text() if(!(O.target)) qdel(O) if(mob_occupant.mind) //Handle job slot/tater cleanup. if(mob_occupant.mind.assigned_role) var/job = mob_occupant.mind.assigned_role SSjob.FreeRole(job) mob_occupant.mind.special_role = null // Delete them from datacore. var/announce_rank = null for(var/datum/data/record/R in GLOB.data_core.medical) if((R.fields["name"] == mob_occupant.real_name)) qdel(R) for(var/datum/data/record/T in GLOB.data_core.security) if((T.fields["name"] == mob_occupant.real_name)) qdel(T) for(var/datum/data/record/G in GLOB.data_core.general) if((G.fields["name"] == mob_occupant.real_name)) announce_rank = G.fields["rank"] qdel(G) for(var/obj/machinery/computer/cloning/cloner in world) for(var/datum/data/record/R in cloner.records) if(R.fields["name"] == mob_occupant.real_name) cloner.records.Remove(R) //Make an announcement and log the person entering storage. if(control_computer) control_computer.frozen_crew += "[mob_occupant.real_name]" 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("\The [src] hums and hisses as it moves [mob_occupant.real_name] into storage.") // Ghost and delete the mob. if(!mob_occupant.get_ghost(1)) mob_occupant.ghostize(FALSE, penalize = TRUE) QDEL_NULL(occupant) open_machine() name = initial(name) #undef CRYO_DESTROY #undef CRYO_PRESERVE #undef CRYO_OBJECTIVE #undef CRYO_IGNORE /obj/machinery/cryopod/MouseDrop_T(mob/living/target, mob/user) if(!istype(target) || user.incapacitated() || !target.Adjacent(user) || !Adjacent(user) || !ismob(target) || (!ishuman(user) && !iscyborg(user)) || !istype(user.loc, /turf) || target.buckled) return if(occupant) to_chat(user, "The cryo pod is already occupied!") return if(target.stat == DEAD) to_chat(user, "Dead people can not be put into cryo.") return if(target.client && user != target) if(iscyborg(target)) to_chat(user, "You can't put [target] into [src]. They're online.") else to_chat(user, "You can't put [target] into [src]. They're conscious.") return else if(target.client) if(alert(target,"Would you like to enter cryosleep?",,"Yes","No") == "No") return var/generic_plsnoleave_message = " Please adminhelp before leaving the round, even if there are no administrators online!" if(target == user && world.time - target.client.cryo_warned > 5 MINUTES)//if we haven't warned them in the last 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) alert(target, "You're a [english_list(caught_string)]![generic_plsnoleave_message][addendum]") target.client.cryo_warned = world.time return if(!target || user.incapacitated() || !target.Adjacent(user) || !Adjacent(user) || (!ishuman(user) && !iscyborg(user)) || !istype(user.loc, /turf) || target.buckled) return //rerun the checks in case of shenanigans if(target == user) visible_message("[user] starts climbing into the cryo pod.") else visible_message("[user] starts putting [target] into the cryo pod.") if(occupant) to_chat(user, "\The [src] is in use.") return close_machine(target) to_chat(target, "If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.") name = "[name] ([occupant.name])" log_admin("[key_name(target)] entered a stasis pod.") message_admins("[key_name_admin(target)] entered a stasis pod. (JMP)") add_fingerprint(target) //Attacks/effects. /obj/machinery/cryopod/blob_act() return //Sorta gamey, but we don't really want these to be destroyed.