diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index 1c333f5fedb..7fe385f2d08 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -7296,6 +7296,7 @@
/obj/structure/table,
/obj/effect/spawner/lootdrop/maintenance/two,
/obj/effect/decal/cleanable/dirt,
+/obj/item/stock_parts/capacitor,
/turf/open/floor/plasteel,
/area/maintenance/port/fore)
"apM" = (
@@ -9547,6 +9548,7 @@
/turf/open/floor/plasteel,
/area/crew_quarters/dorms)
"avS" = (
+/obj/item/circuitboard/machine/stasis,
/obj/item/wrench,
/turf/open/floor/plating,
/area/maintenance/port/fore)
@@ -10074,9 +10076,7 @@
/turf/open/floor/plasteel,
/area/construction/mining/aux_base)
"axe" = (
-/obj/machinery/sleeper{
- dir = 4
- },
+/obj/structure/frame/machine,
/turf/open/floor/plating,
/area/maintenance/port/fore)
"axf" = (
@@ -10590,6 +10590,7 @@
"ayt" = (
/obj/structure/table/glass,
/obj/item/hemostat,
+/obj/item/stock_parts/manipulator,
/turf/open/floor/plating,
/area/maintenance/port/fore)
"ayu" = (
@@ -31259,9 +31260,7 @@
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"bwD" = (
-/obj/machinery/sleeper{
- dir = 8
- },
+/obj/machinery/stasis,
/turf/open/floor/plasteel,
/area/medical/sleeper)
"bwE" = (
@@ -32878,14 +32877,12 @@
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"bAq" = (
-/obj/machinery/sleeper{
- dir = 8
- },
/obj/machinery/camera{
c_tag = "Medbay Treatment Center";
network = list("ss13","medbay");
dir = 8
},
+/obj/machinery/stasis,
/turf/open/floor/plasteel,
/area/medical/sleeper)
"bAr" = (
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index ed27cec2485..c9f4863517a 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -95060,12 +95060,13 @@
dir = 4;
pixel_x = -23
},
-/obj/machinery/sleeper{
- dir = 4
- },
/obj/effect/turf_decal/stripes/line{
dir = 6
},
+/obj/item/stack/rods/ten,
+/obj/item/stock_parts/capacitor,
+/obj/item/circuitboard/machine/stasis,
+/obj/item/stock_parts/manipulator,
/turf/open/floor/plasteel,
/area/medical/abandoned)
"ddn" = (
@@ -95751,12 +95752,10 @@
/turf/open/floor/plating,
/area/security/checkpoint/medical)
"deC" = (
-/obj/machinery/sleeper{
- dir = 4
- },
/obj/effect/turf_decal/stripes/end{
dir = 4
},
+/obj/machinery/stasis,
/turf/open/floor/plasteel,
/area/medical/medbay/central)
"deD" = (
@@ -95776,15 +95775,13 @@
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
"deF" = (
-/obj/machinery/sleeper{
- dir = 8
- },
/obj/effect/turf_decal/stripes/end{
dir = 8
},
/obj/machinery/light{
dir = 4
},
+/obj/machinery/stasis,
/turf/open/floor/plasteel,
/area/medical/medbay/central)
"deG" = (
diff --git a/_maps/map_files/Donutstation/Donutstation.dmm b/_maps/map_files/Donutstation/Donutstation.dmm
index 06963c75824..987ca9839e7 100644
--- a/_maps/map_files/Donutstation/Donutstation.dmm
+++ b/_maps/map_files/Donutstation/Donutstation.dmm
@@ -14613,12 +14613,6 @@
/obj/machinery/vending/wardrobe/viro_wardrobe,
/turf/open/floor/plasteel/white,
/area/medical/virology)
-"aIf" = (
-/obj/machinery/sleeper{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/medical/sleeper)
"aIg" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer3{
@@ -17957,14 +17951,12 @@
/turf/open/floor/plasteel,
/area/quartermaster/warehouse)
"aQh" = (
-/obj/machinery/sleeper{
- dir = 1
- },
/obj/machinery/camera{
c_tag = "Medical - Sleeper Bay";
dir = 1;
network = list("ss13","Medical")
},
+/obj/machinery/stasis,
/turf/open/floor/plasteel,
/area/medical/sleeper)
"aQi" = (
@@ -19424,6 +19416,10 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/plating,
/area/maintenance/starboard)
+"aTD" = (
+/obj/machinery/stasis,
+/turf/open/floor/plasteel,
+/area/medical/sleeper)
"aTE" = (
/obj/structure/grille,
/obj/structure/window/reinforced{
@@ -21877,10 +21873,10 @@
/turf/open/floor/plasteel/white,
/area/medical/surgery)
"aYo" = (
-/obj/machinery/sleeper,
/obj/machinery/firealarm{
pixel_y = 24
},
+/obj/machinery/stasis,
/turf/open/floor/plasteel,
/area/medical/sleeper)
"aYp" = (
@@ -48517,7 +48513,7 @@
empty = 1;
name = "First-Aid (empty)"
},
-/obj/item/circuitboard/machine/sleeper,
+/obj/item/circuitboard/machine/stasis,
/turf/open/floor/plating,
/area/maintenance/port)
"bZY" = (
@@ -56892,7 +56888,7 @@
/turf/open/floor/plasteel/dark,
/area/engine/engineering)
"wMM" = (
-/obj/machinery/sleeper,
+/obj/machinery/stasis,
/obj/machinery/airalarm{
pixel_y = 25
},
@@ -80037,7 +80033,7 @@ aGQ
aYo
aJb
aHP
-aIf
+aTD
aGQ
aTY
bAF
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 3fe7e209874..7e1d22af6c7 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -59037,9 +59037,6 @@
/turf/open/floor/plasteel/dark,
/area/medical/surgery)
"cld" = (
-/obj/machinery/sleeper{
- dir = 4
- },
/obj/effect/turf_decal/tile/blue{
dir = 1
},
@@ -59050,6 +59047,7 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/stasis,
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"cle" = (
@@ -59090,9 +59088,6 @@
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"clh" = (
-/obj/machinery/sleeper{
- dir = 8
- },
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
@@ -59106,6 +59101,7 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/stasis,
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"cli" = (
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index b0cca06757a..cd0a7d8c1c9 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -33201,9 +33201,6 @@
/turf/open/floor/plasteel/white,
/area/medical/medbay/zone2)
"bzP" = (
-/obj/machinery/sleeper{
- dir = 4
- },
/obj/effect/turf_decal/stripes/line{
dir = 1
},
@@ -33224,6 +33221,7 @@
network = list("ss13","medbay");
dir = 4
},
+/obj/machinery/stasis,
/turf/open/floor/plasteel,
/area/medical/sleeper)
"bzQ" = (
@@ -34449,9 +34447,6 @@
/turf/open/floor/plasteel,
/area/medical/sleeper)
"bCj" = (
-/obj/machinery/sleeper{
- dir = 4
- },
/obj/effect/turf_decal/tile/blue{
dir = 1
},
@@ -34462,6 +34457,7 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/stasis,
/turf/open/floor/plasteel,
/area/medical/sleeper)
"bCl" = (
diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm
index a0f85e36158..7b20477582e 100644
--- a/_maps/map_files/generic/CentCom.dmm
+++ b/_maps/map_files/generic/CentCom.dmm
@@ -1118,9 +1118,7 @@
/obj/structure/window{
dir = 8
},
-/obj/machinery/sleeper{
- dir = 1
- },
+/obj/machinery/stasis,
/turf/open/floor/holofloor{
icon_state = "white"
},
@@ -1132,9 +1130,7 @@
},
/area/holodeck/rec_center/medical)
"dd" = (
-/obj/machinery/sleeper{
- dir = 1
- },
+/obj/machinery/stasis,
/turf/open/floor/holofloor{
icon_state = "white"
},
diff --git a/_maps/templates/shelter_1.dmm b/_maps/templates/shelter_1.dmm
index f5b2e141f4c..58146c1fb84 100644
--- a/_maps/templates/shelter_1.dmm
+++ b/_maps/templates/shelter_1.dmm
@@ -27,7 +27,10 @@
/turf/closed/wall/mineral/titanium/survival/pod,
/area/survivalpod)
"g" = (
-/obj/machinery/sleeper/survival_pod,
+/obj/machinery/stasis/survival_pod,
+/obj/machinery/vending/wallmed/survival_pod{
+ pixel_x = -24
+ },
/turf/open/floor/pod,
/area/survivalpod)
"h" = (
diff --git a/_maps/templates/shelter_2.dmm b/_maps/templates/shelter_2.dmm
index 80de4438da3..e259c1cc9c5 100644
--- a/_maps/templates/shelter_2.dmm
+++ b/_maps/templates/shelter_2.dmm
@@ -50,7 +50,10 @@
/turf/closed/wall/mineral/titanium/survival/pod,
/area/survivalpod)
"k" = (
-/obj/machinery/sleeper/survival_pod,
+/obj/machinery/stasis/survival_pod,
+/obj/machinery/vending/wallmed/survival_pod{
+ pixel_x = -24
+ },
/turf/open/floor/pod,
/area/survivalpod)
"l" = (
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index ae0e7de4453..b50423cc80c 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -94,6 +94,8 @@
#define STATUS_EFFECT_GO_AWAY /datum/status_effect/go_away //makes you launch through walls in a single direction for a while
+#define STATUS_EFFECT_STASIS /datum/status_effect/incapacitating/stasis //Halts biological functions like bleeding, chemical processing, blood regeneration, walking, etc
+
/////////////
// NEUTRAL //
/////////////
diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm
index 5fe65af8f3f..677643b9edd 100644
--- a/code/__HELPERS/time.dm
+++ b/code/__HELPERS/time.dm
@@ -11,11 +11,11 @@
wtime = world.time
return time2text(wtime - GLOB.timezoneOffset, format)
-/proc/station_time(display_only = FALSE)
- return ((((world.time - SSticker.round_start_time) * SSticker.station_time_rate_multiplier) + SSticker.gametime_offset) % 864000) - (display_only? GLOB.timezoneOffset : 0)
+/proc/station_time(display_only = FALSE, wtime=world.time)
+ return ((((wtime - SSticker.round_start_time) * SSticker.station_time_rate_multiplier) + SSticker.gametime_offset) % 864000) - (display_only? GLOB.timezoneOffset : 0)
-/proc/station_time_timestamp(format = "hh:mm:ss")
- return time2text(station_time(TRUE), format)
+/proc/station_time_timestamp(format = "hh:mm:ss", wtime)
+ return time2text(station_time(TRUE, wtime), format)
/proc/station_time_debug(force_set)
if(isnum(force_set))
diff --git a/code/controllers/subsystem/traumas.dm b/code/controllers/subsystem/traumas.dm
index c49e5994184..df5df35aa89 100644
--- a/code/controllers/subsystem/traumas.dm
+++ b/code/controllers/subsystem/traumas.dm
@@ -97,7 +97,7 @@ SUBSYSTEM_DEF(traumas)
/obj/item/clothing/under/rank/nursesuit, /obj/item/clothing/under/rank/chief_medical_officer,
/obj/item/reagent_containers/syringe, /obj/item/reagent_containers/pill/, /obj/item/reagent_containers/hypospray,
/obj/item/storage/firstaid, /obj/item/storage/pill_bottle, /obj/item/healthanalyzer,
- /obj/structure/sign/departments/medbay, /obj/machinery/door/airlock/medical, /obj/machinery/sleeper,
+ /obj/structure/sign/departments/medbay, /obj/machinery/door/airlock/medical, /obj/machinery/sleeper, /obj/machinery/stasis,
/obj/machinery/dna_scannernew, /obj/machinery/atmospherics/components/unary/cryo_cell, /obj/item/surgical_drapes,
/obj/item/retractor, /obj/item/hemostat, /obj/item/cautery, /obj/item/surgicaldrill, /obj/item/scalpel, /obj/item/circular_saw,
/obj/item/clothing/suit/bio_suit/plaguedoctorsuit, /obj/item/clothing/head/plaguedoctorhat, /obj/item/clothing/mask/gas/plaguedoctor)),
diff --git a/code/controllers/subsystem/vis_overlays.dm b/code/controllers/subsystem/vis_overlays.dm
index f7945d1db34..df3ad1687bc 100644
--- a/code/controllers/subsystem/vis_overlays.dm
+++ b/code/controllers/subsystem/vis_overlays.dm
@@ -5,11 +5,13 @@ SUBSYSTEM_DEF(vis_overlays)
init_order = INIT_ORDER_VIS
var/list/vis_overlay_cache
+ var/list/unique_vis_overlays
var/list/currentrun
var/datum/callback/rotate_cb
/datum/controller/subsystem/vis_overlays/Initialize()
vis_overlay_cache = list()
+ unique_vis_overlays = list()
rotate_cb = CALLBACK(src, .proc/rotate_vis_overlay)
return ..()
@@ -31,21 +33,23 @@ SUBSYSTEM_DEF(vis_overlays)
return
//the "thing" var can be anything with vis_contents which includes images
-/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE)
- . = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]"
- var/obj/effect/overlay/vis/overlay = vis_overlay_cache[.]
- if(!overlay)
- overlay = new
- overlay.icon = icon
- overlay.icon_state = iconstate
- overlay.layer = layer
- overlay.plane = plane
- overlay.dir = dir
- overlay.alpha = alpha
- overlay.appearance_flags |= add_appearance_flags
- vis_overlay_cache[.] = overlay
+/datum/controller/subsystem/vis_overlays/proc/add_vis_overlay(atom/movable/thing, icon, iconstate, layer, plane, dir, alpha = 255, add_appearance_flags = NONE, unique = FALSE)
+ var/obj/effect/overlay/vis/overlay
+ if(!unique)
+ . = "[icon]|[iconstate]|[layer]|[plane]|[dir]|[alpha]|[add_appearance_flags]"
+ overlay = vis_overlay_cache[.]
+ if(!overlay)
+ overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
+ vis_overlay_cache[.] = overlay
+ else
+ overlay.unused = 0
else
- overlay.unused = 0
+ overlay = _create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
+ overlay.cache_expiration = -1
+ var/cache_id = "\ref[overlay]@{[world.time]}"
+ unique_vis_overlays += overlay
+ vis_overlay_cache[cache_id] = overlay
+ . = overlay
thing.vis_contents += overlay
if(!isatom(thing)) // Automatic rotation is not supported on non atoms
@@ -57,6 +61,18 @@ SUBSYSTEM_DEF(vis_overlays)
else
thing.managed_vis_overlays += overlay
+/datum/controller/subsystem/vis_overlays/proc/_create_new_vis_overlay(icon, iconstate, layer, plane, dir, alpha, add_appearance_flags)
+ var/obj/effect/overlay/vis/overlay = new
+ overlay.icon = icon
+ overlay.icon_state = iconstate
+ overlay.layer = layer
+ overlay.plane = plane
+ overlay.dir = dir
+ overlay.alpha = alpha
+ overlay.appearance_flags |= add_appearance_flags
+ return overlay
+
+
/datum/controller/subsystem/vis_overlays/proc/remove_vis_overlay(atom/movable/thing, list/overlays)
thing.vis_contents -= overlays
if(!isatom(thing))
@@ -71,8 +87,11 @@ SUBSYSTEM_DEF(vis_overlays)
return
var/rotation = dir2angle(old_dir) - dir2angle(new_dir)
var/list/overlays_to_remove = list()
- for(var/i in thing.managed_vis_overlays)
+ for(var/i in thing.managed_vis_overlays - unique_vis_overlays)
var/obj/effect/overlay/vis/overlay = i
add_vis_overlay(thing, overlay.icon, overlay.icon_state, overlay.layer, overlay.plane, turn(overlay.dir, rotation), overlay.alpha, overlay.appearance_flags)
overlays_to_remove += overlay
+ for(var/i in thing.managed_vis_overlays & unique_vis_overlays)
+ var/obj/effect/overlay/vis/overlay = i
+ overlay.dir = turn(overlay.dir, rotation)
remove_vis_overlay(thing, overlays_to_remove)
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index a9de73645b0..f6d6d038d41 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -82,6 +82,43 @@
desc = "You've fallen asleep. Wait a bit and you should wake up. Unless you don't, considering how helpless you are."
icon_state = "asleep"
+//STASIS
+/datum/status_effect/incapacitating/stasis
+ id = "stasis"
+ duration = -1
+ tick_interval = 10
+ alert_type = /obj/screen/alert/status_effect/stasis
+ var/last_dead_time
+
+/datum/status_effect/incapacitating/stasis/proc/update_time_of_death()
+ if(last_dead_time)
+ var/delta = world.time - last_dead_time
+ var/new_timeofdeath = owner.timeofdeath + delta
+ owner.timeofdeath = new_timeofdeath
+ owner.tod = station_time_timestamp(wtime=new_timeofdeath)
+ last_dead_time = null
+ if(owner.stat == DEAD)
+ last_dead_time = world.time
+
+/datum/status_effect/incapacitating/stasis/on_creation(mob/living/new_owner, set_duration, updating_canmove)
+ . = ..()
+ update_time_of_death()
+
+/datum/status_effect/incapacitating/stasis/tick()
+ update_time_of_death()
+
+/datum/status_effect/incapacitating/stasis/on_remove()
+ update_time_of_death()
+ return ..()
+
+/datum/status_effect/incapacitating/stasis/be_replaced()
+ update_time_of_death()
+ return ..()
+
+/obj/screen/alert/status_effect/stasis
+ name = "Stasis"
+ desc = "Your biological functions have halted. You could live forever this way, but it's pretty boring."
+ icon_state = "stasis"
//GOLEM GANG
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index d38963d9e76..276992860db 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -27,8 +27,11 @@
var/enter_message = "You feel cool air surround you. You go numb as your senses turn inward."
payment_department = ACCOUNT_MED
fair_market_price = 5
-/obj/machinery/sleeper/Initialize()
+/obj/machinery/sleeper/Initialize(mapload)
. = ..()
+ if(mapload)
+ component_parts -= circuit
+ QDEL_NULL(circuit)
occupant_typecache = GLOB.typecache_living
update_icon()
reset_chem_buttons()
@@ -259,7 +262,6 @@
/obj/machinery/sleeper/syndie/fullupgrade/Initialize()
. = ..()
component_parts = list()
- component_parts += new /obj/item/circuitboard/machine/sleeper(null)
component_parts += new /obj/item/stock_parts/matter_bin/bluespace(null)
component_parts += new /obj/item/stock_parts/manipulator/femto(null)
component_parts += new /obj/item/stack/sheet/glass(null)
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index 077818cb91f..c537150ec59 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -183,12 +183,15 @@ Class Procs:
L.update_mobility()
occupant = null
+/obj/machinery/proc/can_be_occupant(atom/movable/am)
+ return occupant_typecache ? is_type_in_typecache(am, occupant_typecache) : isliving(am)
+
/obj/machinery/proc/close_machine(atom/movable/target = null)
state_open = FALSE
density = TRUE
if(!target)
for(var/am in loc)
- if (!(occupant_typecache ? is_type_in_typecache(am, occupant_typecache) : isliving(am)))
+ if (!(can_be_occupant(am)))
continue
var/atom/movable/AM = am
if(AM.has_buckled_mobs())
@@ -249,19 +252,19 @@ Class Procs:
var/datum/bank_account/insurance = I.registered_account
if(!insurance)
say("[market_verb] NAP Violation: No bank account found.")
- nap_violation()
+ nap_violation(occupant)
return FALSE
else
if(!insurance.adjust_money(-fair_market_price))
say("[market_verb] NAP Violation: Unable to pay.")
- nap_violation()
+ nap_violation(occupant)
return FALSE
var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department)
if(D)
D.adjust_money(fair_market_price)
else
say("[market_verb] NAP Violation: No ID card found.")
- nap_violation()
+ nap_violation(occupant)
return FALSE
return TRUE
diff --git a/code/game/machinery/stasis.dm b/code/game/machinery/stasis.dm
new file mode 100644
index 00000000000..5f7f0263dbb
--- /dev/null
+++ b/code/game/machinery/stasis.dm
@@ -0,0 +1,141 @@
+#define STASIS_TOGGLE_COOLDOWN 50
+/obj/machinery/stasis
+ name = "Lifeform Stasis Unit"
+ desc = "A not so comfortable looking bed with some nozzles at the top and bottom. It will keep someone in stasis."
+ icon = 'icons/obj/machines/stasis.dmi'
+ icon_state = "stasis"
+ density = FALSE
+ can_buckle = TRUE
+ buckle_lying = 90
+ circuit = /obj/item/circuitboard/machine/stasis
+ idle_power_usage = 40
+ active_power_usage = 340
+ fair_market_price = 10
+ payment_department = ACCOUNT_MED
+ var/stasis_enabled = TRUE
+ var/last_stasis_sound = FALSE
+ var/stasis_can_toggle = 0
+ var/mattress_state = "stasis_on"
+ var/obj/effect/overlay/vis/mattress_on
+
+/obj/machinery/stasis/examine(mob/user)
+ ..()
+ var/turn_on_or_off = stasis_enabled ? "turn off" : "turn on"
+ to_chat(user, "Alt-click to [turn_on_or_off] the machine.")
+
+/obj/machinery/stasis/proc/play_power_sound()
+ var/_running = stasis_running()
+ if(last_stasis_sound != _running)
+ var/sound_freq = rand(5120, 8800)
+ if(_running)
+ playsound(src, 'sound/machines/synth_yes.ogg', 50, TRUE, frequency = sound_freq)
+ else
+ playsound(src, 'sound/machines/synth_no.ogg', 50, TRUE, frequency = sound_freq)
+ last_stasis_sound = _running
+
+/obj/machinery/stasis/AltClick(mob/user)
+ if(world.time >= stasis_can_toggle && user.canUseTopic(src))
+ stasis_enabled = !stasis_enabled
+ stasis_can_toggle = world.time + STASIS_TOGGLE_COOLDOWN
+ playsound(src, 'sound/machines/click.ogg', 60, TRUE)
+ play_power_sound()
+ update_icon()
+
+/obj/machinery/stasis/Exited(atom/movable/AM, atom/newloc)
+ if(AM == occupant)
+ var/mob/living/L = AM
+ if(L.IsInStasis())
+ thaw_them(L)
+ . = ..()
+
+/obj/machinery/stasis/proc/stasis_running()
+ return stasis_enabled && is_operational()
+
+/obj/machinery/stasis/update_icon()
+ . = ..()
+ var/_running = stasis_running()
+ var/list/overlays_to_remove = managed_vis_overlays
+
+ if(mattress_state)
+ if(!mattress_on || !managed_vis_overlays)
+ mattress_on = SSvis_overlays.add_vis_overlay(src, icon, mattress_state, layer, plane, dir, alpha = 0, unique = TRUE)
+
+ if(mattress_on.alpha ? !_running : _running) //check the inverse of _running compared to truthy alpha, to see if they differ
+ var/new_alpha = _running ? 255 : 0
+ var/easing_direction = _running ? EASE_OUT : EASE_IN
+ animate(mattress_on, alpha = new_alpha, time = 50, easing = CUBIC_EASING|easing_direction)
+
+ overlays_to_remove = managed_vis_overlays - mattress_on
+
+ SSvis_overlays.remove_vis_overlay(src, overlays_to_remove)
+
+ if(occupant)
+ SSvis_overlays.add_vis_overlay(src, 'icons/obj/machines/stasis.dmi', "tubes", LYING_MOB_LAYER + 0.1, plane, dir) //using vis_overlays instead of normal overlays for mouse_opacity here
+
+ if(stat & BROKEN)
+ icon_state = "stasis_broken"
+ return
+ if(panel_open || stat & MAINT)
+ icon_state = "stasis_maintenance"
+ return
+ icon_state = "stasis"
+
+/obj/machinery/stasis/obj_break(damage_flag)
+ . = ..()
+ play_power_sound()
+ update_icon()
+
+/obj/machinery/stasis/power_change()
+ . = ..()
+ play_power_sound()
+ update_icon()
+
+/obj/machinery/stasis/proc/chill_out(mob/living/target)
+ if(target != occupant)
+ return
+ var/freq = rand(24750, 26550)
+ playsound(src, 'sound/effects/spray.ogg', 5, TRUE, 2, frequency = freq)
+ target.SetStasis(TRUE)
+ target.ExtinguishMob()
+ use_power = ACTIVE_POWER_USE
+
+/obj/machinery/stasis/proc/thaw_them(mob/living/target)
+ target.SetStasis(FALSE)
+ if(target == occupant)
+ use_power = IDLE_POWER_USE
+
+/obj/machinery/stasis/post_buckle_mob(mob/living/L)
+ if(!can_be_occupant(L))
+ return
+ occupant = L
+ if(stasis_running() && check_nap_violations())
+ chill_out(L)
+ update_icon()
+
+/obj/machinery/stasis/post_unbuckle_mob(mob/living/L)
+ thaw_them(L)
+ if(L == occupant)
+ occupant = null
+ update_icon()
+
+/obj/machinery/stasis/process()
+ if( !( occupant && isliving(occupant) && check_nap_violations() ) )
+ use_power = IDLE_POWER_USE
+ return
+ var/mob/living/L_occupant = occupant
+ if(stasis_running())
+ if(!L_occupant.IsInStasis())
+ chill_out(L_occupant)
+ else if(L_occupant.IsInStasis())
+ thaw_them(L_occupant)
+
+/obj/machinery/stasis/screwdriver_act(mob/living/user, obj/item/I)
+ . = default_deconstruction_screwdriver(user, "stasis_maintenance", "stasis", I)
+ update_icon()
+
+/obj/machinery/stasis/crowbar_act(mob/living/user, obj/item/I)
+ return default_deconstruction_crowbar(I)
+
+/obj/machinery/stasis/nap_violation(mob/violator)
+ unbuckle_mob(violator, TRUE)
+#undef STASIS_TOGGLE_COOLDOWN
diff --git a/code/game/objects/items/circuitboards/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machine_circuitboards.dm
index 40f6aa9fbf1..4d6ac1d131a 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -1002,3 +1002,11 @@
build_path = /obj/machinery/fat_sucker
req_components = list(/obj/item/stock_parts/micro_laser = 1,
/obj/item/kitchen/fork = 1)
+
+/obj/item/circuitboard/machine/stasis
+ name = "Lifeform Stasis Unit (Machine Board)"
+ build_path = /obj/machinery/stasis
+ req_components = list(
+ /obj/item/stack/cable_coil = 3,
+ /obj/item/stock_parts/manipulator = 1,
+ /obj/item/stock_parts/capacitor = 1)
diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm
index e2e3c13516c..108767b07b7 100644
--- a/code/modules/mining/equipment/survival_pod.dm
+++ b/code/modules/mining/equipment/survival_pod.dm
@@ -138,6 +138,26 @@
else
add_overlay("sleeper_cover")
+//Lifeform Stasis Unit
+/obj/machinery/stasis/survival_pod
+ icon = 'icons/obj/lavaland/survival_pod.dmi'
+ icon_state = "sleeper"
+ mattress_state = null
+ buckle_lying = 270
+
+/obj/machinery/stasis/survival_pod/play_power_sound()
+ return
+
+/obj/machinery/stasis/survival_pod/update_icon()
+ return
+
+//NanoMed
+/obj/machinery/vending/wallmed/survival_pod
+ name = "survival pod medical supply"
+ desc = "Wall-mounted Medical Equipment dispenser. This one seems just a tiny bit smaller."
+ refill_canister = null
+ onstation = FALSE
+
//Computer
/obj/item/gps/computer
name = "pod computer"
diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm
index 5cd1e5cd595..51fe5e2e100 100644
--- a/code/modules/mob/living/carbon/alien/larva/life.dm
+++ b/code/modules/mob/living/carbon/alien/larva/life.dm
@@ -4,7 +4,7 @@
set invisibility = 0
if (notransform)
return
- if(..()) //not dead
+ if(..() && !IsInStasis()) //not dead and not in stasis
// GROW!
if(amount_grown < max_grown)
amount_grown++
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index a71f5390518..ca3e63f38d4 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -28,25 +28,26 @@
if (QDELETED(src))
return 0
- if(.) //not dead
- handle_active_genes()
+ if(!IsInStasis())
+ if(.) //not dead
+ handle_active_genes()
- if(stat != DEAD)
- //heart attack stuff
- handle_heart()
+ if(stat != DEAD)
+ //heart attack stuff
+ handle_heart()
- if(stat != DEAD)
- //Stuff jammed in your limbs hurts
- handle_embedded_objects()
+ if(stat != DEAD)
+ //Stuff jammed in your limbs hurts
+ handle_embedded_objects()
- if(stat != DEAD)
- handle_hygiene()
+ if(stat != DEAD)
+ handle_hygiene()
+
+ dna.species.spec_life(src) // for mutantraces
//Update our name based on whether our face is obscured/disfigured
name = get_visible_name()
- dna.species.spec_life(src) // for mutantraces
-
if(stat != DEAD)
return 1
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index bf39ee76404..8d8a939762f 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -8,28 +8,33 @@
damageoverlaytemp = 0
update_damage_hud()
- if(stat != DEAD) //Reagent processing needs to come before breathing, to prevent edge cases.
- handle_organs()
+ if(!IsInStasis())
- . = ..()
+ if(stat != DEAD) //Reagent processing needs to come before breathing, to prevent edge cases.
+ handle_organs()
- if (QDELETED(src))
- return
+ . = ..()
- if(.) //not dead
- handle_blood()
+ if (QDELETED(src))
+ return
- if(stat != DEAD)
- var/bprv = handle_bodyparts()
- if(bprv & BODYPART_LIFE_UPDATE_HEALTH)
- updatehealth()
- update_stamina()
+ if(.) //not dead
+ handle_blood()
- if(stat != DEAD)
- handle_brain_damage()
+ if(stat != DEAD)
+ var/bprv = handle_bodyparts()
+ if(bprv & BODYPART_LIFE_UPDATE_HEALTH)
+ updatehealth()
+ update_stamina()
- if(stat != DEAD)
- handle_liver()
+ if(stat != DEAD)
+ handle_brain_damage()
+
+ if(stat != DEAD)
+ handle_liver()
+
+ else
+ . = ..()
if(stat == DEAD)
stop_sound_channel(CHANNEL_HEARTBEAT)
diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm
index 6b7c1e46c2b..624ed6d0160 100644
--- a/code/modules/mob/living/carbon/monkey/life.dm
+++ b/code/modules/mob/living/carbon/monkey/life.dm
@@ -9,7 +9,7 @@
if (notransform)
return
- if(..())
+ if(..() && !IsInStasis())
if(!client)
if(stat == CONSCIOUS)
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 26b194eb5cf..923e378fbb4 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -33,44 +33,45 @@
return
if(!loc)
return
- var/datum/gas_mixture/environment = loc.return_air()
- if(stat != DEAD)
- //Mutations and radiation
- handle_mutations_and_radiation()
+ if(!IsInStasis())
- if(stat != DEAD)
- //Breathing, if applicable
- handle_breathing(times_fired)
+ if(stat != DEAD)
+ //Mutations and radiation
+ handle_mutations_and_radiation()
- handle_diseases()// DEAD check is in the proc itself; we want it to spread even if the mob is dead, but to handle its disease-y properties only if you're not.
+ if(stat != DEAD)
+ //Breathing, if applicable
+ handle_breathing(times_fired)
- if (QDELETED(src)) // diseases can qdel the mob via transformations
- return
+ handle_diseases()// DEAD check is in the proc itself; we want it to spread even if the mob is dead, but to handle its disease-y properties only if you're not.
- if(stat != DEAD)
- //Random events (vomiting etc)
- handle_random_events()
+ if (QDELETED(src)) // diseases can qdel the mob via transformations
+ return
- //Handle temperature/pressure differences between body and environment
- if(environment)
- handle_environment(environment)
+ if(stat != DEAD)
+ //Random events (vomiting etc)
+ handle_random_events()
+
+ //Handle temperature/pressure differences between body and environment
+ var/datum/gas_mixture/environment = loc.return_air()
+ if(environment)
+ handle_environment(environment)
+
+ //stuff in the stomach
+ handle_stomach()
+
+ handle_gravity()
+
+ if(stat != DEAD)
+ handle_traits() // eye, ear, brain damages
+ handle_status_effects() //all special effects, stun, knockdown, jitteryness, hallucination, sleeping, etc
handle_fire()
- //stuff in the stomach
- handle_stomach()
-
- handle_gravity()
-
if(machine)
machine.check_eye(src)
- if(stat != DEAD)
- handle_traits() // eye, ear, brain damages
- if(stat != DEAD)
- handle_status_effects() //all special effects, stun, knockdown, jitteryness, hallucination, sleeping, etc
-
if(stat != DEAD)
return 1
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index e54634376ac..9f6616d96fd 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -382,8 +382,8 @@
to_chat(src, "You have given up life and succumbed to death.")
death()
-/mob/living/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, check_immobilized = FALSE)
- if(stat || IsUnconscious() || IsStun() || IsParalyzed() || (check_immobilized && IsImmobilized()) || (!ignore_restraints && restrained(ignore_grab)))
+/mob/living/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, check_immobilized = FALSE, ignore_stasis = FALSE)
+ if(stat || IsUnconscious() || IsStun() || IsParalyzed() || (check_immobilized && IsImmobilized()) || (!ignore_restraints && restrained(ignore_grab)) || (!ignore_stasis && IsInStasis()))
return TRUE
/mob/living/canUseStorage()
@@ -678,7 +678,7 @@
..(pressure_difference, direction, pressure_resistance_prob_delta)
/mob/living/can_resist()
- return !((next_move > world.time) || incapacitated(ignore_restraints = TRUE))
+ return !((next_move > world.time) || incapacitated(ignore_restraints = TRUE, ignore_stasis = TRUE))
/mob/living/verb/resist()
set name = "Resist"
@@ -1097,7 +1097,8 @@
var/stun = IsStun()
var/knockdown = IsKnockdown()
var/ignore_legs = get_leg_ignore()
- var/canmove = !IsImmobilized() && !stun && conscious && !paralyzed && !buckled && (!stat_softcrit || !pulledby) && !chokehold && !IsFrozen() && (has_arms || ignore_legs || has_legs)
+ var/in_stasis = IsInStasis()
+ var/canmove = !IsImmobilized() && !stun && conscious && !paralyzed && !buckled && (!stat_softcrit || !pulledby) && !chokehold && !IsFrozen() && !in_stasis && (has_arms || ignore_legs || has_legs)
if(canmove)
mobility_flags |= MOBILITY_MOVE
else
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index b5747b1f65e..1d41e25a334 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -374,6 +374,14 @@
priority_absorb_key["stuns_absorbed"] += amount
return TRUE
+/////////////////////////////////// STASIS ///////////////////////////////////
+
+/mob/living/proc/IsInStasis()
+ . = has_status_effect(STATUS_EFFECT_STASIS)
+
+/mob/living/proc/SetStasis(apply, updating = TRUE)
+ . = apply ? apply_status_effect(STATUS_EFFECT_STASIS, null, updating) : remove_status_effect(STATUS_EFFECT_STASIS)
+
/////////////////////////////////// DISABILITIES ////////////////////////////////////
/mob/living/proc/add_quirk(quirktype, spawn_effects) //separate proc due to the way these ones are handled
if(HAS_TRAIT(src, quirktype))
diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm
index 9e9ac487cf4..1da282f673f 100644
--- a/code/modules/research/designs/machine_designs.dm
+++ b/code/modules/research/designs/machine_designs.dm
@@ -130,14 +130,6 @@
category = list("Teleportation Machinery")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE
-/datum/design/board/sleeper
- name = "Machine Design (Sleeper Board)"
- desc = "The circuit board for a sleeper."
- id = "sleeper"
- build_path = /obj/item/circuitboard/machine/sleeper
- departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_MEDICAL
- category = list ("Medical Machinery")
-
/datum/design/board/vr_sleeper
name = "Machine Design (VR Sleeper Board)"
desc = "The circuit board for a VR sleeper."
@@ -593,4 +585,12 @@
id = "fat_sucker"
build_path = /obj/item/circuitboard/machine/fat_sucker
category = list ("Misc. Machinery")
- departmental_flags = DEPARTMENTAL_FLAG_SERVICE
\ No newline at end of file
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
+
+/datum/design/board/stasis
+ name = "Machine Design (Lifeform Stasis Unit)"
+ desc = "The circuit board for a stasis unit."
+ id = "stasis"
+ build_path = /obj/item/circuitboard/machine/stasis
+ category = list("Medical Machinery")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 9dc1973cd02..0587c7f6077 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -56,7 +56,7 @@
display_name = "Biological Technology"
description = "What makes us tick." //the MC, silly!
prereq_ids = list("base")
- design_ids = list("chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibrillator", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "medspray","genescanner")
+ design_ids = list("chem_heater", "chem_master", "chem_dispenser", "vr_sleeper", "pandemic", "defibrillator", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "medspray","genescanner")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -435,7 +435,7 @@
display_name = "Cryostasis Technology"
description = "Smart freezing of objects to preserve them!"
prereq_ids = list("adv_engi", "biotech")
- design_ids = list("splitbeaker", "noreactsyringe", "cryotube", "cryo_Grenade")
+ design_ids = list("splitbeaker", "noreactsyringe", "cryotube", "cryo_Grenade", "stasis")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000)
export_price = 4000
diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi
old mode 100644
new mode 100755
index cff1a390651..9550d879aa9
Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ
diff --git a/icons/obj/machines/stasis.dmi b/icons/obj/machines/stasis.dmi
new file mode 100755
index 00000000000..d63d8e24d3f
Binary files /dev/null and b/icons/obj/machines/stasis.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 714cd100ecf..67324024493 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -619,6 +619,7 @@
#include "code\game\machinery\Sleeper.dm"
#include "code\game\machinery\slotmachine.dm"
#include "code\game\machinery\spaceheater.dm"
+#include "code\game\machinery\stasis.dm"
#include "code\game\machinery\status_display.dm"
#include "code\game\machinery\suit_storage_unit.dm"
#include "code\game\machinery\syndicatebeacon.dm"