diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 825ae019bf5..35401aa8da7 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -145,6 +145,14 @@ SUBSYSTEM_DEF(job)
JobDebug("AR has failed, Player: [player], Rank: [rank]")
return FALSE
+/datum/controller/subsystem/job/proc/FreeRole(rank)
+ if(!rank)
+ return
+ JobDebug("Freeing role: [rank]")
+ var/datum/job/job = GetJob(rank)
+ if(!job)
+ return FALSE
+ job.current_positions = max(0, job.current_positions - 1)
/datum/controller/subsystem/job/proc/FindOccupationCandidates(datum/job/job, level, flag)
JobDebug("Running FOC, Job: [job], Level: [level], Flag: [flag]")
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index edd8e6ce2c8..b0eceaead7e 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -41,6 +41,7 @@
var/assigned_role
var/special_role
var/list/restricted_roles = list()
+ var/list/datum/objective/objectives = list()
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
diff --git a/code/game/area/space_station_13_areas.dm b/code/game/area/space_station_13_areas.dm
index a18dfab69e9..117b297ceaf 100644
--- a/code/game/area/space_station_13_areas.dm
+++ b/code/game/area/space_station_13_areas.dm
@@ -608,6 +608,10 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
name = "Recreation Area"
icon_state = "rec"
+/area/commons/cryopods
+ name = "Cryopod Room"
+ icon_state = "cryopod"
+
// Commons - Vacant Rooms
/area/commons/vacant_room
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 45c16de0608..d1d701298d1 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -1,4 +1,5 @@
GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list
+GLOBAL_LIST_EMPTY(objectives)
/datum/objective
var/datum/mind/owner //The primary owner of the objective. !!SOMEWHAT DEPRECATED!! Prefer using 'team' for new code.
@@ -14,6 +15,7 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list
var/martyr_compatible = FALSE //If the objective is compatible with martyr objective, i.e. if you can still do it while dead.
/datum/objective/New(text)
+ GLOB.objectives += src
if(text)
explanation_text = text
diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm
index 3d655f943c0..0c9ac785167 100644
--- a/code/game/machinery/announcement_system.dm
+++ b/code/game/machinery/announcement_system.dm
@@ -83,12 +83,10 @@ GLOBAL_LIST_EMPTY(announcement_systems)
message = CompileText(arrival, user, rank)
else if(message_type == "NEWHEAD" && newheadToggle)
message = CompileText(newhead, user, rank)
+ else if(message_type == "CRYOSTORAGE")
+ message = "[user][rank ? ", [rank]" : ""] has been moved to cryo storage."
else if(message_type == "ARRIVALS_BROKEN")
message = "The arrivals shuttle has been damaged. Docking for repairs..."
- //SKYRAT EDIT ADDITION BEGIN - CRYOSLEEP
- else if(message_type == "CRYOSTORAGE")
- message = CompileText("%PERSON, %RANK has been moved to cryo storage.", user, rank)
- //SKYRAT EDIT ADDITION END
broadcast(message, channels)
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
new file mode 100644
index 00000000000..5bad45465e1
--- /dev/null
+++ b/code/game/machinery/cryopod.dm
@@ -0,0 +1,401 @@
+/*
+ * 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 = 'modular_skyrat/modules/cryosleep/icons/cryogenics.dmi' //SKYRAT EDIT CHANGE - ORIGINAL: 'icons/obj/machines/cryopod.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/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 = TRUE
+
+/obj/machinery/computer/cryopod/Initialize()
+ . = ..()
+ GLOB.cryopod_computers += src
+
+/obj/machinery/computer/cryopod/Destroy()
+ GLOB.cryopod_computers -= src
+ ..()
+
+/obj/machinery/computer/cryopod/update_icon_state()
+ if(machine_stat & (NOPOWER|BROKEN))
+ icon_state = "cellconsole"
+ return ..()
+ icon_state = "cellconsole_1"
+ return ..()
+
+/obj/machinery/computer/cryopod/ui_interact(mob/user, datum/tgui/ui)
+ if(machine_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["allow_items"] = allow_items
+ data["frozen_crew"] = frozen_crew
+ data["frozen_items"] = list()
+
+ if(allow_items)
+ data["frozen_items"] = frozen_items
+
+ 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
+
+ return data
+
+/obj/machinery/computer/cryopod/ui_act(action, params)
+ . = ..()
+ if(.)
+ return
+
+ var/mob/user = usr
+
+ add_fingerprint(user)
+
+ switch(action)
+ if("one_item")
+ if(!allowed(user))
+ to_chat(user, "Access Denied.")
+ return
+
+ if(!allow_items) return
+
+ if(!params["item"])
+ return
+
+ var/obj/item/item = frozen_items[text2num(params["item"])]
+ if(!item)
+ to_chat(user, "[item] is no longer in storage.")
+ return
+
+ visible_message("[src] beeps happily as it disgorges [item].")
+ item.forceMove(get_turf(src))
+ frozen_items -= item
+
+ if("all_items")
+ if(!allowed(user))
+ to_chat(user, "Access Denied.")
+ return
+
+ if(!allow_items) return
+
+ visible_message("[src] beeps happily as it disgorges the desired objects.")
+
+ for(var/obj/item/item in frozen_items)
+ item.forceMove(get_turf(src))
+ frozen_items -= item
+
+ return TRUE
+
+// 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/machines/cryopod.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"
+
+ // 3 minutes-ish safe period before being despawned.
+ var/time_till_despawn = 3 MINUTES // This is reduced to 30 seconds if a player manually enters cryo
+ var/fast_despawn = 30 SECONDS
+ var/despawn_world_time = null // Used to keep track of the safe period.
+
+ var/obj/machinery/computer/cryopod/control_computer
+ 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 = 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 = 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 && 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 != 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 || !mob_occupant.key) // Self cryos and SSD
+ despawn_world_time = world.time + (fast_despawn) // This gives them 30 seconds
+ 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_act(mob/living/user)
+ visible_message("[occupant] emerges from [src]!",
+ "You climb out of [src]!")
+ open_machine()
+
+/obj/machinery/cryopod/relaymove(mob/user)
+ container_resist_act(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)
+ return
+
+ if(!mob_occupant.client && mob_occupant.stat <= SOFT_CRIT) // Occupant is living and has no client.
+ if(!control_computer)
+ find_control_computer(urgent = TRUE) // better hope you found it this time
+
+ 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, "
Your target is no longer within reach. Objective removed!")
+ mind.announce_objectives()
+ else if(objective.target && istype(objective.target, /datum/mind))
+ if(objective.target == mob_occupant.mind)
+ var/old_target = objective.target
+ objective.target = null
+ if(!objective)
+ return
+ objective.find_target()
+ if(!objective.target && objective.owner)
+ to_chat(objective.owner.current, "
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, "
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, "
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, "
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 && mob_occupant.mind.assigned_role)
+ // 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
+ //SKYRAT EDIT ADDITION
+ if(SSticker.mode.name == "assaultops")
+ if(is_assaultops_target(mob_occupant.mind))
+ remove_assaultops_target(mob_occupant.mind) //Remove them from the list of targets for the assops.
+ //SKYRAT EDIT END
+ else
+ crew_member["job"] = "N/A"
+ // Delete them from datacore.
+ var/announce_rank = null
+ for(var/datum/data/record/medical_record in GLOB.data_core.medical)
+ if(medical_record.fields["name"] == mob_occupant.real_name)
+ qdel(medical_record)
+ for(var/datum/data/record/security_record in GLOB.data_core.security)
+ if(security_record.fields["name"] == mob_occupant.real_name)
+ qdel(security_record)
+ for(var/datum/data/record/general_record in GLOB.data_core.general)
+ if(general_record.fields["name"] == mob_occupant.real_name)
+ announce_rank = general_record.fields["rank"]
+ qdel(general_record)
+
+ 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("[src] hums and hisses as it moves [mob_occupant.real_name] into storage.")
+
+ for(var/obj/item/item in mob_occupant.GetAllContents())
+ if(item.loc.loc && (item.loc.loc == loc || item.loc.loc == control_computer))
+ continue // means we already moved whatever this thing was in
+ // I'm a professional, okay
+
+ if(!should_preserve_item(item))
+ continue
+
+ if(control_computer && control_computer.allow_items)
+ control_computer.frozen_items += item
+ mob_occupant.transferItemToLoc(item, control_computer, TRUE)
+ else
+ mob_occupant.transferItemToLoc(item, loc, TRUE)
+
+ var/list/contents = mob_occupant.GetAllContents()
+ QDEL_LIST(contents)
+
+ // Ghost and delete the mob.
+ if(!mob_occupant.get_ghost(TRUE))
+ if(world.time < 15 MINUTES) // before the 15 minute mark
+ mob_occupant.ghostize(FALSE) // Players despawned too early may not re-enter the game
+ else
+ mob_occupant.ghostize(TRUE)
+ handle_objectives()
+ QDEL_NULL(occupant)
+ 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, "[src] 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]. [target.p_theyre(capitalized = TRUE)] online.")
+ else
+ to_chat(user, "You can't put [target] into [src]. [target.p_theyre(capitalized = TRUE)] 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 && COOLDOWN_FINISHED(target.client, cryo_warned))
+ var/caught = FALSE
+ var/datum/antagonist/antag = target.mind.has_antag_datum(/datum/antagonist)
+ var/datum/job/target_job = SSjob.GetJob(target.mind.assigned_role)
+ if(target_job.req_admin_notify)
+ alert("You're an important role![generic_plsnoleave_message]")
+ caught = TRUE
+ if(antag)
+ alert("You're \a [antag.name]![generic_plsnoleave_message]")
+ caught = TRUE
+ if(caught)
+ COOLDOWN_START(target.client, cryo_warned, 5 MINUTES)
+ return
+
+ 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(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, "[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. [ADMIN_JMP(src)]")
+ add_fingerprint(target)
+
+// Attacks/effects.
+/obj/machinery/cryopod/blob_act()
+ return // Sorta gamey, but we don't really want these to be destroyed.
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index 6f56ac050b1..aca712df82b 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -283,23 +283,31 @@
/datum/team/cult/proc/ascend(cultist)
if(ishuman(cultist))
- var/mob/living/carbon/human/H = cultist
- new /obj/effect/temp_visual/cult/sparks(get_turf(H), H.dir)
+ var/mob/living/carbon/human/human = cultist
+ new /obj/effect/temp_visual/cult/sparks(get_turf(human), human.dir)
var/istate = pick("halo1","halo2","halo3","halo4","halo5","halo6")
var/mutable_appearance/new_halo_overlay = mutable_appearance('icons/effects/32x64.dmi', istate, -HALO_LAYER)
- H.overlays_standing[HALO_LAYER] = new_halo_overlay
- H.apply_overlay(HALO_LAYER)
+ human.overlays_standing[HALO_LAYER] = new_halo_overlay
+ human.apply_overlay(HALO_LAYER)
-/datum/team/cult/proc/setup_objectives()
- //SAC OBJECTIVE , todo: move this to objective internals
+/datum/team/cult/proc/make_image(datum/objective/sacrifice/sac_objective)
+ var/datum/job/job_of_sacrifice = SSjob.GetJob(sac_objective.target.assigned_role)
+ var/datum/preferences/prefs_of_sacrifice = sac_objective.target.current.client.prefs
+ var/icon/reshape = get_flat_human_icon(null, job_of_sacrifice, prefs_of_sacrifice, list(SOUTH))
+ reshape.Shift(SOUTH, 4)
+ reshape.Shift(EAST, 1)
+ reshape.Crop(7,4,26,31)
+ reshape.Crop(-5,-3,26,30)
+ sac_objective.sac_image = reshape
+
+/datum/objective/sacrifice/find_target(dupe_search_range)
+ if(!istype(team, /datum/team/cult))
+ return
+ var/datum/team/cult/cult = team
var/list/target_candidates = list()
- var/datum/objective/sacrifice/sac_objective = new
- sac_objective.team = src
-
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !player.mind.has_antag_datum(/datum/antagonist/cult) && !is_convertable_to_cult(player) && player.stat != DEAD)
target_candidates += player.mind
-
if(target_candidates.len == 0)
message_admins("Cult Sacrifice: Could not find unconvertible target, checking for convertible target.")
for(var/mob/living/carbon/human/player in GLOB.player_list)
@@ -307,30 +315,26 @@
target_candidates += player.mind
listclearnulls(target_candidates)
if(LAZYLEN(target_candidates))
- sac_objective.target = pick(target_candidates)
- sac_objective.update_explanation_text()
-
- var/datum/job/sacjob = SSjob.GetJob(sac_objective.target.assigned_role)
- var/datum/preferences/sacface = sac_objective.target.current.client.prefs
- var/icon/reshape = get_flat_human_icon(null, sacjob, sacface, list(SOUTH))
- reshape.Shift(SOUTH, 4)
- reshape.Shift(EAST, 1)
- reshape.Crop(7,4,26,31)
- reshape.Crop(-5,-3,26,30)
- sac_objective.sac_image = reshape
-
- objectives += sac_objective
+ target = pick(target_candidates)
+ update_explanation_text()
else
message_admins("Cult Sacrifice: Could not find unconvertible or convertible target. WELP!")
+ cult.make_image(src)
+ for(var/datum/mind/mind in cult.members)
+ if(mind.current)
+ mind.current.clear_alert("bloodsense")
+ mind.current.throw_alert("bloodsense", /atom/movable/screen/alert/bloodsense)
+/datum/team/cult/proc/setup_objectives()
+ var/datum/objective/sacrifice/sacrifice_objective = new
+ sacrifice_objective.team = src
+ sacrifice_objective.find_target()
+ objectives += sacrifice_objective
- //SUMMON OBJECTIVE
-
- var/datum/objective/eldergod/summon_objective = new()
+ var/datum/objective/eldergod/summon_objective = new
summon_objective.team = src
objectives += summon_objective
-
/datum/objective/sacrifice
var/sacced = FALSE
var/sac_image
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index c79aafe2fec..748de9c50d4 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -30,7 +30,8 @@
var/total_count_reset = 0
///Internal counter for clients sending external (IRC/Discord) relay messages via ahelp to prevent spamming. Set to a number every time an admin reply is sent, decremented for every client send.
var/externalreplyamount = 0
-
+ ///When was the last time we warned them about not cryoing without an ahelp, set to -5 minutes so that rounstart cryo still warns
+ COOLDOWN_DECLARE(cryo_warned)
/////////
//OTHER//
/////////
diff --git a/icons/obj/machines/cryopod.dmi b/icons/obj/machines/cryopod.dmi
new file mode 100644
index 00000000000..e8c07222e19
Binary files /dev/null and b/icons/obj/machines/cryopod.dmi differ
diff --git a/modular_skyrat/modules/cryosleep/code/cryopod.dm b/modular_skyrat/modules/cryosleep/code/cryopod.dm
deleted file mode 100644
index 0aab8fb8424..00000000000
--- a/modular_skyrat/modules/cryosleep/code/cryopod.dm
+++ /dev/null
@@ -1,493 +0,0 @@
-/client
- var/cryo_warned = 0
-
-/*
- * 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 = 'modular_skyrat/modules/cryosleep/icons/cryogenics.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)
- . = ..()
- user.set_machine(src)
- add_fingerprint(user)
-
- var/dat = ""
-
- dat += "