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"