/* * 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/weapon/circuitboard/cryopodcontrol" density = 0 interact_offline = 1 var/mode = null //Used for logging people entering cryosleep and important items they are carrying. var/list/frozen_crew = list() var/list/frozen_items = list() var/storage_type = "crewmembers" var/storage_name = "Cryogenic Oversight Control" var/allow_items = 1 /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/weapon/circuitboard/robotstoragecontrol" storage_type = "cyborgs" storage_name = "Robotic Storage Control" allow_items = 0 /obj/machinery/computer/cryopod/attack_ai() src.attack_hand() /obj/machinery/computer/cryopod/attack_hand(mob/user = usr) if(stat & (NOPOWER|BROKEN)) return user.set_machine(src) src.add_fingerprint(usr) var/dat if (!( ticker )) return dat += "

[storage_name]
" dat += "Welcome, [user.real_name].


" dat += "View storage log.
" if(allow_items) dat += "View objects.
" dat += "Recover object.
" dat += "Recover all objects.
" user << browse(dat, "window=cryopod_console") onclose(user, "cryopod_console") /obj/machinery/computer/cryopod/Topic(href, href_list) if(..()) return var/mob/user = usr src.add_fingerprint(user) if(href_list["log"]) var/dat = "Recently stored [storage_type]


" for(var/person in frozen_crew) dat += "[person]
" dat += "
" user << browse(dat, "window=cryolog") if(href_list["view"]) if(!allow_items) return var/dat = "Recently stored objects


" for(var/obj/item/I in frozen_items) dat += "[I.name]
" dat += "
" user << browse(dat, "window=cryoitems") else if(href_list["item"]) if(!allow_items) return if(frozen_items.len == 0) user << "\blue There is nothing to recover from storage." return var/obj/item/I = input(usr, "Please choose which object to retrieve.","Object recovery",null) as null|anything in frozen_items if(!I) return if(!(I in frozen_items)) user << "\blue \The [I] is no longer in storage." return visible_message("\blue The console beeps happily as it disgorges \the [I].", 3) I.loc = get_turf(src) frozen_items -= I else if(href_list["allitems"]) if(!allow_items) return if(frozen_items.len == 0) user << "\blue There is nothing to recover from storage." return visible_message("\blue The console beeps happily as it disgorges the desired objects.", 3) for(var/obj/item/I in frozen_items) I.loc = get_turf(src) frozen_items -= I src.updateUsrDialog() return /obj/item/weapon/circuitboard/cryopodcontrol name = "Circuit board (Cryogenic Oversight Console)" build_path = "/obj/machinery/computer/cryopod" origin_tech = "programming=3" /obj/item/weapon/circuitboard/robotstoragecontrol name = "Circuit board (Robotic Storage Console)" build_path = "/obj/machinery/computer/cryopod/robot" origin_tech = "programming=3" //Decorative structures to go alongside cryopods. /obj/structure/cryofeed name = "\improper cryogenic feed" desc = "A bewildering tangle of machinery and pipes." icon = 'icons/obj/Cryogenic2.dmi' icon_state = "cryo_rear" anchored = 1 var/orient_right = null //Flips the sprite. /obj/structure/cryofeed/right orient_right = 1 icon_state = "cryo_rear-r" /obj/structure/cryofeed/New() if(orient_right) icon_state = "cryo_rear-r" else icon_state = "cryo_rear" ..() //Cryopods themselves. /obj/machinery/cryopod name = "\improper cryogenic freezer" desc = "A man-sized pod for entering suspended animation." icon = 'icons/obj/Cryogenic2.dmi' icon_state = "body_scanner_0" density = 1 anchored = 1 var/base_icon_state = "body_scanner_0" var/occupied_icon_state = "body_scanner_1" 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, /mob/living/carbon/monkey) var/disallow_occupant_types = list() var/mob/occupant = null // Person waiting to be despawned. var/orient_right = null // Flips the sprite. var/time_till_despawn = 18000 // 30 minutes-ish safe period before being despawned. var/time_entered = 0 // Used to keep track of the safe period. var/obj/item/device/radio/intercom/announce // 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/weapon/hand_tele, /obj/item/weapon/card/id/captains_spare, /obj/item/device/aicard, /obj/item/device/mmi, /obj/item/device/paicard, /obj/item/weapon/gun, /obj/item/weapon/pinpointer, /obj/item/clothing/suit, /obj/item/clothing/shoes/magboots, /obj/item/blueprints, /obj/item/clothing/head/helmet/space, /obj/item/weapon/storage/internal ) /obj/machinery/cryopod/right orient_right = 1 icon_state = "body_scanner_0-r" /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." allow_occupant_types = list(/mob/living/silicon/robot) disallow_occupant_types = list(/mob/living/silicon/robot/drone) /obj/machinery/cryopod/robot/right orient_right = 1 icon_state = "pod_0-r" /obj/machinery/cryopod/New() announce = new /obj/item/device/radio/intercom(src) if(orient_right) icon_state = "[base_icon_state]-r" else icon_state = base_icon_state ..() /obj/machinery/cryopod/initialize() ..() find_control_computer() /obj/machinery/cryopod/proc/find_control_computer(urgent=0) control_computer = locate(/obj/machinery/computer/cryopod) in src.loc.loc // 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 [src.loc.loc] could not find control computer!") message_admins("Cryopod in [src.loc.loc] could not find control computer!") last_no_computer_message = world.time return control_computer != null /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) //Allow a ten minute 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 //Drop all items into the pod. for(var/obj/item/W in occupant) if(istype(W, /obj/item/device/mmi)) if(istype(occupant, /mob/living/silicon/robot)) var/mob/living/silicon/robot/R = occupant if(R.mmi == W) del(W) continue occupant.drop_from_inventory(W) W.loc = src if(W.contents.len) //Make sure we catch anything not handled by del() on the items. for(var/obj/item/O in W.contents) if(istype(O,/obj/item/weapon/storage/internal)) //Stop eating pockets, you fuck! continue O.loc = src //Delete all items not on the preservation list. var/list/items = src.contents items -= occupant // Don't delete the occupant items -= announce // or the autosay radio. for(var/obj/item/W in items) var/preserve = null for(var/T in preserve_items) if(istype(W,T)) preserve = 1 break if(!preserve) del(W) else if(control_computer && control_computer.allow_items) control_computer.frozen_items += W W.loc = null else W.loc = src.loc //Update any existing objectives involving this mob. for(var/datum/objective/O in all_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 == occupant.mind) del(O) else if(O.target && istype(O.target,/datum/mind)) if(O.target == occupant.mind) if(O.owner && O.owner.current) O.owner.current << "\red You get the feeling your target is no longer within your reach. Time for Plan [pick(list("A","B","C","D","X","Y","Z"))]..." O.target = null spawn(1) //This should ideally fire after the occupant is deleted. if(!O) return O.find_target() if(!(O.target)) all_objectives -= O O.owner.objectives -= O del(O) //Handle job slot/tater cleanup. var/job = occupant.mind.assigned_role job_master.FreeRole(job) if(occupant.mind.objectives.len) del(occupant.mind.objectives) occupant.mind.special_role = null else if(ticker.mode.name == "AutoTraitor") var/datum/game_mode/traitor/autotraitor/current_mode = ticker.mode current_mode.possible_traitors.Remove(occupant) // Delete them from datacore. if(PDA_Manifest.len) PDA_Manifest.Cut() for(var/datum/data/record/R in data_core.medical) if ((R.fields["name"] == occupant.real_name)) del(R) for(var/datum/data/record/T in data_core.security) if ((T.fields["name"] == occupant.real_name)) del(T) for(var/datum/data/record/G in data_core.general) if ((G.fields["name"] == occupant.real_name)) del(G) if(orient_right) icon_state = "[base_icon_state]-r" else icon_state = base_icon_state //TODO: Check objectives/mode, update new targets if this mob is the target, spawn new antags? //This should guarantee that ghosts don't spawn. occupant.ckey = null //Make an announcement and log the person entering storage. control_computer.frozen_crew += "[occupant.real_name]" announce.autosay("[occupant.real_name] [on_store_message]", "[on_store_name]") visible_message("\blue \The [src] hums and hisses as it moves [occupant.real_name] into storage.", 3) // Delete the mob. del(occupant) occupant = null return /obj/machinery/cryopod/attackby(var/obj/item/weapon/G as obj, var/mob/user as mob) if(istype(G, /obj/item/weapon/grab)) if(occupant) user << "\blue \The [src] is in use." return if(!ismob(G:affecting)) return if(!check_occupant_allowed(G:affecting)) return var/willing = null //We don't want to allow people to be forced into despawning. var/mob/M = G:affecting if(M.client) if(alert(M,"Would you like to enter long-term storage?",,"Yes","No") == "Yes") if(!M || !G || !G:affecting) return willing = 1 else willing = 1 if(willing) visible_message("[user] starts putting [G:affecting:name] into \the [src].", 3) if(do_after(user, 20)) if(!M || !G || !G:affecting) return M.loc = src if(M.client) M.client.perspective = EYE_PERSPECTIVE M.client.eye = src if(orient_right) icon_state = "[occupied_icon_state]-r" else icon_state = occupied_icon_state M << "\blue [on_enter_occupant_message]" M << "\blue If you ghost, log out or close your client now, your character will shortly be permanently removed from the round." occupant = M time_entered = world.time // Book keeping! var/turf/location = get_turf(src) log_admin("[key_name_admin(M)] has entered a stasis pod. (JMP)") message_admins("\blue [key_name_admin(M)] has entered a stasis pod.") //Despawning occurs when process() is called with an occupant without a client. src.add_fingerprint(M) /obj/machinery/cryopod/verb/eject() set name = "Eject Pod" set category = "Object" set src in oview(1) if(usr.stat != 0) return if(orient_right) icon_state = "[base_icon_state]-r" else icon_state = base_icon_state //Eject any items that aren't meant to be in the pod. var/list/items = src.contents if(occupant) items -= occupant if(announce) items -= announce for(var/obj/item/W in items) W.loc = get_turf(src) src.go_out() add_fingerprint(usr) return /obj/machinery/cryopod/verb/move_inside() set name = "Enter Pod" set category = "Object" set src in oview(1) if(usr.stat != 0 || !check_occupant_allowed(usr)) return if(src.occupant) usr << "\blue \The [src] is in use." return for(var/mob/living/carbon/slime/M in range(1,usr)) if(M.Victim == usr) usr << "You're too busy getting your life sucked out of you." return visible_message("[usr] starts climbing into \the [src].", 3) if(do_after(usr, 20)) if(!usr || !usr.client) return if(src.occupant) usr << "\blue \The [src] is in use." return usr.stop_pulling() usr.client.perspective = EYE_PERSPECTIVE usr.client.eye = src usr.loc = src src.occupant = usr if(orient_right) icon_state = "[occupied_icon_state]-r" else icon_state = occupied_icon_state usr << "\blue [on_enter_occupant_message]" usr << "\blue If you ghost, log out or close your client now, your character will shortly be permanently removed from the round." occupant = usr time_entered = world.time src.add_fingerprint(usr) return /obj/machinery/cryopod/proc/go_out() if(!occupant) return if(occupant.client) occupant.client.eye = src.occupant.client.mob occupant.client.perspective = MOB_PERSPECTIVE occupant.loc = get_turf(src) occupant = null if(orient_right) icon_state = "[base_icon_state]-r" else icon_state = base_icon_state return //Attacks/effects. /obj/machinery/cryopod/blob_act() return //Sorta gamey, but we don't really want these to be destroyed.