From c36019bf56bb3cb7e9de2d73de45d4cbf760d24e Mon Sep 17 00:00:00 2001
From: Artur <24881678+Arturlang@users.noreply.github.com>
Date: Wed, 6 Apr 2022 15:38:05 +0300
Subject: [PATCH] Adds stasis beds
---
_maps/map_files/generic/CentCom.dmm | 8 +-
code/__DEFINES/status_effects.dm | 3 +
code/__DEFINES/traits.dm | 4 +
code/__HELPERS/mobs.dm | 2 +
code/__HELPERS/time.dm | 8 +-
code/controllers/subsystem/traumas.dm | 2 +-
code/controllers/subsystem/vis_overlays.dm | 18 +++
code/datums/status_effects/debuffs.dm | 50 ++++++-
code/game/machinery/stasis.dm | 141 ++++++++++++++++++
.../circuitboards/machine_circuitboards.dm | 8 +
code/modules/mining/equipment/survival_pod.dm | 20 +++
code/modules/mob/living/life.dm | 8 +-
code/modules/mob/living/living.dm | 4 +-
icons/obj/machines/stasis.dmi | Bin 0 -> 4025 bytes
tgstation.dme | 1 +
15 files changed, 257 insertions(+), 20 deletions(-)
create mode 100644 code/game/machinery/stasis.dm
create mode 100644 icons/obj/machines/stasis.dmi
diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm
index 4fb880fb4d..4a17fef999 100644
--- a/_maps/map_files/generic/CentCom.dmm
+++ b/_maps/map_files/generic/CentCom.dmm
@@ -1120,9 +1120,7 @@
/obj/structure/window{
dir = 8
},
-/obj/machinery/sleeper{
- dir = 1
- },
+/obj/machinery/stasis,
/turf/open/floor/holofloor{
icon_state = "white"
},
@@ -1134,9 +1132,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/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index e3c928a9a9..b29daa85f6 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -153,3 +153,6 @@
/////////////
#define STASIS_ASCENSION_EFFECT "heretic_ascension"
+
+/// If the incapacitated status effect will ignore a mob in stasis (stasis beds)
+#define IGNORE_STASIS (1<<1)
\ No newline at end of file
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index e1154b305f..daec1ce4c2 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -70,6 +70,10 @@
#define HAS_TRAIT_NOT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (length(target.status_traits[trait] - source) > 0) : FALSE) : FALSE)
//mob traits
+/// Prevents voluntary movement.
+#define TRAIT_IMMOBILIZED "immobilized"
+/// Prevents usage of manipulation appendages (picking, holding or using items, manipulating storage).
+#define TRAIT_HANDS_BLOCKED "handsblocked"
#define TRAIT_BLIND "blind"
#define TRAIT_MUTE "mute"
#define TRAIT_EMOTEMUTE "emotemute"
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index d113b8b789..4cd82f9e66 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -484,3 +484,5 @@ GLOBAL_LIST_EMPTY(species_datums)
//check if the person is dead, not sure where to put this
#define IS_DEAD_OR_INCAP(source) (source.incapacitated() || source.stat)
+
+#define IS_IN_STASIS(mob) (mob.has_status_effect(/datum/status_effect/grouped/stasis))
diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm
index 2e27588ae5..519a54b38d 100644
--- a/code/__HELPERS/time.dm
+++ b/code/__HELPERS/time.dm
@@ -75,10 +75,8 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
/proc/daysSince(realtimev)
return round((world.realtime - realtimev) / (24 HOURS))
-/proc/worldtime2text()
- return gameTimestamp("hh:mm:ss", world.time)
+/proc/worldtime2text(wtime = world.timeofday)
+ return gameTimestamp("hh:mm:ss", wtime)
-/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
- if(!wtime)
- wtime = world.time
+/proc/gameTimestamp(format = "hh:mm:ss", wtime=world.time)
return time2text(wtime - GLOB.timezoneOffset, format)
diff --git a/code/controllers/subsystem/traumas.dm b/code/controllers/subsystem/traumas.dm
index 9a0665e91f..56865f8567 100644
--- a/code/controllers/subsystem/traumas.dm
+++ b/code/controllers/subsystem/traumas.dm
@@ -107,7 +107,7 @@ SUBSYSTEM_DEF(traumas)
/obj/item/clothing/under/rank/medical/doctor/nurse, /obj/item/clothing/under/rank/medical/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 b0e5d6c689..b672217480 100644
--- a/code/controllers/subsystem/vis_overlays.dm
+++ b/code/controllers/subsystem/vis_overlays.dm
@@ -7,10 +7,12 @@ SUBSYSTEM_DEF(vis_overlays)
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 ..()
/datum/controller/subsystem/vis_overlays/fire(resumed = FALSE)
@@ -55,6 +57,7 @@ SUBSYSTEM_DEF(vis_overlays)
if(!thing.managed_vis_overlays)
thing.managed_vis_overlays = list(overlay)
+ RegisterSignal(thing, COMSIG_ATOM_DIR_CHANGE, rotate_cb)
else
thing.managed_vis_overlays += overlay
return overlay
@@ -78,3 +81,18 @@ SUBSYSTEM_DEF(vis_overlays)
thing.managed_vis_overlays -= overlays
if(!length(thing.managed_vis_overlays))
thing.managed_vis_overlays = null
+ UnregisterSignal(thing, COMSIG_ATOM_DIR_CHANGE)
+
+/datum/controller/subsystem/vis_overlays/proc/rotate_vis_overlay(atom/thing, old_dir, new_dir)
+ if(old_dir == new_dir)
+ return
+ var/rotation = dir2angle(old_dir) - dir2angle(new_dir)
+ var/list/overlays_to_remove = list()
+ 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 b5a7a38915..b7680c0d80 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -127,13 +127,61 @@
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"
-
/datum/status_effect/grouped/stasis
id = "stasis"
duration = -1
tick_interval = 10
+ alert_type = /atom/movable/screen/alert/status_effect/stasis
var/last_dead_time
+/datum/status_effect/grouped/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 = gameTimestamp(wtime=new_timeofdeath)
+ last_dead_time = null
+ if(owner.stat == DEAD)
+ last_dead_time = world.time
+
+/datum/status_effect/grouped/stasis/on_creation(mob/living/new_owner, set_duration)
+ . = ..()
+ if(.)
+ update_time_of_death()
+ owner.reagents?.end_metabolization(owner, FALSE)
+
+/datum/status_effect/grouped/stasis/on_apply()
+ . = ..()
+ if(!.)
+ return
+ owner.mobility_flags &= ~MOBILITY_USE
+ owner.mobility_flags &= ~MOBILITY_PICKUP
+ owner.mobility_flags &= ~MOBILITY_PULL
+ owner.mobility_flags &= ~MOBILITY_HOLD
+ owner.update_mobility()
+ owner.add_filter("stasis_status_ripple", 2, list("type" = "ripple", "flags" = WAVE_BOUNDED, "radius" = 0, "size" = 2))
+ var/filter = owner.get_filter("stasis_status_ripple")
+ animate(filter, radius = 32, time = 15, size = 0, loop = -1)
+
+
+/datum/status_effect/grouped/stasis/tick()
+ update_time_of_death()
+
+/datum/status_effect/grouped/stasis/on_remove()
+ owner.mobility_flags |= MOBILITY_USE
+ owner.mobility_flags |= MOBILITY_PICKUP
+ owner.mobility_flags |= MOBILITY_PULL
+ owner.mobility_flags |= MOBILITY_HOLD
+ owner.update_mobility()
+ owner.remove_filter("stasis_status_ripple")
+ update_time_of_death()
+ return ..()
+
+/atom/movable/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"
+
/datum/status_effect/robotic_emp
id = "emp_no_combat_mode"
diff --git a/code/game/machinery/stasis.dm b/code/game/machinery/stasis.dm
new file mode 100644
index 0000000000..5f7f0263db
--- /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 cb1d4aae88..c42d40db83 100644
--- a/code/game/objects/items/circuitboards/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machine_circuitboards.dm
@@ -1482,3 +1482,11 @@
icon_state = "engineering"
build_path = /obj/machinery/research/explosive_compressor
req_components = list(/obj/item/stock_parts/matter_bin = 3)
+
+/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)
\ No newline at end of file
diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm
index ba4b02fcf4..36e9d0a9a9 100644
--- a/code/modules/mining/equipment/survival_pod.dm
+++ b/code/modules/mining/equipment/survival_pod.dm
@@ -162,6 +162,26 @@
if(!state_open)
. += "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/life.dm b/code/modules/mob/living/life.dm
index 0c73c623d1..18a500f6f4 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -6,11 +6,12 @@
SHOULD_NOT_SLEEP(TRUE)
if(mob_transforming)
return
-
+ handle_traits() // eye, ear, brain damages
+ handle_status_effects() //all special effects, stun, knockdown, jitteryness, hallucination, sleeping, etc
. = SEND_SIGNAL(src, COMSIG_LIVING_LIFE, seconds, times_fired)
if(!(. & COMPONENT_INTERRUPT_LIFE_PHYSICAL))
PhysicalLife(seconds, times_fired)
- if(!(. & COMPONENT_INTERRUPT_LIFE_BIOLOGICAL))
+ if(!(. & COMPONENT_INTERRUPT_LIFE_BIOLOGICAL) && !IS_IN_STASIS())
BiologicalLife(seconds, times_fired)
// CODE BELOW SHOULD ONLY BE THINGS THAT SHOULD HAPPEN NO MATTER WHAT AND CAN NOT BE SUSPENDED!
@@ -69,9 +70,6 @@
handle_block_parry(seconds)
- // These two MIGHT need to be moved to base Life() if we get any in the future that's a "physical" effect that needs to fire even while in stasis.
- handle_traits() // eye, ear, brain damages
- handle_status_effects() //all special effects, stun, knockdown, jitteryness, hallucination, sleeping, etc
return TRUE
/**
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index bf3094cb08..e4ffb94493 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -433,8 +433,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() || (combat_flags & COMBAT_FLAG_HARD_STAMCRIT) || (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() || (combat_flags & COMBAT_FLAG_HARD_STAMCRIT) || (check_immobilized && IsImmobilized()) || (!ignore_restraints && restrained(ignore_grab)) || (!ignore_stasis && IS_IN_STASIS()))
return TRUE
/mob/living/canUseStorage()
diff --git a/icons/obj/machines/stasis.dmi b/icons/obj/machines/stasis.dmi
new file mode 100644
index 0000000000000000000000000000000000000000..21844b0f8d50e111db85ed451cb73287e37e5096
GIT binary patch
literal 4025
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
literal 0
HcmV?d00001
diff --git a/tgstation.dme b/tgstation.dme
index cb2fa07f50..b019ea10b1 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -912,6 +912,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"