diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index 53b12ca0bb..55ed3e72ff 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -35129,9 +35129,6 @@
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"bDD" = (
-/obj/structure/sign/warning/nosmoking{
- pixel_x = -28
- },
/obj/structure/bed,
/obj/item/bedsheet/medical,
/obj/effect/turf_decal/tile/blue{
@@ -36070,6 +36067,9 @@
"bFJ" = (
/obj/structure/bed,
/obj/item/bedsheet/medical,
+/obj/structure/sign/warning/nosmoking{
+ pixel_x = -28
+ },
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"bFK" = (
@@ -57530,6 +57530,10 @@
},
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
+"nWU" = (
+/obj/machinery/smartfridge/organ/preloaded,
+/turf/closed/wall,
+/area/medical/sleeper)
"oce" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 1
@@ -93288,7 +93292,7 @@ bvj
bvj
bvd
bFu
-bvj
+nWU
bvj
bvd
bKH
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index d9d46066bf..ac7d291b2f 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -103794,10 +103794,10 @@
/turf/open/floor/plasteel/white,
/area/medical/medbay/central)
"dsI" = (
-/obj/structure/sign/warning/nosmoking,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
+/obj/machinery/smartfridge/organ/preloaded,
/turf/closed/wall,
/area/medical/surgery)
"dsJ" = (
@@ -127428,6 +127428,10 @@
/obj/item/assembly/signaler,
/turf/open/floor/plating,
/area/crew_quarters/abandoned_gambling_den)
+"mMC" = (
+/obj/structure/sign/warning/nosmoking,
+/turf/closed/wall,
+/area/medical/surgery)
"mQE" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
@@ -174919,7 +174923,7 @@ dkv
dma
dma
dma
-dma
+mMC
dsI
dro
dvz
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index f72a787214..0e6feb67c6 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -62776,6 +62776,9 @@
"cro" = (
/obj/structure/bed/roller,
/obj/machinery/iv_drip,
+/obj/structure/sign/warning/nosmoking{
+ pixel_x = -28
+ },
/turf/open/floor/plasteel/white,
/area/medical/surgery)
"crq" = (
@@ -63296,9 +63299,6 @@
dir = 1;
pixel_y = -22
},
-/obj/structure/sign/warning/nosmoking{
- pixel_x = -28
- },
/obj/machinery/iv_drip,
/obj/effect/turf_decal/tile/blue,
/obj/effect/turf_decal/tile/blue{
@@ -83997,6 +83997,10 @@
},
/turf/open/floor/plating,
/area/maintenance/port)
+"qnB" = (
+/obj/machinery/smartfridge/organ/preloaded,
+/turf/closed/wall,
+/area/medical/surgery)
"qqg" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 6
@@ -104229,7 +104233,7 @@ cia
cia
cpX
cia
-cia
+qnB
cia
ceu
dyg
diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm
index a7ab212bd6..bd3d72dc85 100644
--- a/_maps/map_files/OmegaStation/OmegaStation.dmm
+++ b/_maps/map_files/OmegaStation/OmegaStation.dmm
@@ -42880,6 +42880,12 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/closed/wall/r_wall,
/area/maintenance/disposal/incinerator)
+"uvp" = (
+/obj/machinery/smartfridge/organ/preloaded{
+ pixel_y = 2
+ },
+/turf/closed/wall,
+/area/medical/medbay/zone3)
"uxJ" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/public/glass{
@@ -81595,7 +81601,7 @@ aSh
bcf
bcW
blt
-aSh
+uvp
aOL
bfA
bfX
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index d70bc0187b..9f1c1824cd 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -37749,6 +37749,9 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/light_switch{
+ pixel_x = -22
+ },
/turf/open/floor/plasteel/white,
/area/medical/surgery)
"bIp" = (
@@ -38828,10 +38831,6 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 1
},
-/obj/machinery/firealarm{
- dir = 8;
- pixel_x = -26
- },
/obj/effect/turf_decal/tile/blue{
dir = 1
},
@@ -39305,15 +39304,16 @@
/obj/item/clothing/gloves/color/latex,
/obj/item/clothing/mask/surgical,
/obj/item/clothing/suit/apron/surgical,
-/obj/machinery/light_switch{
- pixel_x = -22
- },
/obj/effect/turf_decal/tile/blue{
dir = 1
},
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/machinery/firealarm{
+ dir = 8;
+ pixel_x = -26
+ },
/turf/open/floor/plasteel/white,
/area/medical/surgery)
"bLN" = (
@@ -55674,6 +55674,10 @@
},
/turf/open/floor/plasteel,
/area/hallway/primary/central)
+"jdA" = (
+/obj/machinery/smartfridge/organ/preloaded,
+/turf/closed/wall,
+/area/medical/surgery)
"jeq" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -92221,7 +92225,7 @@ bFU
bFU
bIn
bJt
-bFU
+jdA
bFU
bFU
bFU
diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index b79f1c2e59..9dad2926f8 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -5,6 +5,11 @@
#define COMPONENT_INCOMPATIBLE 1
#define COMPONENT_NOTRANSFER 2
+#define ELEMENT_INCOMPATIBLE 1 // Return value to cancel attaching
+
+// /datum/element flags
+#define ELEMENT_DETACH (1 << 0)
+
// How multiple components of the exact same type are handled in the same datum
#define COMPONENT_DUPE_HIGHLANDER 0 //old component is deleted (default)
@@ -28,7 +33,7 @@
#define COMSIG_COMPONENT_ADDED "component_added" //when a component is added to a datum: (/datum/component)
#define COMSIG_COMPONENT_REMOVING "component_removing" //before a component is removed from a datum because of RemoveComponent: (/datum/component)
#define COMSIG_PARENT_PREQDELETED "parent_preqdeleted" //before a datum's Destroy() is called: (force), returning a nonzero value will cancel the qdel operation
-#define COMSIG_PARENT_QDELETED "parent_qdeleted" //after a datum's Destroy() is called: (force, qdel_hint), at this point none of the other components chose to interrupt qdel and Destroy has been called
+#define COMSIG_PARENT_QDELETING "parent_qdeleting" //just before a datum's Destroy() is called: (force), at this point none of the other components chose to interrupt qdel and Destroy will be called
// /atom signals
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm
index d3e724aefb..94c2c372f0 100644
--- a/code/__DEFINES/obj_flags.dm
+++ b/code/__DEFINES/obj_flags.dm
@@ -25,23 +25,22 @@
#define NO_MAT_REDEMPTION (1<<5) //Stops you from putting things like an RCD or other items into an ORM or protolathe for materials.
#define DROPDEL (1<<6) //When dropped, it calls qdel on itself
#define NOBLUDGEON (1<<7) //when an item has this it produces no "X has been hit by Y with Z" message in the default attackby()
-#define ABSTRACT (1<<8) //for all things that are technically items but used for various different stuff
+#define ABSTRACT (1<<8) //for all things that are technically items but used for various different stuff
#define IMMUTABLE_SLOW (1<<9) //When players should not be able to change the slowdown of the item (Speed potions, ect)
#define SURGICAL_TOOL (1<<10) //Tool commonly used for surgery: won't attack targets in an active surgical operation on help intent (in case of mistakes)
-#define NO_UNIFORM_REQUIRED (1<<11) //Can be worn on certain slots (currently belt and id) that would otherwise require an uniform.
+#define NO_UNIFORM_REQUIRED (1<<11) //Can be worn on certain slots (currently belt and id) that would otherwise require an uniform.
// Flags for the clothing_flags var on /obj/item/clothing
#define LAVAPROTECT (1<<0)
#define STOPSPRESSUREDAMAGE (1<<1) //SUIT and HEAD items which stop pressure damage. To stop you taking all pressure damage you must have both a suit and head item with this flag.
#define BLOCK_GAS_SMOKE_EFFECT (1<<2) //blocks the effect that chemical clouds would have on a mob --glasses, mask and helmets ONLY!
-#define ALLOWINTERNALS (1<<3) //mask allows internals
+#define ALLOWINTERNALS (1<<3) //mask allows internals
#define NOSLIP (1<<4) //prevents from slipping on wet floors, in space etc
#define THICKMATERIAL (1<<5) //prevents syringes, parapens and hypos if the external suit or helmet (if targeting head) has this flag. Example: space suits, biosuit, bombsuits, thick suits that cover your body.
#define VOICEBOX_TOGGLABLE (1<<6) //The voicebox in this clothing can be toggled.
#define VOICEBOX_DISABLED (1<<7) //The voicebox is currently turned off.
-#define SNUG_FIT (1<<8) //Prevents knock-off from things like hat-throwing.
-#define ANTI_TINFOIL_MANEUVER (1<<9) //Hats with negative effects when worn (i.e the tinfoil hat).
+#define IGNORE_HAT_TOSS (1<<8) //Hats with negative effects when worn (i.e the tinfoil hat).
// Flags for the organ_flags var on /obj/item/organ
@@ -50,4 +49,4 @@
#define ORGAN_FAILING (1<<2) //Failing organs perform damaging effects until replaced or fixed
#define ORGAN_EXTERNAL (1<<3) //Was this organ implanted/inserted/etc, if true will not be removed during species change.
#define ORGAN_VITAL (1<<4) //Currently only the brain
-#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances
\ No newline at end of file
+#define ORGAN_NO_SPOIL (1<<5) //Do not spoil under any circumstances
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 60212385f8..d3e9131226 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -162,6 +162,7 @@
#define TRAIT_FRIENDLY "friendly"
#define TRAIT_ASSBLASTUSA "assblastusa"
#define TRAIT_CULT_EYES "cult_eyes"
+#define TRAIT_FREESPRINT "free_sprinting"
// common trait sources
@@ -216,4 +217,4 @@
#define NINJA_SUIT_TRAIT "ninja-suit"
#define ANTI_DROP_IMPLANT_TRAIT "anti-drop-implant"
#define ABDUCTOR_ANTAGONIST "abductor-antagonist"
-#define MADE_UNCLONEABLE "made-uncloneable"
\ No newline at end of file
+#define MADE_UNCLONEABLE "made-uncloneable"
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 2c92816264..b899d7f6ab 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -313,14 +313,13 @@
parts += "[FOURSPACES]Threat level: [mode.threat_level]"
parts += "[FOURSPACES]Threat left: [mode.threat]"
parts += "[FOURSPACES]Executed rules:"
+ for(var/datum/dynamic_ruleset/rule in mode.executed_rules)
+ parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - [rule.name]: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat"
+ parts += "[FOURSPACES]Other threat changes:"
for(var/str in mode.threat_log)
parts += "[FOURSPACES][FOURSPACES][str]"
for(var/entry in mode.threat_tallies)
parts += "[FOURSPACES][FOURSPACES][entry] added [mode.threat_tallies[entry]]"
- /*
- for(var/datum/dynamic_ruleset/rule in mode.executed_rules)
- parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - [rule.name]: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat"
- */
return parts.Join("
")
/client/proc/roundend_report_file()
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 91f5105553..e0cf8ebdd5 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -142,8 +142,7 @@ GLOBAL_LIST_INIT(bitfields, list(
"THICKMATERIAL" = THICKMATERIAL,
"VOICEBOX_TOGGLABLE" = VOICEBOX_TOGGLABLE,
"VOICEBOX_DISABLED" = VOICEBOX_DISABLED,
- "SNUG_FIT" = SNUG_FIT,
- "ANTI_TINFOIL_MANEUVER" = ANTI_TINFOIL_MANEUVER,
+ "IGNORE_HAT_TOSS" = IGNORE_HAT_TOSS,
),
"tesla_flags" = list(
"TESLA_MOB_DAMAGE" = TESLA_MOB_DAMAGE,
diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm
index 0ac8a61183..e2705ad49f 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -46,10 +46,15 @@ GLOBAL_LIST_INIT(ai_core_display_screens, list(
":thinking:",
"Alien",
"Angel",
+ "Angryface",
+ "AtlantisCZE",
"Banned",
"Bliss",
"Blue",
- "Clown",
+ "Boy",
+ "Boy-Malf",
+ "Girl",
+ "Girl-Malf",
"Database",
"Dorf",
"Firewall",
@@ -61,26 +66,44 @@ GLOBAL_LIST_INIT(ai_core_display_screens, list(
"Hades",
"Heartline",
"Helios",
+ "Hotdog",
+ "Hourglass",
"House",
"Inverted",
+ "Jack",
"Matrix",
"Monochrome",
+ "Mothman",
"Murica",
"Nanotrasen",
"Not Malf",
+ "Patriot",
+ "Pirate",
"President",
- "Random",
"Rainbow",
- "Red",
+ "Clown",
+ "Random",
+ "Ravensdale",
"Red October",
+ "Red",
+ "Royal",
+ "Searif",
+ "Serithi",
+ "SilveryFerret",
+ "Smiley",
"Static",
"Syndicat Meow",
"TechDemon",
+ "Terminal",
"Text",
"Too Deep",
"Triumvirate",
"Triumvirate-M",
- "Weird"))
+ "Wasp",
+ "Weird",
+ "Xerxes",
+ "Yes-Man"
+ ))
/proc/resolve_ai_icon(input)
if(!input || !(input in GLOB.ai_core_display_screens))
diff --git a/code/_globalvars/lists/typecache.dm b/code/_globalvars/lists/typecache.dm
index 96807214f2..1ec3de0bc5 100644
--- a/code/_globalvars/lists/typecache.dm
+++ b/code/_globalvars/lists/typecache.dm
@@ -10,3 +10,5 @@ GLOBAL_LIST_INIT(typecache_living, typecacheof(/mob/living))
GLOBAL_LIST_INIT(typecache_stack, typecacheof(/obj/item/stack))
GLOBAL_LIST_INIT(typecache_machine_or_structure, typecacheof(list(/obj/machinery, /obj/structure)))
+
+GLOBAL_LIST_INIT(freezing_objects, typecacheof(list(/obj/structure/closet/crate/freezer, /obj/structure/closet/secure_closet/freezer, /obj/structure/bodycontainer, /obj/item/autosurgeon, /obj/machinery/smartfridge/organ))) //list of all cold objects, that freeze organs when inside
diff --git a/code/controllers/subsystem/dcs.dm b/code/controllers/subsystem/dcs.dm
index c1e101a0e7..e94f233f04 100644
--- a/code/controllers/subsystem/dcs.dm
+++ b/code/controllers/subsystem/dcs.dm
@@ -1,6 +1,15 @@
-SUBSYSTEM_DEF(dcs)
+PROCESSING_SUBSYSTEM_DEF(dcs)
name = "Datum Component System"
- flags = SS_NO_INIT | SS_NO_FIRE
+ flags = SS_NO_INIT
+ var/list/elements_by_type = list()
-/datum/controller/subsystem/dcs/Recover()
+/datum/controller/subsystem/processing/dcs/Recover()
comp_lookup = SSdcs.comp_lookup
+
+/datum/controller/subsystem/processing/dcs/proc/GetElement(eletype)
+ . = elements_by_type[eletype]
+ if(.)
+ return
+ if(!ispath(eletype, /datum/element))
+ CRASH("Attempted to instantiate [eletype] as a /datum/element")
+ . = elements_by_type[eletype] = new eletype
\ No newline at end of file
diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm
index eec9f63a12..f8ca1e7eae 100644
--- a/code/controllers/subsystem/garbage.dm
+++ b/code/controllers/subsystem/garbage.dm
@@ -98,7 +98,7 @@ SUBSYSTEM_DEF(garbage)
state = SS_RUNNING
break
-
+
/datum/controller/subsystem/garbage/proc/HandleQueue(level = GC_QUEUE_CHECK)
@@ -266,8 +266,8 @@ SUBSYSTEM_DEF(garbage)
D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED
var/start_time = world.time
var/start_tick = world.tick_usage
+ SEND_SIGNAL(D, COMSIG_PARENT_QDELETING, force) // Let the (remaining) components know about the result of Destroy
var/hint = D.Destroy(arglist(args.Copy(2))) // Let our friend know they're about to get fucked up.
- SEND_SIGNAL(D, COMSIG_PARENT_QDELETED, force, hint) // Let the (remaining) components know about the result of Destroy
if(world.time != start_time)
I.slept_destroy++
else
diff --git a/code/controllers/subsystem/traumas.dm b/code/controllers/subsystem/traumas.dm
index fb9e163f91..1ad4a15ee7 100644
--- a/code/controllers/subsystem/traumas.dm
+++ b/code/controllers/subsystem/traumas.dm
@@ -87,7 +87,7 @@ SUBSYSTEM_DEF(traumas)
"skeletons" = typecacheof(list(/obj/item/organ/tongue/bone, /obj/item/clothing/suit/armor/bone, /obj/item/stack/sheet/bone,
/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton,
/obj/effect/decal/remains/human)),
- "conspiracies" = typecacheof(list(/obj/item/clothing/under/rank/captain, /obj/item/clothing/under/rank/head_of_security,
+ "conspiracies" = typecacheof(list(/obj/item/clothing/under/rank/captain, /obj/item/clothing/under/rank/head_of_security,
/obj/item/clothing/under/rank/chief_engineer, /obj/item/clothing/under/rank/chief_medical_officer,
/obj/item/clothing/under/rank/head_of_personnel, /obj/item/clothing/under/rank/research_director,
/obj/item/clothing/under/rank/head_of_security/grey, /obj/item/clothing/under/rank/head_of_security/alt,
diff --git a/code/datums/components/earhealing.dm b/code/datums/components/earhealing.dm
deleted file mode 100644
index bd3d57480d..0000000000
--- a/code/datums/components/earhealing.dm
+++ /dev/null
@@ -1,30 +0,0 @@
-// An item worn in the ear slot with this component will heal your ears each
-// Life() tick, even if normally your ears would be too damaged to heal.
-
-/datum/component/earhealing
- var/mob/living/carbon/wearer
-
-/datum/component/earhealing/Initialize()
- if(!isitem(parent))
- return COMPONENT_INCOMPATIBLE
- RegisterSignal(parent, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED), .proc/equippedChanged)
-
-/datum/component/earhealing/proc/equippedChanged(datum/source, mob/living/carbon/user, slot)
- if (slot == SLOT_EARS && istype(user))
- if (!wearer)
- START_PROCESSING(SSobj, src)
- wearer = user
- else
- if (wearer)
- STOP_PROCESSING(SSobj, src)
- wearer = null
-
-/datum/component/earhealing/process()
- if (!wearer)
- STOP_PROCESSING(SSobj, src)
- return
- if(!HAS_TRAIT(wearer, TRAIT_DEAF))
- var/obj/item/organ/ears/ears = wearer.getorganslot(ORGAN_SLOT_EARS)
- if (ears)
- ears.deaf = max(ears.deaf - 1, (ears.damage < ears.maxHealth ? 0 : 1)) // Do not clear deafness if our ears are too damaged
- ears.damage = max(ears.damage - 0.1, 0)
diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm
index b46919a6c6..a0e6f97de0 100644
--- a/code/datums/components/mood.dm
+++ b/code/datums/components/mood.dm
@@ -248,7 +248,7 @@
var/datum/hud/hud = owner.hud_used
screen_obj = new
hud.infodisplay += screen_obj
- RegisterSignal(hud, COMSIG_PARENT_QDELETED, .proc/unmodify_hud)
+ RegisterSignal(hud, COMSIG_PARENT_QDELETING, .proc/unmodify_hud)
RegisterSignal(screen_obj, COMSIG_CLICK, .proc/hud_click)
/datum/component/mood/proc/unmodify_hud(datum/source)
diff --git a/code/datums/components/virtual_reality.dm b/code/datums/components/virtual_reality.dm
index f8f0679e9b..7bad836e47 100644
--- a/code/datums/components/virtual_reality.dm
+++ b/code/datums/components/virtual_reality.dm
@@ -12,7 +12,7 @@
return COMPONENT_INCOMPATIBLE
var/mob/vr_M = parent
mastermind = M.mind
- RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETED), .proc/game_over)
+ RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING), .proc/game_over)
RegisterSignal(M, COMSIG_MOB_KEY_CHANGE, .proc/switch_player)
RegisterSignal(mastermind, COMSIG_MIND_TRANSFER, .proc/switch_player)
you_die_in_the_game_you_die_for_real = yolo
@@ -32,7 +32,7 @@
current_mind = M.mind
quit_action.Grant(M)
RegisterSignal(quit_action, COMSIG_ACTION_TRIGGER, .proc/revert_to_reality)
- RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETED), .proc/game_over)
+ RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING), .proc/game_over)
RegisterSignal(M, COMSIG_MOB_GHOSTIZE, .proc/be_a_quitter)
RegisterSignal(M, COMSIG_MOB_KEY_CHANGE, .proc/pass_me_the_remote)
RegisterSignal(current_mind, COMSIG_MIND_TRANSFER, .proc/pass_me_the_remote)
@@ -42,7 +42,7 @@
/datum/component/virtual_reality/UnregisterFromParent()
quit_action.Remove(parent)
- UnregisterSignal(parent, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETED, COMSIG_MOB_KEY_CHANGE, COMSIG_MOB_GHOSTIZE))
+ UnregisterSignal(parent, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING, COMSIG_MOB_KEY_CHANGE, COMSIG_MOB_GHOSTIZE))
UnregisterSignal(current_mind, COMSIG_MIND_TRANSFER)
UnregisterSignal(quit_action, COMSIG_ACTION_TRIGGER)
current_mind = null
diff --git a/code/datums/elements/_element.dm b/code/datums/elements/_element.dm
new file mode 100644
index 0000000000..f12835d2e2
--- /dev/null
+++ b/code/datums/elements/_element.dm
@@ -0,0 +1,29 @@
+/datum/element
+ var/element_flags = NONE
+
+/datum/element/proc/Attach(datum/target)
+ if(type == /datum/element)
+ return ELEMENT_INCOMPATIBLE
+ if(element_flags & ELEMENT_DETACH)
+ RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach)
+
+/datum/element/proc/Detach(datum/source, force)
+ UnregisterSignal(source, COMSIG_PARENT_QDELETING)
+
+/datum/element/Destroy(force)
+ if(!force)
+ return QDEL_HINT_LETMELIVE
+ SSdcs.elements_by_type -= type
+ return ..()
+
+//DATUM PROCS
+
+/datum/proc/AddElement(eletype, ...)
+ var/datum/element/ele = SSdcs.GetElement(eletype)
+ args[1] = src
+ if(ele.Attach(arglist(args)) == ELEMENT_INCOMPATIBLE)
+ CRASH("Incompatible [eletype] assigned to a [type]! args: [json_encode(args)]")
+
+/datum/proc/RemoveElement(eletype)
+ var/datum/element/ele = SSdcs.GetElement(eletype)
+ ele.Detach(src)
diff --git a/code/datums/components/cleaning.dm b/code/datums/elements/cleaning.dm
similarity index 79%
rename from code/datums/components/cleaning.dm
rename to code/datums/elements/cleaning.dm
index 5324a87fee..e4fb3edd48 100644
--- a/code/datums/components/cleaning.dm
+++ b/code/datums/elements/cleaning.dm
@@ -1,13 +1,15 @@
-/datum/component/cleaning
- dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
+/datum/element/cleaning/Attach(datum/target)
+ . = ..()
+ if(!ismovableatom(target))
+ return ELEMENT_INCOMPATIBLE
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/Clean)
-/datum/component/cleaning/Initialize()
- if(!ismovableatom(parent))
- return COMPONENT_INCOMPATIBLE
- RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/Clean)
+/datum/element/cleaning/Detach(datum/target)
+ . = ..()
+ UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
-/datum/component/cleaning/proc/Clean()
- var/atom/movable/AM = parent
+/datum/element/cleaning/proc/Clean(datum/source)
+ var/atom/movable/AM = source
var/turf/T = AM.loc
SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
for(var/A in T)
@@ -43,4 +45,4 @@
cleaned_human.clean_blood()
cleaned_human.wash_cream()
cleaned_human.regenerate_icons()
- to_chat(cleaned_human, "[src] cleans your face!")
\ No newline at end of file
+ to_chat(cleaned_human, "[src] cleans your face!")
diff --git a/code/datums/elements/earhealing.dm b/code/datums/elements/earhealing.dm
new file mode 100644
index 0000000000..7477742673
--- /dev/null
+++ b/code/datums/elements/earhealing.dm
@@ -0,0 +1,37 @@
+
+/datum/element/earhealing
+ element_flags = ELEMENT_DETACH
+ var/list/user_by_item = list()
+
+/datum/element/earhealing/New()
+ START_PROCESSING(SSdcs, src)
+
+/datum/element/earhealing/Attach(datum/target)
+ . = ..()
+ if(!isitem(target))
+ return ELEMENT_INCOMPATIBLE
+
+ RegisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED), .proc/equippedChanged)
+
+/datum/element/earhealing/Detach(datum/target)
+ . = ..()
+ UnregisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED))
+ user_by_item -= target
+
+/datum/element/earhealing/proc/equippedChanged(datum/source, mob/living/carbon/user, slot)
+ if(slot == SLOT_EARS && istype(user))
+ user_by_item[source] = user
+ else
+ user_by_item -= source
+
+/datum/element/earhealing/process()
+ for(var/i in user_by_item)
+ var/mob/living/carbon/user = user_by_item[i]
+ if(HAS_TRAIT(user, TRAIT_DEAF))
+ continue
+ var/obj/item/organ/ears/ears = user.getorganslot(ORGAN_SLOT_EARS)
+ if(!ears)
+ continue
+ ears.deaf = max(ears.deaf - 0.25, (ears.damage < ears.maxHealth ? 0 : 1)) // Do not clear deafness if our ears are too damaged
+ ears.damage = max(ears.damage - 0.025, 0)
+ CHECK_TICK
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 5cf03e2684..0ded5f9912 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -91,7 +91,10 @@
if(current) // remove ourself from our old body's mind variable
current.mind = null
SStgui.on_transfer(current, new_character)
-
+ if(iscarbon(current))
+ var/mob/living/carbon/C = current
+ if(C.combatmode)
+ C.toggle_combat_mode(TRUE, TRUE)
if(!language_holder)
var/datum/language_holder/mob_holder = new_character.get_language_holder(shadow = FALSE)
language_holder = mob_holder.copy(src)
diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm
index 65a7c6a954..1a57cf5051 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -189,7 +189,13 @@
if(tod)
var/tdelta = round(world.time - timeofdeath)
if(tdelta < (DEFIB_TIME_LIMIT * 10))
- holder.icon_state = "huddefib"
+ var/obj/item/organ/heart/He = getorgan(/obj/item/organ/heart)
+ if(He)
+ holder.icon_state = "huddefib"
+ if(He.organ_flags & ORGAN_FAILING)
+ holder.icon_state = "huddefibheart"
+ else
+ holder.icon_state = "huddefibheart"
return
holder.icon_state = "huddead"
else
diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm
index 25edd0c68b..cd9500284b 100644
--- a/code/game/gamemodes/dynamic/dynamic.dm
+++ b/code/game/gamemodes/dynamic/dynamic.dm
@@ -510,7 +510,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
var/added_threat = starting_rule.scale_up(extra_rulesets_amount, threat)
if (starting_rule.pre_execute())
spend_threat(starting_rule.cost + added_threat)
- log_threat("[starting_rule.ruletype] - [starting_rule.name] -[starting_rule.cost + starting_rule.scaled_times * starting_rule.scaling_cost] threat")
+ log_threat("[starting_rule.ruletype] - [starting_rule.name] -[starting_rule.cost + starting_rule.scaled_times * starting_rule.scaling_cost] threat", verbose = TRUE)
if(starting_rule.flags & HIGHLANDER_RULESET)
highlander_executed = TRUE
else if(starting_rule.flags & ONLY_RULESET)
@@ -605,7 +605,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
new_rule.trim_candidates()
if (new_rule.ready(forced))
spend_threat(new_rule.cost)
- log_threat("[new_rule.ruletype] - [new_rule.name] -[new_rule.cost] threat")
+ log_threat("[new_rule.ruletype] - [new_rule.name] -[new_rule.cost] threat", verbose = TRUE)
if (new_rule.execute()) // This should never fail since ready() returned 1
if(new_rule.flags & HIGHLANDER_RULESET)
highlander_executed = TRUE
@@ -626,7 +626,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
if (rule.execute())
log_game("DYNAMIC: Injected a [rule.ruletype == "latejoin" ? "latejoin" : "midround"] ruleset [rule.name].")
spend_threat(rule.cost)
- log_threat("[rule.ruletype] [rule.name] spent [rule.cost]")
+ log_threat("[rule.ruletype] [rule.name] spent [rule.cost]", verbose = TRUE)
if(rule.flags & HIGHLANDER_RULESET)
highlander_executed = TRUE
else if(rule.flags & ONLY_RULESET)
@@ -815,16 +815,19 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
/// Refund threat, but no more than threat_level.
/datum/game_mode/dynamic/proc/refund_threat(regain)
threat = min(threat_level,threat+regain)
+ log_threat("[regain] refunded. Threat is now [threat].", verbose = TRUE)
/// Generate threat and increase the threat_level if it goes beyond, capped at 100
/datum/game_mode/dynamic/proc/create_threat(gain)
threat = min(100, threat+gain)
if(threat > threat_level)
threat_level = threat
+ log_threat("[gain] created. Threat is now [threat] and threat level is now [threat_level].", verbose = TRUE)
/// Expend threat, can't fall under 0.
/datum/game_mode/dynamic/proc/spend_threat(cost)
threat = max(threat-cost,0)
+ log_threat("[cost] spent. Threat is now [threat].", verbose = TRUE)
/// Turns the value generated by lorentz distribution to threat value between 0 and 100.
/datum/game_mode/dynamic/proc/lorentz_to_threat(x)
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index 281f28688e..3f3bacc64f 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -12,6 +12,7 @@
density = FALSE
state_open = TRUE
circuit = /obj/item/circuitboard/machine/sleeper
+ req_access = list(ACCESS_CMO) //Used for reagent deletion and addition of non medicines
var/efficiency = 1
var/min_health = -25
var/list/available_chems
@@ -28,9 +29,27 @@
/obj/machinery/sleeper/Initialize()
. = ..()
+ create_reagents(500, NO_REACT)
occupant_typecache = GLOB.typecache_living
update_icon()
reset_chem_buttons()
+ RefreshParts()
+ add_inital_chems()
+
+/obj/machinery/sleeper/on_deconstruction()
+ var/obj/item/reagent_containers/sleeper_buffer/buffer = new (loc)
+ buffer.volume = reagents.maximum_volume
+ buffer.reagents.maximum_volume = reagents.maximum_volume
+ reagents.trans_to(buffer.reagents, reagents.total_volume)
+
+/obj/machinery/sleeper/proc/add_inital_chems()
+ for(var/i in available_chems)
+ var/datum/reagent/R = reagents.has_reagent(i)
+ if(!R)
+ reagents.add_reagent(i, (20))
+ continue
+ if(R.volume < 20)
+ reagents.add_reagent(i, (20 - R.volume))
/obj/machinery/sleeper/RefreshParts()
var/E
@@ -47,6 +66,11 @@
available_chems |= possible_chems[i]
reset_chem_buttons()
+ //Total container size 500 - 2000u
+ if(reagents)
+ reagents.maximum_volume = (500*E)
+
+
/obj/machinery/sleeper/update_icon()
icon_state = initial(icon_state)
if(state_open)
@@ -81,7 +105,42 @@
if (. & EMP_PROTECT_SELF)
return
if(is_operational() && occupant)
+ var/datum/reagent/R = pick(reagents.reagent_list)
+ inject_chem(R.id, occupant)
open_machine()
+ //Is this too much?
+ if(severity == EMP_HEAVY)
+ var/chem = pick(available_chems)
+ available_chems -= chem
+ available_chems += get_random_reagent_id()
+ reset_chem_buttons()
+
+/obj/machinery/sleeper/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/reagent_containers/sleeper_buffer))
+ var/obj/item/reagent_containers/sleeper_buffer/SB = I
+ if((SB.reagents.total_volume + reagents.total_volume) < reagents.maximum_volume)
+ SB.reagents.trans_to(reagents, SB.reagents.total_volume)
+ visible_message("[user] places the [SB] into the [src].")
+ qdel(SB)
+ return
+ else
+ SB.reagents.trans_to(reagents, SB.reagents.total_volume)
+ visible_message("[user] adds as much as they can to the [src] from the [SB].")
+ return
+ if(istype(I, /obj/item/reagent_containers))
+ var/obj/item/reagent_containers/RC = I
+ if(RC.reagents.total_volume == 0)
+ to_chat(user, "The [I] is empty!")
+ for(var/datum/reagent/R in RC.reagents.reagent_list)
+ if((obj_flags & EMAGGED) || (allowed(usr)))
+ break
+ if(!istype(R, /datum/reagent/medicine))
+ visible_message("The [src] gives out a hearty boop and rejects the [I]. The Sleeper's screen flashes with a pompous \"Medicines only, please.\"")
+ return
+ RC.reagents.trans_to(reagents, 1000)
+ visible_message("[user] adds as much as they can to the [src] from the [I].")
+ return
+
/obj/machinery/sleeper/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
@@ -141,18 +200,24 @@
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
- ui = new(user, src, ui_key, "sleeper", name, 375, 550, master_ui, state)
+ ui = new(user, src, ui_key, "sleeper", name, 550, 700, master_ui, state)
ui.open()
/obj/machinery/sleeper/ui_data()
var/list/data = list()
data["occupied"] = occupant ? 1 : 0
data["open"] = state_open
+ data["efficiency"] = efficiency
+ data["current_vol"] = reagents.total_volume
+ data["tot_capacity"] = reagents.maximum_volume
data["chems"] = list()
for(var/chem in available_chems)
- var/datum/reagent/R = GLOB.chemical_reagents_list[chem]
- data["chems"] += list(list("name" = R.name, "id" = R.id, "allowed" = chem_allowed(chem)))
+ var/datum/reagent/R = reagents.has_reagent(chem)
+ R = GLOB.chemical_reagents_list[chem]
+ data["synthchems"] += list(list("name" = R.name, "id" = R.id, "synth_allowed" = synth_allowed(chem)))
+ for(var/datum/reagent/R in reagents.reagent_list)
+ data["chems"] += list(list("name" = R.name, "id" = R.id, "vol" = R.volume, "purity" = R.purity, "allowed" = chem_allowed(R.id)))
data["occupant"] = list()
var/mob/living/mob_occupant = occupant
@@ -184,8 +249,15 @@
if(mob_occupant.reagents && mob_occupant.reagents.reagent_list.len)
for(var/datum/reagent/R in mob_occupant.reagents.reagent_list)
data["occupant"]["reagents"] += list(list("name" = R.name, "volume" = R.volume))
+ data["occupant"]["failing_organs"] = list()
+ var/mob/living/carbon/C = mob_occupant
+ if(C)
+ for(var/obj/item/organ/Or in C.getFailingOrgans())
+ if(istype(Or, /obj/item/organ/brain))
+ continue
+ data["occupant"]["failing_organs"] += list(list("name" = Or.name))
+
if(mob_occupant.has_dna()) // Blood-stuff is mostly a copy-paste from the healthscanner.
- var/mob/living/carbon/C = mob_occupant
var/blood_id = C.get_blood_id()
if(blood_id)
data["occupant"]["blood"] = list() // We can start populating this list.
@@ -196,7 +268,7 @@
blood_type = R.name
else
blood_type = blood_id
- data["occupant"]["blood"]["maxBloodVolume"] = BLOOD_VOLUME_NORMAL
+ data["occupant"]["blood"]["maxBloodVolume"] = (BLOOD_VOLUME_NORMAL*C.blood_ratio)
data["occupant"]["blood"]["currentBloodVolume"] = C.blood_volume
data["occupant"]["blood"]["dangerBloodVolume"] = BLOOD_VOLUME_SAFE
data["occupant"]["blood"]["bloodType"] = blood_type
@@ -216,24 +288,49 @@
. = TRUE
if("inject")
var/chem = params["chem"]
+ var/amount = text2num(params["volume"])
if(!is_operational() || !mob_occupant)
return
if(mob_occupant.health < min_health && chem != "epinephrine")
return
- if(inject_chem(chem, usr))
+ if(inject_chem(chem, usr, amount))
. = TRUE
if(scrambled_chems && prob(5))
to_chat(usr, "Chemical system re-route detected, results may not be as expected!")
+ if("synth")
+ var/chem = params["chem"]
+ if(!is_operational())
+ return
+ reagents.add_reagent(chem_buttons[chem], 10) //other_purity = 0.75 for when the mechanics are in
+ if("purge")
+ var/chem = params["chem"]
+ if(allowed(usr))
+ if(!is_operational())
+ return
+ reagents.remove_reagent(chem, 10)
+ return
+ if(chem in available_chems)
+ if(!is_operational())
+ return
+ /*var/datum/reagent/R = reagents.has_reagent(chem) //For when purity effects are in
+ if(R.purity < 0.8)*/
+ reagents.remove_reagent(chem, 10)
+ else
+ visible_message("Access Denied.")
+ playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
+
/obj/machinery/sleeper/emag_act(mob/user)
. = ..()
+ obj_flags |= EMAGGED
scramble_chem_buttons()
to_chat(user, "You scramble the sleeper's user interface!")
return TRUE
-/obj/machinery/sleeper/proc/inject_chem(chem, mob/user)
- if((chem in available_chems) && chem_allowed(chem))
- occupant.reagents.add_reagent(chem_buttons[chem], 10) //emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU
+//trans to
+/obj/machinery/sleeper/proc/inject_chem(chem, mob/user, volume = 10)
+ if(chem_allowed(chem))
+ reagents.trans_id_to(occupant, chem, volume)//emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU
if(user)
log_combat(user, occupant, "injected [chem] into", addition = "via [src]")
return TRUE
@@ -246,6 +343,14 @@
var/occ_health = mob_occupant.health > min_health || chem == "epinephrine"
return amount && occ_health
+/obj/machinery/sleeper/proc/synth_allowed(chem)
+ var/datum/reagent/R = reagents.has_reagent(chem)
+ if(!R)
+ return TRUE
+ if(R.volume < 50)
+ return TRUE
+ return FALSE
+
/obj/machinery/sleeper/proc/reset_chem_buttons()
scrambled_chems = FALSE
LAZYINITLIST(chem_buttons)
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index b5cb066b3a..a8b4608b36 100755
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -42,12 +42,6 @@
. = ..()
GLOB.shuttle_caller_list += src
-/obj/machinery/computer/communications/process()
- if(..())
- var/ai_autoupdate = aistate != STATE_STATUSDISPLAY && aistate != STATE_CALLSHUTTLE && aistate != STATE_PURCHASE && aistate != STATE_VIEWMESSAGE
- var/machine_user_autoupdate = state != STATE_STATUSDISPLAY && state != STATE_CALLSHUTTLE && state != STATE_PURCHASE && state != STATE_VIEWMESSAGE
- updateDialog(machine_user_autoupdate,ai_autoupdate)
-
/obj/machinery/computer/communications/Topic(href, href_list)
if(..())
return
@@ -586,8 +580,6 @@
popup.set_content(dat)
popup.open()
- popup.set_content(dat)
- popup.open()
/obj/machinery/computer/communications/proc/get_javascript_header(form_id)
var/dat = {"