diff --git a/.github/alternate_byond_versions.txt b/.github/alternate_byond_versions.txt
index 7b50af46885e..fa7883a31aee 100644
--- a/.github/alternate_byond_versions.txt
+++ b/.github/alternate_byond_versions.txt
@@ -5,3 +5,4 @@
 # Format is version: map
 # Example:
 # 500.1337: runtimestation
+515.1626: runtimestation
diff --git a/.github/workflows/has_515_compatibility.yml b/.github/workflows/has_515_compatibility.yml
deleted file mode 100644
index a026105d7c20..000000000000
--- a/.github/workflows/has_515_compatibility.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-# This workflow was added in the 515 compatibility PR - https://github.com/tgstation/tgstation/pull/71161
-# By having this in your repository, we know that you have that PR merged as well.
-# This will be REMOVED when 515 is fully compatible and ready, but for now we need this
-# to prevent merge skew.
-# In the future, this will be a more proper system where commits can be added into a text file,
-# but that's a lot more difficult and I'm in a huge time crunch right now.
-name: "515 Compatibility Pass"
-on:
-  pull_request:
-    branches:
-    - master
-jobs:
-  has_515_compatibility:
-    name: Has 515 Compatibility
-    runs-on: ubuntu-20.04
-    steps:
-      - run: echo "You're ready to go!"
diff --git a/code/__DEFINES/_flags.dm b/code/__DEFINES/_flags.dm
index 012ded7eac16..e1eae54d9437 100644
--- a/code/__DEFINES/_flags.dm
+++ b/code/__DEFINES/_flags.dm
@@ -289,3 +289,5 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
 #define EMOTE_VISIBLE (1<<1)
 /// Is it an emote that should be shown regardless of blindness/deafness
 #define EMOTE_IMPORTANT (1<<2)
+/// Emote only prints to runechat, not to the chat window
+#define EMOTE_RUNECHAT (1<<3)
diff --git a/code/__DEFINES/alerts.dm b/code/__DEFINES/alerts.dm
index 1933b592d55c..e6f4feb259a5 100644
--- a/code/__DEFINES/alerts.dm
+++ b/code/__DEFINES/alerts.dm
@@ -47,11 +47,9 @@
 #define ALERT_HACKING_APC "hackingapc"
 
 /** MODsuit/Mech related */
-#define ALERT_MODSUIT_CHARGE "mod_charge"
 #define ALERT_MECH_DAMAGE "mech_damage"
 
 /** Food related */
-#define ALERT_NUTRITION "nutrition"
 #define ALERT_DISGUST "disgust"
 
 /** Environment related */
diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm
index a027dc61adbf..7d0fbe92ab2b 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm
@@ -12,10 +12,9 @@
 ///from base of atom/get_examine_name(): (/mob, list/overrides)
 #define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name"
 	//Positions for overrides list
-	#define EXAMINE_POSITION_ARTICLE (1<<0)
-	#define EXAMINE_POSITION_BEFORE (1<<1)
-	//End positions
-	#define COMPONENT_EXNAME_CHANGED (1<<0)
+	#define EXAMINE_POSITION_ARTICLE 1
+	#define EXAMINE_POSITION_BEFORE 2
+	#define EXAMINE_POSITION_NAME 3
 ///from base of atom/examine(): (/mob, list/examine_text, can_see_inside)
 #define COMSIG_ATOM_REAGENT_EXAMINE "atom_reagent_examine"
 	/// Stop the generic reagent examine text
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
index fff19f397741..a044fe75892a 100644
--- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
@@ -180,8 +180,6 @@
 #define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack"
 ///from base of obj/item/afterattack_secondary(): (atom/target, obj/item/weapon, proximity_flag, click_parameters)
 #define COMSIG_MOB_ITEM_AFTERATTACK_SECONDARY "mob_item_afterattack_secondary"
-///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, proximity_flag, click_parameters)
-#define COMSIG_MOB_ITEM_ATTACK_QDELETED "mob_item_attack_qdeleted"
 ///from base of mob/RangedAttack(): (atom/A, modifiers)
 #define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged"
 ///from base of mob/ranged_secondary_attack(): (atom/target, modifiers)
diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm
index 25efe87272f3..cd510b540a50 100644
--- a/code/__DEFINES/dcs/signals/signals_object.dm
+++ b/code/__DEFINES/dcs/signals/signals_object.dm
@@ -453,8 +453,6 @@
 	#define COMPONENT_AFTERATTACK_PROCESSED_ITEM (1<<0)
 ///from base of obj/item/afterattack_secondary(): (atom/target, mob/user, proximity_flag, click_parameters)
 #define COMSIG_ITEM_AFTERATTACK_SECONDARY "item_afterattack_secondary"
-///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, params)
-#define COMSIG_ITEM_ATTACK_QDELETED "item_attack_qdeleted"
 ///from base of obj/item/embedded(): (atom/target, obj/item/bodypart/part)
 #define COMSIG_ITEM_EMBEDDED "item_embedded"
 ///from base of datum/component/embedded/safeRemove(): (mob/living/carbon/victim)
diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm
index 5798fd29e82d..c3cd691afc8b 100644
--- a/code/__DEFINES/hud.dm
+++ b/code/__DEFINES/hud.dm
@@ -78,13 +78,6 @@
 #define ui_language_menu "EAST-4:6,SOUTH:21"
 #define ui_navigate_menu "EAST-4:22,SOUTH:5"
 
-//Upper-middle right (alerts)
-#define ui_alert1 "EAST-1:28,CENTER+5:27"
-#define ui_alert2 "EAST-1:28,CENTER+4:25"
-#define ui_alert3 "EAST-1:28,CENTER+3:23"
-#define ui_alert4 "EAST-1:28,CENTER+2:21"
-#define ui_alert5 "EAST-1:28,CENTER+1:19"
-
 //Upper left (action buttons)
 #define ui_action_palette "WEST+0:23,NORTH-1:5"
 #define ui_action_palette_offset(north_offset) ("WEST+0:23,NORTH-[1+north_offset]:5")
@@ -97,6 +90,7 @@
 #define ui_health "EAST-1:28,CENTER-1:19"
 #define ui_internal "EAST-1:28,CENTER+1:21"
 #define ui_mood "EAST-1:28,CENTER:21"
+#define ui_hunger "EAST-1:2,CENTER:21"
 #define ui_spacesuit "EAST-1:28,CENTER-4:14"
 #define ui_stamina "EAST-1:28,CENTER-3:14"
 
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 908a1202faf6..b01dd46677a1 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -281,6 +281,8 @@
 #define SANITY_LEVEL_UNSTABLE 4
 #define SANITY_LEVEL_CRAZY 5
 #define SANITY_LEVEL_INSANE 6
+/// Equal to the highest sanity level
+#define SANITY_LEVEL_MAX SANITY_LEVEL_INSANE
 
 //Nutrition levels for humans
 #define NUTRITION_LEVEL_FAT 600
@@ -491,9 +493,6 @@
 #define ROBOTIC_BRUTE_EXAMINE_TEXT "denting"
 #define ROBOTIC_BURN_EXAMINE_TEXT "charring"
 
-// If a mob has a higher threshold than this, the icon shown will be increased to the big fire icon.
-#define MOB_BIG_FIRE_STACK_THRESHOLD 3
-
 #define GRAB_PIXEL_SHIFT_PASSIVE 6
 #define GRAB_PIXEL_SHIFT_AGGRESSIVE 12
 #define GRAB_PIXEL_SHIFT_NECK 16
@@ -761,8 +760,8 @@ GLOBAL_LIST_INIT(human_heights_to_offsets, list(
 #define WOUND_LAYER 3
 /// Blood cult ascended halo layer, because there's currently no better solution for adding/removing
 #define HALO_LAYER 2
-/// Fire layer when you're on fire
-#define FIRE_LAYER 1
+/// The highest most layer for mob overlays. Unused
+#define HIGHEST_LAYER 1
 
 #define UPPER_BODY "upper body"
 #define LOWER_BODY "lower body"
@@ -803,7 +802,7 @@ GLOBAL_LIST_INIT(layers_to_offset, list(
 	// BODY_BEHIND_LAYER (external organs like wings)
 	// BODY_FRONT_LAYER (external organs like wings)
 	// DAMAGE_LAYER (full body)
-	// FIRE_LAYER (full body)
+	// HIGHEST_LAYER (full body)
 	// UNIFORM_LAYER (full body)
 	// WOUND_LAYER (full body)
 ))
diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm
index ba22075285c6..7955f3b5e1af 100644
--- a/code/__DEFINES/say.dm
+++ b/code/__DEFINES/say.dm
@@ -107,5 +107,10 @@
 
 
 
-//Used in visible_message_flags, audible_message_flags and runechat_flags
+// Used in visible_message_flags, audible_message_flags and runechat_flags
+/// Automatically applies emote related spans/fonts/formatting to the message
 #define EMOTE_MESSAGE (1<<0)
+/// By default, self_message will respect the visual / audible component of the message.
+/// Meaning that if the message is visual, and sourced from a blind mob, they will not see it.
+/// This flag skips that behavior, and will always show the self message to the mob.
+#define ALWAYS_SHOW_SELF_MESSAGE (1<<1)
diff --git a/code/__DEFINES/sprite_accessories.dm b/code/__DEFINES/sprite_accessories.dm
index 9c9471130e6f..a4003a31972c 100644
--- a/code/__DEFINES/sprite_accessories.dm
+++ b/code/__DEFINES/sprite_accessories.dm
@@ -7,3 +7,9 @@
 #define FACIAL_HAIR_COLOR "facial_hair_color"
 /// Color of the sprite accessory will match the owner's (left) eye color
 #define EYE_COLOR "eye_color"
+
+// ~color source defines for species hair overrides
+/// Uses the species's mutant color for the hair color
+#define USE_MUTANT_COLOR "use_mutant_color"
+/// Uses the species's fixed mutant color for the hair color
+#define USE_FIXED_MUTANT_COLOR "use_fixed_mutant_color"
diff --git a/code/__DEFINES/stat_tracking.dm b/code/__DEFINES/stat_tracking.dm
index d143e5df4c70..9bd697440406 100644
--- a/code/__DEFINES/stat_tracking.dm
+++ b/code/__DEFINES/stat_tracking.dm
@@ -54,7 +54,8 @@
 #define EXPORT_STATS_TO_FILE_LATER(filename, costs, counts, proc) \
 	do { \
 		var/static/last_export = 0; \
-		if (world.time - last_export > 1.1 SECONDS) { \
+		/* Need to always run if we haven't yet, since this code can be placed ANYWHERE */ \
+		if (world.time - last_export > 1.1 SECONDS || (last_export == 0)) { \
 			last_export = world.time; \
 			/* spawn() is used here because this is often used to track init times, where timers act oddly. */ \
 			/* I was making timers and even after init times were complete, the timers didn't run :shrug: */ \
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index 768f1faa514f..4e901c4ba2ce 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -31,6 +31,11 @@
 /// If the incapacitated status effect will ignore a mob being agressively grabbed
 #define IGNORE_GRAB (1<<2)
 
+/// Maxamounts of fire stacks a mob can get
+#define MAX_FIRE_STACKS 20
+/// If a mob has a higher threshold than this, the icon shown will be increased to the big fire icon.
+#define MOB_BIG_FIRE_STACK_THRESHOLD 3
+
 // Grouped effect sources, see also code/__DEFINES/traits.dm
 
 #define STASIS_MACHINE_EFFECT "stasis_machine"
diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index b3cd1921a643..1f63fa143486 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -353,8 +353,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
 #define TRAIT_TUMOR_SUPPRESSED "brain_tumor_suppressed"
 /// Prevents hallucinations from the hallucination brain trauma (RDS)
 #define TRAIT_RDS_SUPPRESSED "rds_suppressed"
-/// mobs that have this trait cannot be extinguished
-#define TRAIT_PERMANENTLY_ONFIRE "permanently_onfire"
+/// Mobs that have this trait cannot be extinguished
+#define TRAIT_NO_EXTINGUISH "no_extinguish"
 /// Indicates if the mob is currently speaking with sign language
 #define TRAIT_SIGN_LANG "sign_language"
 /// This mob is able to use sign language over the radio.
@@ -732,6 +732,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
 #define TRAIT_POSTERBOY "poster_boy"
 #define TRAIT_THROWINGARM "throwing_arm"
 #define TRAIT_SETTLER "settler"
+#define TRAIT_STRONG_STOMACH "strong_stomach"
 
 /// This mob always lands on their feet when they fall, for better or for worse.
 #define TRAIT_CATLIKE_GRACE "catlike_grace"
diff --git a/code/__HELPERS/type_processing.dm b/code/__HELPERS/type_processing.dm
index 117067a05782..7a9cd512d58b 100644
--- a/code/__HELPERS/type_processing.dm
+++ b/code/__HELPERS/type_processing.dm
@@ -1,14 +1,60 @@
 /proc/make_types_fancy(list/types)
 	if (ispath(types))
 		types = list(types)
-	. = list()
-	for(var/type in types)
-		var/typename = "[type]"
-		// Longest paths comes first
-		var/static/list/TYPES_SHORTCUTS = list(
-			/obj/effect/decal/cleanable = "CLEANABLE",
+	var/static/list/types_to_replacement
+	var/static/list/replacement_to_text
+	if(!types_to_replacement)
+		// Longer paths come after shorter ones, try and keep the structure
+		var/list/work_from = list(
+			/datum = "DATUM",
+			/area = "AREA",
+			/atom/movable = "MOVABLE",
+			/obj = "OBJ",
+			/turf = "TURF",
+			/turf/closed = "CLOSED",
+			/turf/open = "OPEN",
+
+			/mob = "MOB",
+			/mob/living = "LIVING",
+			/mob/living/carbon = "CARBON",
+			/mob/living/carbon/human = "HUMANOID",
+			/mob/living/simple_animal = "SIMPLE",
+			/mob/living/basic = "BASIC",
+			/mob/living/silicon = "SILICON",
+			/mob/living/silicon/robot = "CYBORG",
+
+			/obj/item = "ITEM",
+			/obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP",
+			/obj/item/mecha_parts/mecha_equipment/weapon = "MECHA_WEAPON",
+			/obj/item/organ = "ORGAN",
+			/obj/item/mod/control = "MODSUIT",
+			/obj/item/mod/module = "MODSUIT_MOD",
+			/obj/item/gun = "GUN",
+			/obj/item/gun/magic = "GUN_MAGIC",
+			/obj/item/gun/energy = "GUN_ENERGY",
+			/obj/item/gun/energy/laser = "GUN_LASER",
+			/obj/item/gun/ballistic = "GUN_BALLISTIC",
+			/obj/item/gun/ballistic/automatic = "GUN_AUTOMATIC",
+			/obj/item/gun/ballistic/revolver = "GUN_REVOLVER",
+			/obj/item/gun/ballistic/rifle = "GUN_RIFLE",
+			/obj/item/gun/ballistic/shotgun = "GUN_SHOTGUN",
+			/obj/item/stack/sheet = "SHEET",
+			/obj/item/stack/sheet/mineral = "MINERAL_SHEET",
+			/obj/item/stack/ore = "ORE",
+			/obj/item/ai_module = "AI_LAW_MODULE",
+			/obj/item/circuitboard = "CIRCUITBOARD",
+			/obj/item/circuitboard/machine = "MACHINE_BOARD",
+			/obj/item/circuitboard/computer = "COMPUTER_BOARD",
+			/obj/item/reagent_containers = "REAGENT_CONTAINERS",
+			/obj/item/reagent_containers/pill = "PILL",
+			/obj/item/reagent_containers/pill/patch = "MEDPATCH",
+			/obj/item/reagent_containers/hypospray/medipen = "MEDIPEN",
+			/obj/item/reagent_containers/cup/glass = "DRINK",
+			/obj/item/food = "FOOD",
 			/obj/item/bodypart = "BODYPART",
+			/obj/effect/decal/cleanable = "CLEANABLE",
 			/obj/item/radio/headset = "HEADSET",
+			/obj/item/clothing = "CLOTHING",
 			/obj/item/clothing/accessory = "ACCESSORY",
 			/obj/item/clothing/mask/gas = "GASMASK",
 			/obj/item/clothing/mask = "MASK",
@@ -21,75 +67,46 @@
 			/obj/item/clothing/head/helmet = "HELMET",
 			/obj/item/clothing/head = "HEAD",
 			/obj/item/clothing/neck = "NECK",
-			/obj/item/clothing = "CLOTHING",
 			/obj/item/storage/backpack = "BACKPACK",
 			/obj/item/storage/belt = "BELT",
-			/obj/item/book/manual = "MANUAL",
 			/obj/item/storage/pill_bottle = "PILL_BOTTLE",
-			/obj/item/reagent_containers/pill/patch = "MEDPATCH",
-			/obj/item/reagent_containers/pill = "PILL",
-			/obj/item/reagent_containers/hypospray/medipen = "MEDIPEN",
-			/obj/item/reagent_containers/cup/glass = "DRINK",
-			/obj/item/food = "FOOD",
-			/obj/item/reagent_containers = "REAGENT_CONTAINERS",
-			/obj/machinery/atmospherics = "ATMOS_MECH",
-			/obj/machinery/portable_atmospherics = "PORT_ATMOS",
-			/obj/item/mecha_parts/mecha_equipment/weapon = "MECHA_WEAPON",
-			/obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP",
-			/obj/item/organ = "ORGAN",
-			/obj/item/mod/control = "MODSUIT",
-			/obj/item/mod/module = "MODSUIT_MOD",
-			/obj/item/gun/ballistic/automatic = "GUN_AUTOMATIC",
-			/obj/item/gun/ballistic/revolver = "GUN_REVOLVER",
-			/obj/item/gun/ballistic/rifle = "GUN_RIFLE",
-			/obj/item/gun/ballistic/shotgun = "GUN_SHOTGUN",
-			/obj/item/gun/ballistic = "GUN_BALLISTIC",
-			/obj/item/gun/energy/laser = "GUN_LASER",
-			/obj/item/gun/energy = "GUN_ENERGY",
-			/obj/item/gun/magic = "GUN_MAGIC",
-			/obj/item/gun = "GUN",
-			/obj/item/stack/sheet/mineral = "MINERAL_SHEET",
-			/obj/item/stack/sheet = "SHEET",
-			/obj/item/stack/ore = "ORE",
-			/obj/item/ai_module = "AI_LAW_MODULE",
-			/obj/item/circuitboard/machine = "MACHINE_BOARD",
-			/obj/item/circuitboard/computer = "COMPUTER_BOARD",
-			/obj/item/circuitboard = "CIRCUITBOARD",
-			/obj/item = "ITEM",
-			/obj/structure/closet/crate/secure = "LOCKED_CRATE",
+			/obj/item/book/manual = "MANUAL",
+
+			/obj/structure = "STRUCTURE",
+			/obj/structure/closet = "CLOSET",
 			/obj/structure/closet/crate = "CRATE",
+			/obj/structure/closet/crate/secure = "LOCKED_CRATE",
 			/obj/structure/closet/secure_closet = "LOCKED_CLOSET",
-			/obj/structure/closet = "CLOSET",
-			/obj/structure = "STRUCTURE",
-			/obj/machinery/door/airlock = "AIRLOCK",
+
+			/obj/machinery = "MACHINERY",
+			/obj/machinery/atmospherics = "ATMOS_MECH",
+			/obj/machinery/portable_atmospherics = "PORT_ATMOS",
 			/obj/machinery/door = "DOOR",
+			/obj/machinery/door/airlock = "AIRLOCK",
 			/obj/machinery/rnd/production = "RND_FABRICATOR",
-			/obj/machinery/computer/camera_advanced/shuttle_docker = "DOCKING_COMPUTER",
 			/obj/machinery/computer = "COMPUTER",
-			/obj/machinery/vending/wardrobe = "JOBDROBE",
+			/obj/machinery/computer/camera_advanced/shuttle_docker = "DOCKING_COMPUTER",
 			/obj/machinery/vending = "VENDING",
-			/obj/machinery = "MACHINERY",
+			/obj/machinery/vending/wardrobe = "JOBDROBE",
 			/obj/effect = "EFFECT",
 			/obj/projectile = "PROJECTILE",
-			/obj = "O",
-			/datum = "D",
-			/turf/open = "OPEN",
-			/turf/closed = "CLOSED",
-			/turf = "T",
-			/mob/living/carbon/human = "HUMANOID",
-			/mob/living/carbon = "CARBON",
-			/mob/living/simple_animal = "SIMPLE",
-			/mob/living/basic = "BASIC",
-			/mob/living/silicon/robot = "CYBORG",
-			/mob/living/silicon = "SILICON",
-			/mob/living = "LIVING",
-			/mob = "M",
 		)
-		for (var/tn in TYPES_SHORTCUTS)
-			if(copytext(typename, 1, length("[tn]/") + 1) == "[tn]/" /*findtextEx(typename,"[tn]/",1,2)*/ )
-				typename = TYPES_SHORTCUTS[tn] + copytext(typename, length("[tn]/"))
-				break
-		.[typename] = type
+		// ignore_root_path so we can draw the root normally
+		types_to_replacement = zebra_typecacheof(work_from, ignore_root_path = TRUE)
+		replacement_to_text = list()
+		for(var/key in work_from)
+			replacement_to_text[work_from[key]] = "[key]"
+
+
+	. = list()
+	for(var/type in types)
+		var/replace_with = types_to_replacement[type]
+		if(!replace_with)
+			.["[type]"] = type
+			continue
+		var/cut_out = replacement_to_text[replace_with]
+		// + 1 to account for /
+		.[replace_with + copytext("[type]", length(cut_out) + 1)] = type
 
 /proc/get_fancy_list_of_atom_types()
 	var/static/list/pre_generated_list
diff --git a/code/__byond_version_compat.dm b/code/__byond_version_compat.dm
index f3677cf2c644..2d6ad4533334 100644
--- a/code/__byond_version_compat.dm
+++ b/code/__byond_version_compat.dm
@@ -2,11 +2,11 @@
 
 //Update this whenever you need to take advantage of more recent byond features
 #define MIN_COMPILER_VERSION 515
-#define MIN_COMPILER_BUILD 1609
+#define MIN_COMPILER_BUILD 1626
 #if (DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD) && !defined(SPACEMAN_DMM)
 //Don't forget to update this part
 #error Your version of BYOND is too out-of-date to compile this project. Go to https://secure.byond.com/download and update.
-#error You need version 515.1609 or higher
+#error You need version 515.1626 or higher
 #endif
 
 // Keep savefile compatibilty at minimum supported level
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index f33afc11f4b3..653470493e44 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -316,6 +316,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
 		"TRAIT_NO_DEBRAIN_OVERLAY" = TRAIT_NO_DEBRAIN_OVERLAY,
 		"TRAIT_NO_DNA_COPY" = TRAIT_NO_DNA_COPY,
 		"TRAIT_NO_DNA_SCRAMBLE" = TRAIT_NO_DNA_SCRAMBLE,
+		"TRAIT_NO_EXTINGUISH" = TRAIT_NO_EXTINGUISH,
 		"TRAIT_NO_FLOATING_ANIM" = TRAIT_NO_FLOATING_ANIM,
 		"TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE,
 		"TRAIT_NO_GUN_AKIMBO" = TRAIT_NO_GUN_AKIMBO,
@@ -351,7 +352,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
 		"TRAIT_PASSTABLE" = TRAIT_PASSTABLE,
 		"TRAIT_PERFECT_ATTACKER" = TRAIT_PERFECT_ATTACKER,
 		"TRAIT_PERMANENTLY_MORTAL" = TRAIT_PERMANENTLY_MORTAL,
-		"TRAIT_PERMANENTLY_ONFIRE" = TRAIT_PERMANENTLY_ONFIRE,
 		"TRAIT_PHOTOGRAPHER" = TRAIT_PHOTOGRAPHER,
 		"TRAIT_PIERCEIMMUNE" = TRAIT_PIERCEIMMUNE,
 		"TRAIT_PLANT_SAFE" = TRAIT_PLANT_SAFE,
@@ -417,6 +417,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
 		"TRAIT_STABLELIVER" = TRAIT_STABLELIVER,
 		"TRAIT_STASIS" = TRAIT_STASIS,
 		"TRAIT_STRONG_GRABBER" = TRAIT_STRONG_GRABBER,
+		"TRAIT_STRONG_STOMACH" = TRAIT_STRONG_STOMACH,
 		"TRAIT_STUNIMMUNE" = TRAIT_STUNIMMUNE,
 		"TRAIT_SUCCUMB_OVERRIDE" = TRAIT_SUCCUMB_OVERRIDE,
 		"TRAIT_SUICIDED" = TRAIT_SUICIDED,
diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm
index 8424f1e48303..30b708789dd0 100644
--- a/code/_globalvars/traits/admin_tooling.dm
+++ b/code/_globalvars/traits/admin_tooling.dm
@@ -128,6 +128,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
 		"TRAIT_NO_AUGMENTS" = TRAIT_NO_AUGMENTS,
 		"TRAIT_NO_BLOOD_OVERLAY" = TRAIT_NO_BLOOD_OVERLAY,
 		"TRAIT_NO_DNA_COPY" = TRAIT_NO_DNA_COPY,
+		"TRAIT_NO_EXTINGUISH" = TRAIT_NO_EXTINGUISH,
 		"TRAIT_NO_GLIDE" = TRAIT_NO_GLIDE,
 		"TRAIT_NO_PLASMA_TRANSFORM" = TRAIT_NO_PLASMA_TRANSFORM,
 		"TRAIT_NO_SLIP_ALL" = TRAIT_NO_SLIP_ALL,
@@ -161,7 +162,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
 		"TRAIT_PARALYSIS_R_LEG" = TRAIT_PARALYSIS_R_LEG,
 		"TRAIT_PASSTABLE" = TRAIT_PASSTABLE,
 		"TRAIT_PERFECT_ATTACKER" = TRAIT_PERFECT_ATTACKER,
-		"TRAIT_PERMANENTLY_ONFIRE" = TRAIT_PERMANENTLY_ONFIRE,
 		"TRAIT_PHOTOGRAPHER" = TRAIT_PHOTOGRAPHER,
 		"TRAIT_PIERCEIMMUNE" = TRAIT_PIERCEIMMUNE,
 		"TRAIT_PLANT_SAFE" = TRAIT_PLANT_SAFE,
@@ -200,6 +200,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
 		"TRAIT_STABLEHEART" = TRAIT_STABLEHEART,
 		"TRAIT_STABLELIVER" = TRAIT_STABLELIVER,
 		"TRAIT_STRONG_GRABBER" = TRAIT_STRONG_GRABBER,
+		"TRAIT_STRONG_STOMACH" = TRAIT_STRONG_STOMACH,
 		"TRAIT_STUNIMMUNE" = TRAIT_STUNIMMUNE,
 		"TRAIT_SURGEON" = TRAIT_SURGEON,
 		"TRAIT_SURGICALLY_ANALYZED" = TRAIT_SURGICALLY_ANALYZED,
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index e73cebf14c0c..2f2c767c012c 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -68,8 +68,8 @@
 	if(client && hud_used)
 		hud_used.reorganize_alerts()
 	if(!no_anim)
-		thealert.transform = matrix(32, 6, MATRIX_TRANSLATE)
-		animate(thealert, transform = matrix(), time = 2.5, easing = CUBIC_EASING)
+		thealert.transform = matrix(32, 0, MATRIX_TRANSLATE)
+		animate(thealert, transform = matrix(), time = 1 SECONDS, easing = ELASTIC_EASING)
 	if(timeout_override)
 		thealert.timeout = timeout_override
 	if(thealert.timeout)
@@ -185,22 +185,6 @@
 
 //End gas alerts
 
-
-/atom/movable/screen/alert/fat
-	name = "Fat"
-	desc = "You ate too much food, lardass. Run around the station and lose some weight."
-	icon_state = "fat"
-
-/atom/movable/screen/alert/hungry
-	name = "Hungry"
-	desc = "Some food would be good right about now."
-	icon_state = "hungry"
-
-/atom/movable/screen/alert/starving
-	name = "Starving"
-	desc = "You're severely malnourished. The hunger pains make moving around a chore."
-	icon_state = "starving"
-
 /atom/movable/screen/alert/gross
 	name = "Grossed out."
 	desc = "That was kind of gross..."
@@ -317,12 +301,25 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
 	/// The offer we're linked to, yes this is suspiciously like a status effect alert
 	var/datum/status_effect/offering/offer
 	/// Additional text displayed in the description of the alert.
-	var/additional_desc_text = "Click this alert to take it."
+	var/additional_desc_text = "Click this alert to take it, or shift click it to examiante it."
+	/// Text to override what appears in screentips for the alert
+	var/screentip_override_text
+	/// Whether the offered item can be examined by shift-clicking the alert
+	var/examinable = TRUE
+
+/atom/movable/screen/alert/give/Initialize(mapload, datum/hud/hud_owner)
+	. = ..()
+	register_context()
 
 /atom/movable/screen/alert/give/Destroy()
 	offer = null
 	return ..()
 
+/atom/movable/screen/alert/give/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+	context[SCREENTIP_CONTEXT_LMB] = screentip_override_text || "Take [offer.offered_item.name]"
+	context[SCREENTIP_CONTEXT_SHIFT_LMB] = "Examine"
+	return CONTEXTUAL_SCREENTIP_SET
+
 /**
  * Handles assigning most of the variables for the alert that pops up when an item is offered
  *
@@ -373,6 +370,16 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
 
 	handle_transfer()
 
+/atom/movable/screen/alert/give/examine(mob/user)
+	if(!examinable)
+		return ..()
+
+	return list(
+		span_boldnotice(name),
+		span_info("[offer.owner] is offering you the following item (click the alert to take it!):"),
+		"<hr>[jointext(offer.offered_item.examine(user), "\n")]",
+	)
+
 /// An overrideable proc used simply to hand over the item when claimed, this is a proc so that high-fives can override them since nothing is actually transferred
 /atom/movable/screen/alert/give/proc/handle_transfer()
 	var/mob/living/carbon/taker = owner
@@ -383,6 +390,8 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
 
 /atom/movable/screen/alert/give/highfive
 	additional_desc_text = "Click this alert to slap it."
+	screentip_override_text = "High Five"
+	examinable = FALSE
 	/// Tracks active "to slow"ing so we can't spam click
 	var/too_slowing_this_guy = FALSE
 
@@ -441,6 +450,10 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
 	if(QDELETED(offer.offered_item))
 		examine_list += span_warning("[source]'s arm appears tensed up, as if [source.p_they()] plan on pulling it back suddenly...")
 
+/atom/movable/screen/alert/give/hand
+	screentip_override_text = "Take Hand"
+	examinable = FALSE
+
 /atom/movable/screen/alert/give/hand/get_receiving_name(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving)
 	additional_desc_text = "Click this alert to take it and let [offerer.p_them()] pull you around!"
 	return "[offerer.p_their()] [receiving.name]"
@@ -1034,39 +1047,35 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
 
 // PRIVATE = only edit, use, or override these if you're editing the system as a whole
 
+/// Gets the placement for the alert based on its index
+/datum/hud/proc/get_ui_alert_placement(index)
+	PRIVATE_PROC(TRUE)
+	// Only has support for 5 slots currently
+	if(index > 5)
+		return ""
+
+	return "EAST-1:28,CENTER+[6 - index]:[29 - (index * 2)]"
+
 // Re-render all alerts - also called in /datum/hud/show_hud() because it's needed there
 /datum/hud/proc/reorganize_alerts(mob/viewmob)
 	var/mob/screenmob = viewmob || mymob
 	if(!screenmob.client)
-		return
+		return FALSE
 	var/list/alerts = mymob.alerts
 	if(!hud_shown)
-		for(var/i in 1 to alerts.len)
+		for(var/i in 1 to length(alerts))
 			screenmob.client.screen -= alerts[alerts[i]]
-		return 1
-	for(var/i in 1 to alerts.len)
+		return TRUE
+	for(var/i in 1 to length(alerts))
 		var/atom/movable/screen/alert/alert = alerts[alerts[i]]
 		if(alert.icon_state == "template")
 			alert.icon = ui_style
-		switch(i)
-			if(1)
-				. = ui_alert1
-			if(2)
-				. = ui_alert2
-			if(3)
-				. = ui_alert3
-			if(4)
-				. = ui_alert4
-			if(5)
-				. = ui_alert5 // Right now there's 5 slots
-			else
-				. = ""
-		alert.screen_loc = .
+		alert.screen_loc = get_ui_alert_placement(i)
 		screenmob.client.screen |= alert
 	if(!viewmob)
-		for(var/M in mymob.observers)
-			reorganize_alerts(M)
-	return 1
+		for(var/viewer in mymob.observers)
+			reorganize_alerts(viewer)
+	return TRUE
 
 /atom/movable/screen/alert/Click(location, control, params)
 	if(!usr || !usr.client)
@@ -1075,7 +1084,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
 		return FALSE
 	var/list/modifiers = params2list(params)
 	if(LAZYACCESS(modifiers, SHIFT_CLICK)) // screen objects don't do the normal Click() stuff so we'll cheat
-		to_chat(usr, span_boldnotice("[name]</span> - <span class='info'>[desc]"))
+		to_chat(usr, examine_block(jointext(examine(usr), "\n")))
 		return FALSE
 	var/datum/our_master = master_ref?.resolve()
 	if(our_master && click_master)
@@ -1089,3 +1098,9 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
 	master_ref = null
 	owner = null
 	screen_loc = ""
+
+/atom/movable/screen/alert/examine(mob/user)
+	return list(
+		span_boldnotice(name),
+		span_info(desc),
+	)
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index b915e3dc19c8..0b907833f76c 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -95,6 +95,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
 	var/atom/movable/screen/stamina
 	var/atom/movable/screen/healthdoll
 	var/atom/movable/screen/spacesuit
+	var/atom/movable/screen/hunger
 	// subtypes can override this to force a specific UI style
 	var/ui_style
 
@@ -239,6 +240,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
 	stamina = null
 	healthdoll = null
 	spacesuit = null
+	hunger = null
 	blobpwrdisplay = null
 	alien_plasma_display = null
 	alien_queen_finder = null
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 1ab08695cc75..58846dad6af6 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -268,6 +268,9 @@
 	healths = new /atom/movable/screen/healths(null, src)
 	infodisplay += healths
 
+	hunger = new /atom/movable/screen/hunger(null, src)
+	infodisplay += hunger
+
 	healthdoll = new /atom/movable/screen/healthdoll(null, src)
 	infodisplay += healthdoll
 
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 79a4c93a3ddb..ab6ad083027f 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -724,3 +724,102 @@ INITIALIZE_IMMEDIATE(/atom/movable/screen/splash)
 	name = "stamina"
 	icon_state = "stamina0"
 	screen_loc = ui_stamina
+
+#define HUNGER_STATE_FAT 2
+#define HUNGER_STATE_FULL 1
+#define HUNGER_STATE_FINE 0
+#define HUNGER_STATE_HUNGRY -1
+#define HUNGER_STATE_STARVING -2
+
+/atom/movable/screen/hunger
+	name = "hunger"
+	icon_state = "hungerbar"
+	base_icon_state = "hungerbar"
+	screen_loc = ui_hunger
+	mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+	/// What state of hunger are we in?
+	VAR_PRIVATE/state = HUNGER_STATE_FINE
+	/// What food icon do we show by the bar
+	var/food_icon = 'icons/obj/food/burgerbread.dmi'
+	/// What food icon state do we show by the bar
+	var/food_icon_state = "hburger"
+	/// The image shown by the bar.
+	VAR_PRIVATE/image/food_image
+
+/atom/movable/screen/hunger/Initialize(mapload, datum/hud/hud_owner)
+	. = ..()
+	var/mob/living/hungry = hud_owner?.mymob
+	if(!istype(hungry))
+		return
+
+	if(!ishuman(hungry) || CONFIG_GET(flag/disable_human_mood))
+		screen_loc = ui_mood // Slot in where mood normally is if mood is disabled
+
+	food_image = image(icon = food_icon, icon_state = food_icon_state, pixel_x = -5)
+	food_image.plane = plane
+	food_image.appearance_flags |= KEEP_APART // To be unaffected by filters applied to src
+	food_image.add_filter("simple_outline", 2, outline_filter(1, COLOR_BLACK))
+	underlays += food_image // To be below filters applied to src
+
+	SetInvisibility(INVISIBILITY_ABSTRACT, name) // Start invisible, update later
+	update_appearance()
+
+/atom/movable/screen/hunger/proc/update_hunger_state()
+	var/mob/living/hungry = hud?.mymob
+	if(!istype(hungry))
+		return
+
+	if(HAS_TRAIT(hungry, TRAIT_NOHUNGER) || !hungry.get_organ_slot(ORGAN_SLOT_STOMACH))
+		state = HUNGER_STATE_FINE
+		return
+
+	if(HAS_TRAIT(hungry, TRAIT_FAT))
+		state = HUNGER_STATE_FAT
+		return
+
+	switch(hungry.nutrition)
+		if(NUTRITION_LEVEL_FULL to INFINITY)
+			state = HUNGER_STATE_FULL
+		if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FULL)
+			state = HUNGER_STATE_FINE
+		if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
+			state = HUNGER_STATE_HUNGRY
+		if(0 to NUTRITION_LEVEL_STARVING)
+			state = HUNGER_STATE_STARVING
+
+/atom/movable/screen/hunger/update_appearance(updates)
+	var/old_state = state
+	update_hunger_state() // Do this before we call all the other update procs
+	. = ..()
+	if(state == old_state) // Let's not be wasteful
+		return
+	if(state == HUNGER_STATE_FINE)
+		SetInvisibility(INVISIBILITY_ABSTRACT, name)
+		return
+
+	else if(invisibility)
+		RemoveInvisibility(name)
+
+	if(state == HUNGER_STATE_STARVING)
+		if(!get_filter("hunger_outline"))
+			add_filter("hunger_outline", 1, list("type" = "outline", "color" = "#FF0033", "alpha" = 0, "size" = 2))
+			animate(get_filter("hunger_outline"), alpha = 200, time = 1.5 SECONDS, loop = -1)
+			animate(alpha = 0, time = 1.5 SECONDS)
+
+	else if(get_filter("hunger_outline"))
+		remove_filter("hunger_outline")
+
+	// Update color of the food
+	underlays -= food_image
+	food_image.color = state == HUNGER_STATE_FAT ? COLOR_DARK : null
+	underlays += food_image
+
+/atom/movable/screen/hunger/update_icon_state()
+	. = ..()
+	icon_state = "[base_icon_state][state]"
+
+#undef HUNGER_STATE_FAT
+#undef HUNGER_STATE_FULL
+#undef HUNGER_STATE_FINE
+#undef HUNGER_STATE_HUNGRY
+#undef HUNGER_STATE_STARVING
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index c1f3850c331f..f17ce8ef9132 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -52,10 +52,6 @@
 	if (attackby_result)
 		return TRUE
 
-	if(QDELETED(src) || QDELETED(target))
-		attack_qdeleted(target, user, TRUE, params)
-		return TRUE
-
 	if (is_right_clicking)
 		var/after_attack_secondary_result = afterattack_secondary(target, user, TRUE, params)
 
@@ -390,7 +386,7 @@
 					glasses.add_mob_blood(src)
 					update_worn_glasses()
 
-			if(!attacking_item.get_sharpness() && armor_block < 50)
+			if(!attacking_item.get_sharpness() && armor_block < 50 && attacking_item.damtype == BRUTE)
 				if(prob(damage_done))
 					adjustOrganLoss(ORGAN_SLOT_BRAIN, 20)
 					if(stat == CONSCIOUS)
@@ -420,7 +416,7 @@
 					w_uniform.add_mob_blood(src)
 					update_worn_undersuit()
 
-			if(stat == CONSCIOUS && !attacking_item.get_sharpness() && armor_block < 50)
+			if(stat == CONSCIOUS && !attacking_item.get_sharpness() && armor_block < 50 && attacking_item.damtype == BRUTE)
 				if(prob(damage_done))
 					visible_message(
 						span_danger("[src] is knocked down!"),
@@ -471,11 +467,6 @@
 
 	return SECONDARY_ATTACK_CALL_NORMAL
 
-/// Called if the target gets deleted by our attack
-/obj/item/proc/attack_qdeleted(atom/target, mob/user, proximity_flag, click_parameters)
-	SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_QDELETED, target, user, proximity_flag, click_parameters)
-	SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK_QDELETED, target, user, proximity_flag, click_parameters)
-
 /obj/item/proc/get_clamped_volume()
 	if(w_class)
 		if(force)
diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm
index a3520ab1ee37..1083f941d3ba 100644
--- a/code/controllers/globals.dm
+++ b/code/controllers/globals.dm
@@ -15,13 +15,12 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
 
 	var/datum/controller/exclude_these = new
 	// I know this is dumb but the nested vars list hangs a ref to the datum. This fixes that
+	// I have an issue report open, lummox has not responded. It might be a FeaTuRE
+	// Sooo we gotta be dumb
 	var/list/controller_vars = exclude_these.vars.Copy()
 	controller_vars["vars"] = null
 	gvars_datum_in_built_vars = controller_vars + list(NAMEOF(src, gvars_datum_protected_varlist), NAMEOF(src, gvars_datum_in_built_vars), NAMEOF(src, gvars_datum_init_order))
 
-#if MIN_COMPILER_VERSION >= 515 && MIN_COMPILER_BUILD > 1620
-	#warn datum.vars hanging a ref should now be fixed, there should be no reason to remove the vars list from our controller's vars list anymore
-#endif
 	QDEL_IN(exclude_these, 0) //signal logging isn't ready
 
 	Initialize()
@@ -68,4 +67,3 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars)
 
 	// Someone make it so this call isn't necessary
 	make_datum_reference_lists()
-
diff --git a/code/datums/ai/hunting_behavior/hunting_mouse.dm b/code/datums/ai/hunting_behavior/hunting_mouse.dm
index d4160f826dd6..8767274f9136 100644
--- a/code/datums/ai/hunting_behavior/hunting_mouse.dm
+++ b/code/datums/ai/hunting_behavior/hunting_mouse.dm
@@ -11,7 +11,7 @@
 	finding_behavior = /datum/ai_behavior/find_hunt_target/mouse_cable
 	hunt_targets = list(/obj/structure/cable)
 	hunt_range = 0 // Only look below us
-	hunt_chance = 5
+	hunt_chance = 0.5
 
 // When looking for a cable, we can only bite things we can reach.
 /datum/ai_behavior/find_hunt_target/mouse_cable
diff --git a/code/datums/components/infective.dm b/code/datums/components/infective.dm
index 006fc84b6c98..50574e8fdb63 100644
--- a/code/datums/components/infective.dm
+++ b/code/datums/components/infective.dm
@@ -64,9 +64,10 @@
 	if(is_type_in_typecache(parent, liver?.disease_free_foods))
 		return
 	// NON-MODULE CHANGE END
+	if(HAS_TRAIT(eater, TRAIT_STRONG_STOMACH))
+		return
 
-	if(!eater.has_quirk(/datum/quirk/deviant_tastes))
-		eater.add_mood_event("disgust", /datum/mood_event/disgust/dirty_food)
+	eater.add_mood_event("disgust", /datum/mood_event/disgust/dirty_food)
 
 	if(is_weak && !prob(weak_infection_chance))
 		return
@@ -82,6 +83,9 @@
 /datum/component/infective/proc/try_infect_drink(datum/source, mob/living/drinker, mob/living/feeder)
 	SIGNAL_HANDLER
 
+	if(HAS_TRAIT(drinker, TRAIT_STRONG_STOMACH))
+		return
+
 	var/appendage_zone = feeder.held_items.Find(source)
 	appendage_zone = appendage_zone == 0 ? BODY_ZONE_CHEST : appendage_zone % 2 ? BODY_ZONE_R_ARM : BODY_ZONE_L_ARM
 	try_infect(feeder, appendage_zone)
diff --git a/code/datums/components/puzzgrid.dm b/code/datums/components/puzzgrid.dm
index 611df16ccaa3..e6eb0db83d90 100644
--- a/code/datums/components/puzzgrid.dm
+++ b/code/datums/components/puzzgrid.dm
@@ -172,7 +172,7 @@
 
 	var/message = answers.Join("<p>-----</p>")
 
-	for (var/mob/mob as anything in get_hearers_in_view(DEFAULT_MESSAGE_RANGE, src))
+	for (var/mob/mob as anything in get_hearers_in_view(DEFAULT_MESSAGE_RANGE, parent))
 		to_chat(mob, message)
 
 /datum/component/puzzgrid/ui_data(mob/user)
diff --git a/code/datums/diseases/tuberculosis.dm b/code/datums/diseases/tuberculosis.dm
index de87cab6f3f6..4bb005917b47 100644
--- a/code/datums/diseases/tuberculosis.dm
+++ b/code/datums/diseases/tuberculosis.dm
@@ -18,6 +18,10 @@
 	if(!.)
 		return
 
+	if(SPT_PROB(stage * 2, seconds_per_tick))
+		affected_mob.emote("cough")
+		to_chat(affected_mob, span_danger("Your chest hurts."))
+
 	switch(stage)
 		if(2)
 			if(SPT_PROB(1, seconds_per_tick))
diff --git a/code/datums/elements/decals/blood.dm b/code/datums/elements/decals/blood.dm
index 3a3aa4b35300..ac640a01c48e 100644
--- a/code/datums/elements/decals/blood.dm
+++ b/code/datums/elements/decals/blood.dm
@@ -42,10 +42,13 @@
 	pic.color = source.get_blood_dna_color() || COLOR_BLOOD // NON-MODULE CHANGE
 	return ..()
 
-/datum/element/decal/blood/proc/get_examine_name(datum/source, mob/user, list/override)
+/datum/element/decal/blood/proc/get_examine_name(atom/source, mob/user, list/override)
 	SIGNAL_HANDLER
 
-	var/atom/A = source
-	override[EXAMINE_POSITION_ARTICLE] = A.gender == PLURAL? "some" : "a"
-	override[EXAMINE_POSITION_BEFORE] = " blood-stained "
-	return COMPONENT_EXNAME_CHANGED
+	var/list/all_dna = GET_ATOM_BLOOD_DNA(source)
+	var/list/all_blood_names = list()
+	for(var/dna_sample in all_dna)
+		var/datum/blood_type/blood = GLOB.blood_types[all_dna[dna_sample]]
+		all_blood_names |= lowertext(initial(blood.reagent_type.name))
+
+	override[EXAMINE_POSITION_BEFORE] = "[english_list(all_blood_names, nothing_text = "blood")] stained"
diff --git a/code/datums/elements/permanent_fire_overlay.dm b/code/datums/elements/permanent_fire_overlay.dm
new file mode 100644
index 000000000000..514d0f121a45
--- /dev/null
+++ b/code/datums/elements/permanent_fire_overlay.dm
@@ -0,0 +1,24 @@
+/// When applied to a mob, they will always have a fire overlay regardless of if they are *actually* on fire.
+/datum/element/perma_fire_overlay
+
+/datum/element/perma_fire_overlay/Attach(atom/target)
+	. = ..()
+	if(!isliving(target))
+		return ELEMENT_INCOMPATIBLE
+
+	RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(add_fire_overlay))
+	target.update_appearance(UPDATE_OVERLAYS)
+
+/datum/element/perma_fire_overlay/Detach(atom/target)
+	. = ..()
+	UnregisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS)
+	target.update_appearance(UPDATE_OVERLAYS)
+
+/datum/element/perma_fire_overlay/proc/add_fire_overlay(mob/living/source, list/overlays)
+	SIGNAL_HANDLER
+
+	var/mutable_appearance/created_overlay = source.get_fire_overlay(stacks = MAX_FIRE_STACKS, on_fire = TRUE)
+	if(isnull(created_overlay))
+		return
+
+	overlays |= created_overlay
diff --git a/code/datums/elements/skill_reward.dm b/code/datums/elements/skill_reward.dm
index 0c0e04754f74..7809eea85f71 100644
--- a/code/datums/elements/skill_reward.dm
+++ b/code/datums/elements/skill_reward.dm
@@ -24,14 +24,15 @@
 	if(!LAZYACCESS(modifiers, CTRL_CLICK) && !check_equippable(user)) //Allows other players to drag it around at least.
 		to_chat(user, span_warning("You feel completely and utterly unworthy to even touch \the [source]."))
 		return COMPONENT_CANCEL_ATTACK_CHAIN
+	return NONE
 
 ///We check if the item can be equipped, otherwise we drop it.
 /datum/element/skill_reward/proc/drop_if_unworthy(datum/source, mob/living/user)
 	SIGNAL_HANDLER
-	if(check_equippable(user) | !(source in user.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE)))
-		return
+	if(check_equippable(user) || !(source in user.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE)))
+		return NONE
 	to_chat(user, span_warning("You feel completely and utterly unworthy to even touch \the [source]."))
-	user.dropItemToGround(src, TRUE)
+	user.dropItemToGround(source, TRUE)
 	return COMPONENT_EQUIPPED_FAILED
 
 /datum/element/skill_reward/proc/check_equippable(mob/living/user)
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index 3c0e2a903c23..a10b838d02bc 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -88,11 +88,10 @@
  * Returns TRUE if it was able to run the emote, FALSE otherwise.
  */
 /datum/emote/proc/run_emote(mob/user, params, type_override, intentional = FALSE)
-	. = TRUE
 	if(!can_run_emote(user, TRUE, intentional))
 		return FALSE
 	if(SEND_SIGNAL(user, COMSIG_MOB_PRE_EMOTED, key, params, type_override, intentional) & COMPONENT_CANT_EMOTE)
-		return // We don't return FALSE because the error output would be incorrect, provide your own if necessary.
+		return TRUE // We don't return FALSE because the error output would be incorrect, provide your own if necessary.
 	var/msg = select_message_type(user, message, intentional)
 	if(params && message_param)
 		msg = select_param(user, params)
@@ -100,31 +99,94 @@
 	msg = replace_pronoun(user, msg)
 
 	if(!msg)
-		return
+		return TRUE
 
 	user.log_message(msg, LOG_EMOTE)
-	var/dchatmsg = "<b>[user]</b> [msg]"
 
 	var/tmp_sound = get_sound(user)
 	if(tmp_sound && should_play_sound(user, intentional) && TIMER_COOLDOWN_FINISHED(user, type))
 		TIMER_COOLDOWN_START(user, type, audio_cooldown)
 		playsound(user, tmp_sound, 50, vary)
 
-	var/user_turf = get_turf(user)
-	if (user.client)
-		for(var/mob/ghost as anything in GLOB.dead_mob_list)
-			if(!ghost.client || isnewplayer(ghost))
+	var/is_important = emote_type & EMOTE_IMPORTANT
+	var/is_visual = emote_type & EMOTE_VISIBLE
+	var/is_audible = emote_type & EMOTE_AUDIBLE
+
+	// Emote doesn't get printed to chat, runechat only
+	if(emote_type & EMOTE_RUNECHAT)
+		for(var/mob/viewer as anything in viewers(user))
+			if(isnull(viewer.client))
+				continue
+			if(!is_important && viewer != user && (!is_visual || !is_audible))
+				if(is_audible && !viewer.can_hear())
+					continue
+				if(is_visual && viewer.is_blind())
+					continue
+			if(user.runechat_prefs_check(viewer, EMOTE_MESSAGE))
+				viewer.create_chat_message(
+					speaker = user,
+					raw_message = msg,
+					runechat_flags = EMOTE_MESSAGE,
+				)
+			else if(is_important)
+				to_chat(viewer, "<span class='emote'><b>[user]</b> [msg]</span>")
+			else if(is_audible && is_visual)
+				viewer.show_message(
+					"<span class='emote'><b>[user]</b> [msg]</span>", MSG_AUDIBLE,
+					"<span class='emote'>You see how <b>[user]</b> [msg]</span>", MSG_VISUAL,
+				)
+			else if(is_audible)
+				viewer.show_message("<span class='emote'><b>[user]</b> [msg]</span>", MSG_AUDIBLE)
+			else if(is_visual)
+				viewer.show_message("<span class='emote'><b>[user]</b> [msg]</span>", MSG_VISUAL)
+		return TRUE // Early exit so no dchat message
+
+	// The emote has some important information, and should always be shown to the user
+	else if(is_important)
+		for(var/mob/viewer as anything in viewers(user))
+			to_chat(viewer, "<span class='emote'><b>[user]</b> [msg]</span>")
+			if(user.runechat_prefs_check(viewer, EMOTE_MESSAGE))
+				viewer.create_chat_message(
+					speaker = user,
+					raw_message = msg,
+					runechat_flags = EMOTE_MESSAGE,
+				)
+	// Emotes has both an audible and visible component
+	// Prioritize audible, and provide a visible message if the user is deaf
+	else if(is_visual && is_audible)
+		user.audible_message(
+			message = msg,
+			deaf_message = "<span class='emote'>You see how <b>[user]</b> [msg]</span>",
+			self_message = msg,
+			audible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE,
+		)
+	// Emote is entirely audible, no visible component
+	else if(is_audible)
+		user.audible_message(
+			message = msg,
+			self_message = msg,
+			audible_message_flags = EMOTE_MESSAGE,
+		)
+	// Emote is entirely visible, no audible component
+	else if(is_visual)
+		user.visible_message(
+			message = msg,
+			self_message = msg,
+			visible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE,
+		)
+	else
+		CRASH("Emote [type] has no valid emote type set!")
+
+	if(!isnull(user.client))
+		var/dchatmsg = "<b>[user]</b> [msg]"
+		for(var/mob/ghost as anything in GLOB.dead_mob_list - viewers(get_turf(user)))
+			if(isnull(ghost.client) || isnewplayer(ghost))
+				continue
+			if(!(get_chat_toggles(ghost.client) & CHAT_GHOSTSIGHT))
 				continue
-			if(get_chat_toggles(ghost.client) & CHAT_GHOSTSIGHT && !(ghost in viewers(user_turf, null)))
-				ghost.show_message("<span class='emote'>[FOLLOW_LINK(ghost, user)] [dchatmsg]</span>")
-	if(emote_type & (EMOTE_AUDIBLE | EMOTE_VISIBLE)) //emote is audible and visible
-		user.audible_message(msg, deaf_message = "<span class='emote'>You see how <b>[user]</b> [msg]</span>", audible_message_flags = EMOTE_MESSAGE)
-	else if(emote_type & EMOTE_VISIBLE)	//emote is only visible
-		user.visible_message(msg, visible_message_flags = EMOTE_MESSAGE)
-	if(emote_type & EMOTE_IMPORTANT)
-		for(var/mob/living/viewer in viewers())
-			if(viewer.is_blind() && !viewer.can_hear())
-				to_chat(viewer, msg)
+			to_chat(ghost, "<span class='emote'>[FOLLOW_LINK(ghost, user)] [dchatmsg]</span>")
+
+	return TRUE
 
 /**
  * For handling emote cooldown, return true to allow the emote to happen.
diff --git a/code/datums/mood.dm b/code/datums/mood.dm
index 150220cfbcfd..c61ceea0faf6 100644
--- a/code/datums/mood.dm
+++ b/code/datums/mood.dm
@@ -92,7 +92,6 @@
 			set_sanity(sanity + 0.4 * seconds_per_tick, SANITY_NEUTRAL, SANITY_MAXIMUM)
 		if(MOOD_LEVEL_HAPPY4)
 			set_sanity(sanity + 0.6 * seconds_per_tick, SANITY_NEUTRAL, SANITY_MAXIMUM)
-	handle_nutrition()
 
 	// 0.416% is 15 successes / 3600 seconds. Calculated with 2 minute
 	// mood runtime, so 50% average uptime across the hour.
@@ -112,16 +111,18 @@
 	last_stat = mob_parent.stat
 
 /// Handles mood given by nutrition
-/datum/mood/proc/handle_nutrition()
-	if (HAS_TRAIT(mob_parent, TRAIT_NOHUNGER))
-		clear_mood_event(MOOD_CATEGORY_NUTRITION)  // if you happen to switch species while hungry youre no longer hungy
-		return FALSE // no moods for nutrition
+/datum/mood/proc/update_nutrition_moodlets()
+	if(HAS_TRAIT(mob_parent, TRAIT_NOHUNGER))
+		clear_mood_event(MOOD_CATEGORY_NUTRITION)
+		return FALSE
+
+	if(HAS_TRAIT(mob_parent, TRAIT_FAT) && !HAS_TRAIT(mob_parent, TRAIT_VORACIOUS))
+		add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/fat)
+		return TRUE
+
 	switch(mob_parent.nutrition)
 		if(NUTRITION_LEVEL_FULL to INFINITY)
-			if (!HAS_TRAIT(mob_parent, TRAIT_VORACIOUS))
-				add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/fat)
-			else
-				add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/wellfed) // round and full
+			add_mood_event(MOOD_CATEGORY_NUTRITION, HAS_TRAIT(mob_parent, TRAIT_VORACIOUS) ? /datum/mood_event/wellfed : /datum/mood_event/too_wellfed)
 		if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
 			add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/wellfed)
 		if( NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
@@ -133,6 +134,8 @@
 		if(0 to NUTRITION_LEVEL_STARVING)
 			add_mood_event(MOOD_CATEGORY_NUTRITION, /datum/mood_event/starving)
 
+	return TRUE
+
 /**
  * Adds a mood event to the mob
  *
diff --git a/code/datums/mood_events/needs_events.dm b/code/datums/mood_events/needs_events.dm
index dd710554d8d9..dd5441476dcf 100644
--- a/code/datums/mood_events/needs_events.dm
+++ b/code/datums/mood_events/needs_events.dm
@@ -3,6 +3,10 @@
 	description = "<B>I'm so fat...</B>" //muh fatshaming
 	mood_change = -6
 
+/datum/mood_event/too_wellfed
+	description = "I think I've eaten too much."
+	mood_change = 0
+
 /datum/mood_event/wellfed
 	description = "I'm stuffed!"
 	mood_change = 8
@@ -62,7 +66,7 @@
 	mood_change = -12
 
 /datum/mood_event/disgust/dirty_food
-	description = "It was too dirty to eat..."
+	description = "That was too dirty to eat..."
 	mood_change = -6
 	timeout = 4 MINUTES
 
diff --git a/code/datums/quirks/negative_quirks/social_anxiety.dm b/code/datums/quirks/negative_quirks/social_anxiety.dm
index b6916b2dd038..046ac4715f57 100644
--- a/code/datums/quirks/negative_quirks/social_anxiety.dm
+++ b/code/datums/quirks/negative_quirks/social_anxiety.dm
@@ -15,9 +15,26 @@
 	RegisterSignal(quirk_holder, COMSIG_MOB_EYECONTACT, PROC_REF(eye_contact))
 	RegisterSignal(quirk_holder, COMSIG_MOB_EXAMINATE, PROC_REF(looks_at_floor))
 	RegisterSignal(quirk_holder, COMSIG_MOB_SAY, PROC_REF(handle_speech))
+	quirk_holder.apply_status_effect(/datum/status_effect/speech/stutter/anxiety, INFINITY)
 
 /datum/quirk/social_anxiety/remove()
 	UnregisterSignal(quirk_holder, list(COMSIG_MOB_EYECONTACT, COMSIG_MOB_EXAMINATE, COMSIG_MOB_SAY))
+	quirk_holder.remove_status_effect(/datum/status_effect/speech/stutter/anxiety)
+
+/// Calculates how much to modifiy our effects based on our mood level
+/datum/quirk/social_anxiety/proc/calculate_mood_mod()
+	var/nearby_people = 0
+	for(var/mob/living/carbon/human/listener in oview(3, quirk_holder))
+		if(listener.client || listener.mind)
+			nearby_people++
+
+	var/mod = 1
+	if(quirk_holder.mob_mood)
+		mod = 1 + 0.02 * (50 - (max(50, quirk_holder.mob_mood.mood_level * (SANITY_LEVEL_MAX + 1 - quirk_holder.mob_mood.sanity_level)))) //low sanity levels are better, they max at 6
+	else
+		mod = 1 + 0.02 * (50 - (max(50, 0.1 * quirk_holder.nutrition)))
+
+	return mod * nearby_people * 12.5
 
 /datum/quirk/social_anxiety/proc/handle_speech(datum/source, list/speech_args)
 	SIGNAL_HANDLER
@@ -27,48 +44,33 @@
 	if(HAS_TRAIT(source, TRAIT_SIGN_LANG)) // No modifiers for signers, so you're less anxious when you go non-verbal
 		return
 
-	var/moodmod
-	if(quirk_holder.mob_mood)
-		moodmod = (1+0.02*(50-(max(50, quirk_holder.mob_mood.mood_level*(7-quirk_holder.mob_mood.sanity_level))))) //low sanity levels are better, they max at 6
-	else
-		moodmod = (1+0.02*(50-(max(50, 0.1*quirk_holder.nutrition))))
-	var/nearby_people = 0
-	for(var/mob/living/carbon/human/H in oview(3, quirk_holder))
-		if(H.client)
-			nearby_people++
+	var/moodmod = calculate_mood_mod()
 	var/message = speech_args[SPEECH_MESSAGE]
 	if(message)
 		var/list/message_split = splittext(message, " ")
 		var/list/new_message = list()
-		var/mob/living/carbon/human/quirker = quirk_holder
 		for(var/word in message_split)
-			if(prob(max(5,(nearby_people*12.5*moodmod))) && word != message_split[1]) //Minimum 1/20 chance of filler
+			if(prob(max(5, moodmod)) && word != message_split[1]) //Minimum 1/20 chance of filler
 				new_message += pick("uh,","erm,","um,")
-				if(prob(min(5,(0.05*(nearby_people*12.5)*moodmod)))) //Max 1 in 20 chance of cutoff after a successful filler roll, for 50% odds in a 15 word sentence
-					quirker.set_silence_if_lower(6 SECONDS)
-					to_chat(quirker, span_danger("You feel self-conscious and stop talking. You need a moment to recover!"))
+				if(prob(min(5, moodmod))) //Max 1 in 20 chance of cutoff after a successful filler roll, for 50% odds in a 15 word sentence
+					quirk_holder.set_silence_if_lower(6 SECONDS)
+					to_chat(quirk_holder, span_danger("You feel self-conscious and stop talking. You need a moment to recover!"))
 					break
-			if(prob(max(5,(nearby_people*12.5*moodmod)))) //Minimum 1/20 chance of stutter
-				// Add a short stutter, THEN treat our word
-				quirker.adjust_stutter(0.5 SECONDS)
-				var/list/message_data = quirker.treat_message(word, capitalize_message = FALSE)
-				new_message += message_data["message"]
-			else
-				new_message += word
+			new_message += word
 
 		message = jointext(new_message, " ")
-	var/mob/living/carbon/human/quirker = quirk_holder
-	if(prob(min(50,(0.50*(nearby_people*12.5)*moodmod)))) //Max 50% chance of not talking
+
+	if(prob(min(50, (0.50 * moodmod)))) //Max 50% chance of not talking
 		if(dumb_thing)
-			to_chat(quirker, span_userdanger("You think of a dumb thing you said a long time ago and scream internally."))
+			to_chat(quirk_holder, span_userdanger("You think of a dumb thing you said a long time ago and scream internally."))
 			dumb_thing = FALSE //only once per life
 			if(prob(1))
-				new/obj/item/food/spaghetti/pastatomato(get_turf(quirker)) //now that's what I call spaghetti code
+				new/obj/item/food/spaghetti/pastatomato(get_turf(quirk_holder)) //now that's what I call spaghetti code
 		else
 			to_chat(quirk_holder, span_warning("You think that wouldn't add much to the conversation and decide not to say it."))
-			if(prob(min(25,(0.25*(nearby_people*12.75)*moodmod)))) //Max 25% chance of silence stacks after successful not talking roll
-				to_chat(quirker, span_danger("You retreat into yourself. You <i>really</i> don't feel up to talking."))
-				quirker.set_silence_if_lower(10 SECONDS)
+			if(prob(min(25, (0.25 * moodmod)))) //Max 25% chance of silence stacks after successful not talking roll
+				to_chat(quirk_holder, span_danger("You retreat into yourself. You <i>really</i> don't feel up to talking."))
+				quirk_holder.set_silence_if_lower(10 SECONDS)
 
 		speech_args[SPEECH_MESSAGE] = pick("Uh.","Erm.","Um.")
 	else
diff --git a/code/datums/quirks/positive_quirks/strong_stomach.dm b/code/datums/quirks/positive_quirks/strong_stomach.dm
new file mode 100644
index 000000000000..8c0a3f3b1375
--- /dev/null
+++ b/code/datums/quirks/positive_quirks/strong_stomach.dm
@@ -0,0 +1,12 @@
+/datum/quirk/strong_stomach
+	name = "Strong Stomach"
+	desc = "You can eat food discarded on the ground without getting sick, and vomiting affects you less."
+	icon = FA_ICON_FACE_GRIN_BEAM_SWEAT
+	value = 4
+	mob_trait = TRAIT_STRONG_STOMACH
+	gain_text = span_notice("You feel like you could eat anything!")
+	lose_text = span_danger("Looking at food on the ground makes you feel a little queasy.")
+	medical_record_text = "Patient has a stronger than average immune system...to food poisoning, at least."
+	mail_goodies = list(
+		/obj/item/reagent_containers/pill/ondansetron,
+	)
diff --git a/code/datums/status_effects/debuffs/fire_stacks.dm b/code/datums/status_effects/debuffs/fire_stacks.dm
index 4a6e7b6b730f..2f32ff5b3bed 100644
--- a/code/datums/status_effects/debuffs/fire_stacks.dm
+++ b/code/datums/status_effects/debuffs/fire_stacks.dm
@@ -7,7 +7,7 @@
 	/// Current amount of stacks we have
 	var/stacks
 	/// Maximum of stacks that we could possibly get
-	var/stack_limit = 20
+	var/stack_limit = MAX_FIRE_STACKS
 	/// What status effect types do we remove uppon being applied. These are just deleted without any deduction from our or their stacks when forced.
 	var/list/enemy_types
 	/// What status effect types do we merge into if they exist. Ignored when forced.
@@ -116,12 +116,8 @@
 		owner.clear_alert(ALERT_FIRE)
 	else if(!was_on_fire && owner.on_fire)
 		owner.throw_alert(ALERT_FIRE, /atom/movable/screen/alert/fire)
-
-/**
- * Used to update owner's effect overlay
- */
-
-/datum/status_effect/fire_handler/proc/update_overlay()
+	owner.update_appearance(UPDATE_OVERLAYS)
+	update_particles()
 
 /datum/status_effect/fire_handler/fire_stacks
 	id = "fire_stacks" //fire_stacks and wet_stacks should have different IDs or else has_status_effect won't work
@@ -132,8 +128,6 @@
 
 	/// If we're on fire
 	var/on_fire = FALSE
-	/// Stores current fire overlay icon state, for optimisation purposes
-	var/last_icon_state
 	/// Reference to the mob light emitter itself
 	var/obj/effect/dummy/lighting_obj/moblight
 	/// Type of mob light emitter we use when on fire
@@ -160,8 +154,6 @@
 		return TRUE
 
 	deal_damage(seconds_between_ticks)
-	update_overlay()
-	update_particles()
 
 /datum/status_effect/fire_handler/fire_stacks/update_particles()
 	if(on_fire)
@@ -239,8 +231,6 @@
 		moblight = new moblight_type(owner)
 
 	cache_stacks()
-	update_overlay()
-	update_particles()
 	SEND_SIGNAL(owner, COMSIG_LIVING_IGNITED, owner)
 	return TRUE
 
@@ -254,8 +244,6 @@
 	owner.clear_mood_event("on_fire")
 	SEND_SIGNAL(owner, COMSIG_LIVING_EXTINGUISHED, owner)
 	cache_stacks()
-	update_overlay()
-	update_particles()
 	for(var/obj/item/equipped in owner.get_equipped_items())
 		equipped.extinguish()
 
@@ -263,16 +251,26 @@
 	if(on_fire)
 		extinguish()
 	set_stacks(0)
-	update_overlay()
-	update_particles()
+	UnregisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS)
+	owner.update_appearance(UPDATE_OVERLAYS)
 	return ..()
 
-/datum/status_effect/fire_handler/fire_stacks/update_overlay()
-	last_icon_state = owner.update_fire_overlay(stacks, on_fire, last_icon_state)
-
 /datum/status_effect/fire_handler/fire_stacks/on_apply()
 	. = ..()
-	update_overlay()
+	RegisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(add_fire_overlay))
+	owner.update_appearance(UPDATE_OVERLAYS)
+
+/datum/status_effect/fire_handler/fire_stacks/proc/add_fire_overlay(mob/living/source, list/overlays)
+	SIGNAL_HANDLER
+
+	if(stacks <= 0 || !on_fire)
+		return
+
+	var/mutable_appearance/created_overlay = owner.get_fire_overlay(stacks, on_fire)
+	if(isnull(created_overlay))
+		return
+
+	overlays |= created_overlay
 
 /obj/effect/dummy/lighting_obj/moblight/fire
 	name = "fire"
diff --git a/code/datums/status_effects/debuffs/speech_debuffs.dm b/code/datums/status_effects/debuffs/speech_debuffs.dm
index 4968bb42e39b..f8371c82dc21 100644
--- a/code/datums/status_effects/debuffs/speech_debuffs.dm
+++ b/code/datums/status_effects/debuffs/speech_debuffs.dm
@@ -2,8 +2,10 @@
 	id = null
 	alert_type = null
 	remove_on_fullheal = TRUE
-
+	tick_interval = -1
+	/// If TRUE, TTS will say the original message rather than what we changed it to
 	var/make_tts_message_original = FALSE
+	/// If set, this will be appended to the TTS filter of the message
 	var/tts_filter = ""
 
 /datum/status_effect/speech/on_creation(mob/living/new_owner, duration = 10 SECONDS)
@@ -41,7 +43,15 @@
 	for(var/i = 1, i <= length(phrase), i += length(original_char))
 		original_char = phrase[i]
 
-		final_phrase += apply_speech(original_char, original_char)
+		final_phrase += apply_speech(original_char)
+
+	if(final_phrase == phrase)
+		return // No change was done, whatever
+
+	if(length(tts_filter) > 0)
+		message_args[TREAT_TTS_FILTER_ARG] += tts_filter
+	if(make_tts_message_original)
+		message_args[TREAT_TTS_MESSAGE_ARG] = message_args[TREAT_MESSAGE_ARG]
 
 	message_args[TREAT_MESSAGE_ARG] = sanitize(final_phrase)
 
@@ -51,20 +61,26 @@
  *
  * Return the modified_char to be reapplied to the message.
  */
-/datum/status_effect/speech/proc/apply_speech(original_char, modified_char)
+/datum/status_effect/speech/proc/apply_speech(original_char)
 	stack_trace("[type] didn't implement apply_speech.")
 	return original_char
 
 /datum/status_effect/speech/stutter
 	id = "stutter"
+	make_tts_message_original = TRUE
+	tts_filter = "tremolo=f=10:d=0.8,rubberband=tempo=0.5"
+
 	/// The probability of adding a stutter to any character
 	var/stutter_prob = 80
+	/// The chance of a four character stutter
+	var/four_char_chance = 10
+	/// The chance of a three character stutter
+	var/three_char_chance = 20
+	/// The chance of a two character stutter
+	var/two_char_chance = 95
 	/// Regex of characters we won't apply a stutter to
 	var/static/regex/no_stutter
 
-	make_tts_message_original = TRUE
-	tts_filter = "tremolo=f=10:d=0.8,rubberband=tempo=0.5"
-
 /datum/status_effect/speech/stutter/on_creation(mob/living/new_owner, ...)
 	. = ..()
 	if(!.)
@@ -72,18 +88,32 @@
 	if(!no_stutter)
 		no_stutter = regex(@@[aeiouAEIOU ""''()[\]{}.!?,:;_`~-]@)
 
-/datum/status_effect/speech/stutter/apply_speech(original_char, modified_char)
+/datum/status_effect/speech/stutter/apply_speech(original_char)
 	if(prob(stutter_prob) && !no_stutter.Find(original_char))
-		if(prob(10))
-			modified_char = "[modified_char]-[modified_char]-[modified_char]-[modified_char]"
-		else if(prob(20))
-			modified_char = "[modified_char]-[modified_char]-[modified_char]"
-		else if(prob(95))
-			modified_char = "[modified_char]-[modified_char]"
-		else
-			modified_char = ""
+		if(prob(four_char_chance))
+			return "[original_char]-[original_char]-[original_char]-[original_char]"
+		if(prob(three_char_chance))
+			return "[original_char]-[original_char]-[original_char]"
+		if(prob(two_char_chance))
+			return "[original_char]-[original_char]"
 
-	return modified_char
+	return original_char
+
+/datum/status_effect/speech/stutter/anxiety
+	id = "anxiety_stutter"
+	stutter_prob = 5
+	four_char_chance = 4
+	three_char_chance = 10
+	two_char_chance = 100
+	remove_on_fullheal = FALSE
+
+/datum/status_effect/speech/stutter/anxiety/handle_message(datum/source, list/message_args)
+	if(HAS_TRAIT(owner, TRAIT_FEARLESS) || HAS_TRAIT(owner, TRAIT_SIGN_LANG))
+		stutter_prob = 0
+	else
+		var/datum/quirk/social_anxiety/host_quirk = owner.get_quirk(/datum/quirk/social_anxiety)
+		stutter_prob = clamp(host_quirk?.calculate_mood_mod() * 0.5, 5, 50)
+	return ..()
 
 /datum/status_effect/speech/stutter/derpspeech
 	id = "derp_stutter"
@@ -160,8 +190,9 @@
 	string_replacements = speech_changes["string_replacements"]
 	string_additions = speech_changes["string_additions"]
 
-/datum/status_effect/speech/slurring/apply_speech(original_char, modified_char)
+/datum/status_effect/speech/slurring/apply_speech(original_char)
 
+	var/modified_char = original_char
 	var/lower_char = lowertext(modified_char)
 	if(prob(common_prob) && (lower_char in common_replacements))
 		var/to_replace = common_replacements[lower_char]
diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm
index de4de4673289..415113c3bd77 100644
--- a/code/datums/wounds/burns.dm
+++ b/code/datums/wounds/burns.dm
@@ -130,8 +130,7 @@
 					if(0)
 						to_chat(victim, span_deadsay("<b>The last of the nerve endings in your [limb.plaintext_zone] wither away, as the infection completely paralyzes your joint connector.</b>"))
 						threshold_penalty = 120 // piss easy to destroy
-						var/datum/brain_trauma/severe/paralysis/sepsis = new (limb.body_zone)
-						victim.gain_trauma(sepsis)
+						set_disabling(TRUE)
 
 /datum/wound/burn/flesh/get_wound_description(mob/user)
 	if(strikes_to_lose_limb <= 0)
diff --git a/code/game/atom/atom_examine.dm b/code/game/atom/atom_examine.dm
index de813cd983dc..ad1d83222778 100644
--- a/code/game/atom/atom_examine.dm
+++ b/code/game/atom/atom_examine.dm
@@ -75,13 +75,16 @@
  * [COMSIG_ATOM_GET_EXAMINE_NAME] signal
  */
 /atom/proc/get_examine_name(mob/user)
-	. = "\a <b>[src]</b>"
-	var/list/override = list(gender == PLURAL ? "some" : "a", " ", "[name]")
-	if(article)
-		. = "[article] <b>[src]</b>"
-		override[EXAMINE_POSITION_ARTICLE] = article
-	if(SEND_SIGNAL(src, COMSIG_ATOM_GET_EXAMINE_NAME, user, override) & COMPONENT_EXNAME_CHANGED)
-		. = override.Join("")
+	var/list/override = list(article, null, "<b>[name]</b>")
+	SEND_SIGNAL(src, COMSIG_ATOM_GET_EXAMINE_NAME, user, override)
+
+	if(!isnull(override[EXAMINE_POSITION_ARTICLE]))
+		override -= null // IF there is no "before", don't try to join it
+		return jointext(override, " ")
+	if(!isnull(override[EXAMINE_POSITION_BEFORE]))
+		override -= null // There is no article, don't try to join it
+		return "\a [jointext(override, " ")]"
+	return "\a <b>[src]</b>"
 
 ///Generate the full examine string of this atom (including icon for goonchat)
 /atom/proc/get_examine_string(mob/user, thats = FALSE)
diff --git a/code/game/machinery/computer/arcade/arcade.dm b/code/game/machinery/computer/arcade/arcade.dm
index 8cac5ae48f17..d0a8b0a63819 100644
--- a/code/game/machinery/computer/arcade/arcade.dm
+++ b/code/game/machinery/computer/arcade/arcade.dm
@@ -72,8 +72,9 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list(
 		/obj/item/toy/plush/peepy = 2)) // NON-MODULE CHANGE: PEEPY
 
 /obj/machinery/computer/arcade
-	name = "random arcade"
-	desc = "random arcade machine"
+	name = "\proper the arcade cabinet which shouldn't exist"
+	desc = "This arcade cabinet has no games installed, and in fact, should not exist. \
+		Report the location of this machine to your local diety."
 	icon_state = "arcade"
 	icon_keyboard = null
 	icon_screen = "invaders"
@@ -137,19 +138,21 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list(
 		new empprize(loc)
 	explosion(src, devastation_range = -1, light_impact_range = 1+num_of_prizes, flame_range = 1+num_of_prizes)
 
-/obj/machinery/computer/arcade/attackby(obj/item/O, mob/user, params)
-	if(istype(O, /obj/item/stack/arcadeticket))
-		var/obj/item/stack/arcadeticket/T = O
-		var/amount = T.get_amount()
-		if(amount <2)
-			to_chat(user, span_warning("You need 2 tickets to claim a prize!"))
-			return
-		prizevend(user)
-		T.pay_tickets()
-		T.update_appearance()
-		O = T
-		to_chat(user, span_notice("You turn in 2 tickets to the [src] and claim a prize!"))
-		return
+/obj/machinery/computer/arcade/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking)
+	. = ..()
+	if(. & ITEM_INTERACT_ANY_BLOCKER)
+		return .
+	if(!istype(tool, /obj/item/stack/arcadeticket))
+		return .
+
+	var/obj/item/stack/arcadeticket/tickets = tool
+	if(!tickets.use(2))
+		balloon_alert(user, "need 2 tickets!")
+		return ITEM_INTERACT_BLOCKING
+
+	prizevend(user)
+	balloon_alert(user, "prize claimed")
+	return ITEM_INTERACT_SUCCESS
 
 // ** BATTLE ** //
 /obj/machinery/computer/arcade/battle
diff --git a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm
index 092a4c7889a2..4e84870ec9c3 100644
--- a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm
+++ b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm
@@ -65,26 +65,22 @@
 
 /obj/item/organ/internal/heart/rat/on_mob_insert(mob/living/carbon/receiver)
 	. = ..()
-	if(!. || !ishuman(receiver))
+	if(!ishuman(receiver))
 		return
 	var/mob/living/carbon/human/human_receiver = receiver
-	if(!human_receiver.can_mutate())
-		return
-	human_receiver.dna.add_mutation(/datum/mutation/human/dwarfism)
+	if(human_receiver.can_mutate())
+		human_receiver.dna.add_mutation(/datum/mutation/human/dwarfism)
 	//but 1.5 damage
-	if(human_receiver.physiology)
-		human_receiver.physiology.damage_resistance -= 50
+	human_receiver.physiology?.damage_resistance -= 50
 
 /obj/item/organ/internal/heart/rat/on_mob_remove(mob/living/carbon/heartless, special)
 	. = ..()
 	if(!ishuman(heartless))
 		return
 	var/mob/living/carbon/human/human_heartless = heartless
-	if(!human_heartless.can_mutate())
-		return
-	human_heartless.dna.remove_mutation(/datum/mutation/human/dwarfism)
-	if(human_heartless.physiology)
-		human_heartless.physiology.damage_resistance += 50
+	if(human_heartless.can_mutate())
+		human_heartless.dna.remove_mutation(/datum/mutation/human/dwarfism)
+	human_heartless.physiology?.damage_resistance += 50
 
 /// you occasionally squeak, and have some rat related verbal tics
 /obj/item/organ/internal/tongue/rat
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 0bf6bf7872d3..f7e3dbfeefb8 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -557,17 +557,24 @@
 			dump_inventory_contents()
 
 /obj/machinery/suit_storage_unit/process(seconds_per_tick)
-	var/obj/item/stock_parts/cell/cell
-	if(suit && istype(suit))
-		cell = suit.cell
-	if(mod)
-		cell = mod.get_cell()
-	if(!cell || cell.charge == cell.maxcharge)
+	var/list/cells_to_charge = list()
+	for(var/obj/item/charging in list(mod, suit, helmet, mask, storage))
+		var/obj/item/stock_parts/cell/cell_charging = charging.get_cell()
+		if(!istype(cell_charging) || cell_charging.charge == cell_charging.maxcharge)
+			continue
+
+		cells_to_charge += cell_charging
+
+	var/cell_count = length(cells_to_charge)
+	if(cell_count <= 0)
 		return
 
-	var/cell_charged = cell.give(final_charge_rate * seconds_per_tick)
-	if(cell_charged)
-		use_power((active_power_usage + final_charge_rate) * seconds_per_tick)
+	var/charge_per_item = (final_charge_rate * seconds_per_tick) / cell_count
+	for(var/obj/item/stock_parts/cell/cell as anything in cells_to_charge)
+		var/charge_used = use_power_from_net(charge_per_item, take_any = TRUE)
+		if(charge_used <= 0)
+			break
+		cell.give(charge_used)
 
 /obj/machinery/suit_storage_unit/proc/shock(mob/user, prb)
 	if(!prob(prb))
diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm
index f7300f720863..9988f8c91640 100644
--- a/code/game/machinery/teleporter.dm
+++ b/code/game/machinery/teleporter.dm
@@ -73,22 +73,24 @@
 		com.target_ref = null
 		visible_message(span_alert("Cannot authenticate locked on coordinates. Please reinstate coordinate matrix."))
 		return
-	if (ismovable(M))
-		if(do_teleport(M, target, channel = TELEPORT_CHANNEL_BLUESPACE))
-			use_power(active_power_usage)
-			if(!calibrated && prob(30 - ((accuracy) * 10))) //oh dear a problem
-				if(ishuman(M))//don't remove people from the round randomly you jerks
-					var/mob/living/carbon/human/human = M
-					if(!(human.mob_biotypes & (MOB_ROBOTIC|MOB_MINERAL|MOB_UNDEAD|MOB_SPIRIT)))
-						var/datum/species/species_to_transform = /datum/species/fly
-						if(check_holidays(MOTH_WEEK))
-							species_to_transform = /datum/species/moth
-						if(human.dna && human.dna.species.id != initial(species_to_transform.id))
-							to_chat(M, span_hear("You hear a buzzing in your ears."))
-							human.set_species(species_to_transform)
-							human.log_message("was turned into a [initial(species_to_transform.name)] through [src].", LOG_GAME)
-			calibrated = FALSE
-	return
+	if(!ismovable(M))
+		return
+	var/turf/start_turf = get_turf(M)
+	if(!do_teleport(M, target, channel = TELEPORT_CHANNEL_BLUESPACE))
+		return
+	use_power(active_power_usage)
+	new /obj/effect/temp_visual/portal_animation(start_turf, src, M)
+	if(!calibrated && ishuman(M) && prob(30 - ((accuracy) * 10))) //oh dear a problem
+		var/mob/living/carbon/human/human = M
+		if(!(human.mob_biotypes & (MOB_ROBOTIC|MOB_MINERAL|MOB_UNDEAD|MOB_SPIRIT)))
+			var/datum/species/species_to_transform = /datum/species/fly
+			if(check_holidays(MOTH_WEEK))
+				species_to_transform = /datum/species/moth
+			if(human.dna && human.dna.species.id != initial(species_to_transform.id))
+				to_chat(M, span_hear("You hear a buzzing in your ears."))
+				human.set_species(species_to_transform)
+				human.log_message("was turned into a [initial(species_to_transform.name)] through [src].", LOG_GAME)
+	calibrated = FALSE
 
 /obj/machinery/teleport/hub/update_icon_state()
 	icon_state = "[base_icon_state][panel_open ? "-o" : (is_ready() ? 1 : 0)]"
diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm
index 6ae54a8c5105..03543a6df169 100644
--- a/code/game/objects/effects/decals/cleanable/humans.dm
+++ b/code/game/objects/effects/decals/cleanable/humans.dm
@@ -76,7 +76,7 @@
 	for(var/dna_sample in all_dna)
 		var/datum/blood_type/blood = GLOB.blood_types[all_dna[dna_sample]]
 		all_blood_names |= lowertext(initial(blood.reagent_type.name))
-	return english_list(all_blood_names)
+	return english_list(all_blood_names, nothing_text = "blood")
 
 /obj/effect/decal/cleanable/blood/process(seconds_per_tick)
 	if(dried || !can_dry)
diff --git a/code/game/objects/effects/particle_holder.dm b/code/game/objects/effects/particle_holder.dm
index f2cbea06aa73..b5b4fa47108d 100644
--- a/code/game/objects/effects/particle_holder.dm
+++ b/code/game/objects/effects/particle_holder.dm
@@ -64,7 +64,6 @@
 		var/mob/particle_mob = attached.loc
 		particle_mob.vis_contents += src
 
-/// Sets the particles position to the passed coordinate list (X, Y, Z)
-/// See [https://www.byond.com/docs/ref/#/{notes}/particles] for position documentation
-/obj/effect/abstract/particle_holder/proc/set_particle_position(list/pos)
-	particles.position = pos
+/// Sets the particles position to the passed coordinates
+/obj/effect/abstract/particle_holder/proc/set_particle_position(x = 0, y = 0, z = 0)
+	particles.position = list(x, y, z)
diff --git a/code/game/objects/effects/particles/smoke.dm b/code/game/objects/effects/particles/smoke.dm
index 4f31ffc08699..27249c65a683 100644
--- a/code/game/objects/effects/particles/smoke.dm
+++ b/code/game/objects/effects/particles/smoke.dm
@@ -37,6 +37,31 @@
 	spawning = 2
 	velocity = list(0, 0.25, 0)
 
+/particles/smoke/cig
+	icon_state = list("steam_1" = 2, "steam_2" = 1, "steam_3" = 1)
+	count = 1
+	spawning = 0.05 // used to pace it out roughly in time with breath ticks
+	position = list(-6, -2, 0)
+	gravity = list(0, 0.75, 0)
+	lifespan = 0.75 SECONDS
+	fade = 0.75 SECONDS
+	velocity = list(0, 0.2, 0)
+	scale = 0.5
+	grow = 0.01
+	friction = 0.5
+	color = "#d0d0d09d"
+
+/particles/smoke/cig/big
+	icon_state = list("steam_1" = 1, "steam_2" = 2, "steam_3" = 2)
+	gravity = list(0, 0.5, 0)
+	velocity = list(0, 0.1, 0)
+	lifespan = 1 SECONDS
+	fade = 1 SECONDS
+	grow = 0.1
+	scale = 0.75
+	spawning = 1
+	friction = 0.75
+
 /particles/smoke/ash
 	icon_state = list("ash_1" = 2, "ash_2" = 2, "ash_3" = 1, "smoke_1" = 3, "smoke_2" = 2)
 	count = 500
@@ -46,3 +71,16 @@
 	fadein = 0.7 SECONDS
 	position = generator(GEN_VECTOR, list(-3, 5, 0), list(3, 6.5, 0), NORMAL_RAND)
 	velocity = generator(GEN_VECTOR, list(-0.1, 0.4, 0), list(0.1, 0.5, 0), NORMAL_RAND)
+
+/particles/fog
+	icon = 'icons/effects/particles/smoke.dmi'
+	icon_state = list("chill_1" = 2, "chill_2" = 2, "chill_3" = 1)
+
+/particles/fog/breath
+	count = 1
+	spawning = 1
+	lifespan = 1 SECONDS
+	fade = 0.5 SECONDS
+	grow = 0.05
+	spin = 2
+	color = "#fcffff77"
diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm
index 091b47006732..8fb5dfea9bfb 100644
--- a/code/game/objects/effects/portals.dm
+++ b/code/game/objects/effects/portals.dm
@@ -140,10 +140,12 @@
 		no_effect = TRUE
 	else
 		last_effect = world.time
+	var/turf/start_turf = get_turf(M)
 	if(do_teleport(M, real_target, innate_accuracy_penalty, no_effects = no_effect, channel = teleport_channel, forced = force_teleport))
 		if(isprojectile(M))
 			var/obj/projectile/P = M
 			P.ignore_source_check = TRUE
+		new /obj/effect/temp_visual/portal_animation(start_turf, src, M)
 		return TRUE
 	return FALSE
 
@@ -206,3 +208,22 @@
 	. = ..()
 	if (. && !isdead(M))
 		qdel(src)
+
+/**
+ * Animation used for transitioning atoms which are teleporting somewhere via a portal
+ *
+ * To use, pass it the atom doing the teleporting and the atom that is being teleported in init.
+ */
+/obj/effect/temp_visual/portal_animation
+	duration = 0.25 SECONDS
+
+/obj/effect/temp_visual/portal_animation/Initialize(mapload, atom/portal, atom/movable/teleporting)
+	. = ..()
+	if(isnull(portal) || isnull(teleporting))
+		return
+
+	appearance = teleporting.appearance
+	dir = teleporting.dir
+	layer = portal.layer + 0.01
+	alpha = teleporting.alpha
+	animate(src, pixel_x = (portal.x * 32) - (x * 32), pixel_y = (portal.y * 32) - (y * 32), alpha = 0, time = duration)
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index 30c853746b48..d6ab992cb1b2 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -137,7 +137,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 	heat = 1000
 	throw_verb = "flick"
 	/// Whether this cigarette has been lit.
-	var/lit = FALSE
+	VAR_FINAL/lit = FALSE
 	/// Whether this cigarette should start lit.
 	var/starts_lit = FALSE
 	// Note - these are in masks.dmi not in cigarette.dmi
@@ -169,6 +169,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 	var/choke_forever = FALSE
 	/// When choking, what is the maximum amount of time we COULD choke for
 	var/choke_time_max = 30 SECONDS // I am mean
+	/// The particle effect of the smoke rising out of the cigarette when lit
+	VAR_PRIVATE/obj/effect/abstract/particle_holder/cig_smoke
+	/// The particle effect of the smoke rising out of the mob when...smoked
+	VAR_PRIVATE/obj/effect/abstract/particle_holder/mob_smoke
+	/// How long the current mob has been smoking this cigarette
+	VAR_FINAL/how_long_have_we_been_smokin = 0 SECONDS
 
 /obj/item/clothing/mask/cigarette/Initialize(mapload)
 	. = ..()
@@ -184,23 +190,59 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 
 /obj/item/clothing/mask/cigarette/Destroy()
 	STOP_PROCESSING(SSobj, src)
+	QDEL_NULL(mob_smoke)
+	QDEL_NULL(cig_smoke)
 	return ..()
 
 /obj/item/clothing/mask/cigarette/equipped(mob/equipee, slot)
 	. = ..()
 	if(!(slot & ITEM_SLOT_MASK))
-		UnregisterSignal(equipee, COMSIG_HUMAN_FORCESAY)
+		UnregisterSignal(equipee, list(COMSIG_HUMAN_FORCESAY, COMSIG_ATOM_DIR_CHANGE))
 		return
 	RegisterSignal(equipee, COMSIG_HUMAN_FORCESAY, PROC_REF(on_forcesay))
+	RegisterSignal(equipee, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_mob_dir_change))
+
+	if(lit && iscarbon(loc))
+		make_mob_smoke(loc)
 
-/obj/item/clothing/mask/cigarette/dropped(mob/dropee)
+/obj/item/clothing/mask/cigarette/dropped(mob/dropee, silent)
 	. = ..()
-	UnregisterSignal(dropee, COMSIG_HUMAN_FORCESAY)
+	// Moving the cigarette from mask to hands (or pocket I guess) will emit a larger puff of smoke
+	if(!QDELETED(src) && !QDELETED(dropee) && how_long_have_we_been_smokin >= 4 SECONDS && iscarbon(dropee) && iscarbon(loc))
+		var/mob/living/carbon/smoker = dropee
+		// This relies on the fact that dropped is called before slot is nulled
+		if(src == smoker.wear_mask && !smoker.incapacitated())
+			long_exhale(smoker)
+
+	UnregisterSignal(dropee, list(COMSIG_HUMAN_FORCESAY, COMSIG_ATOM_DIR_CHANGE))
+	QDEL_NULL(mob_smoke)
+	how_long_have_we_been_smokin = 0 SECONDS
 
 /obj/item/clothing/mask/cigarette/proc/on_forcesay(mob/living/source)
 	SIGNAL_HANDLER
 	source.apply_status_effect(/datum/status_effect/choke, src, lit, choke_forever ? -1 : rand(25 SECONDS, choke_time_max))
 
+/obj/item/clothing/mask/cigarette/proc/on_mob_dir_change(mob/living/source, old_dir, new_dir)
+	SIGNAL_HANDLER
+	if(isnull(mob_smoke))
+		return
+	update_particle_position(mob_smoke, new_dir)
+
+/obj/item/clothing/mask/cigarette/proc/update_particle_position(obj/effect/abstract/particle_holder/to_edit, new_dir = loc.dir)
+	var/new_x = 0
+	var/new_layer = initial(to_edit.layer)
+	if(new_dir & NORTH)
+		new_x = 4
+		new_layer = BELOW_MOB_LAYER
+	else if(new_dir & SOUTH)
+		new_x = -4
+	else if(new_dir & EAST)
+		new_x = 8
+	else if(new_dir & WEST)
+		new_x = -8
+	to_edit.set_particle_position(new_x, 8, 0)
+	to_edit.layer = new_layer
+
 /obj/item/clothing/mask/cigarette/suicide_act(mob/living/user)
 	user.visible_message(span_suicide("[user] is huffing [src] as quickly as [user.p_they()] can! It looks like [user.p_theyre()] trying to give [user.p_them()]self cancer."))
 	return (TOXLOSS|OXYLOSS)
@@ -266,9 +308,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 		return
 
 	lit = TRUE
-
+	make_cig_smoke()
 	if(!(flags_1 & INITIALIZED_1))
-		update_icon()
+		update_appearance(UPDATE_ICON)
 		return
 
 	attack_verb_continuous = string_list(list("burns", "singes"))
@@ -291,17 +333,16 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 	// allowing reagents to react after being lit
 	reagents.flags &= ~(NO_REACT)
 	reagents.handle_reactions()
-	update_icon()
+	update_appearance(UPDATE_ICON)
 	if(flavor_text)
 		var/turf/T = get_turf(src)
 		T.visible_message(flavor_text)
 	START_PROCESSING(SSobj, src)
 
-	//can't think of any other way to update the overlays :<
-	if(ismob(loc))
-		var/mob/M = loc
-		M.update_worn_mask()
-		M.update_held_items()
+	if(iscarbon(loc))
+		var/mob/living/carbon/smoker = loc
+		if(src == smoker.wear_mask)
+			make_mob_smoke(smoker)
 
 /obj/item/clothing/mask/cigarette/extinguish()
 	. = ..()
@@ -315,18 +356,29 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 	STOP_PROCESSING(SSobj, src)
 	reagents.flags |= NO_REACT
 	lit = FALSE
-	update_icon()
-
+	update_appearance(UPDATE_ICON)
 	if(ismob(loc))
-		var/mob/living/M = loc
-		to_chat(M, span_notice("Your [name] goes out."))
-		M.update_worn_mask()
-		M.update_held_items()
+		to_chat(loc, span_notice("Your [name] goes out."))
+	QDEL_NULL(cig_smoke)
+	QDEL_NULL(mob_smoke)
+
+/obj/item/clothing/mask/cigarette/proc/long_exhale(mob/living/carbon/smoker)
+	smoker.visible_message(
+		span_notice("[smoker] exhales a large cloud of smoke from [src]."),
+		span_notice("You exhale a large cloud of smoke from [src]."),
+	)
+	if(!isturf(smoker.loc))
+		return
+
+	var/obj/effect/abstract/particle_holder/big_smoke = new(smoker.loc, /particles/smoke/cig/big)
+	update_particle_position(big_smoke, smoker.dir)
+	QDEL_IN(big_smoke, big_smoke.particles.lifespan)
 
 /// Handles processing the reagents in the cigarette.
-/obj/item/clothing/mask/cigarette/proc/handle_reagents()
+/obj/item/clothing/mask/cigarette/proc/handle_reagents(seconds_per_tick)
 	if(!reagents.total_volume)
 		return
+	how_long_have_we_been_smokin += seconds_per_tick * (1 SECONDS)
 	reagents.expose_temperature(heat, 0.05)
 	if(!reagents.total_volume) //may have reacted and gone to 0 after expose_temperature
 		return
@@ -375,7 +427,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 	open_flame(heat)
 	if((reagents?.total_volume) && COOLDOWN_FINISHED(src, drag_cooldown))
 		COOLDOWN_START(src, drag_cooldown, dragtime)
-		handle_reagents()
+		handle_reagents(seconds_per_tick)
 
 /obj/item/clothing/mask/cigarette/attack_self(mob/user)
 	if(lit)
@@ -384,11 +436,17 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 
 /obj/item/clothing/mask/cigarette/proc/put_out(mob/user, done_early = FALSE)
 	var/atom/location = drop_location()
-	if(done_early)
-		user.visible_message(span_notice("[user] calmly drops and treads on \the [src], putting it out instantly."))
-		new /obj/effect/decal/cleanable/ash(location)
-	else if(user)
-		to_chat(user, span_notice("Your [name] goes out."))
+	if(!isnull(user))
+		if(done_early)
+			if(isfloorturf(location) && location.has_gravity())
+				user.visible_message(span_notice("[user] calmly drops and treads on [src], putting it out instantly."))
+				new /obj/effect/decal/cleanable/ash(location)
+				long_exhale(user)
+			else
+				user.visible_message(span_notice("[user] pinches out [src]."))
+			how_long_have_we_been_smokin = 0 SECONDS
+		else
+			to_chat(user, span_notice("Your [name] goes out."))
 	new type_butt(location)
 	qdel(src)
 
@@ -415,6 +473,15 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 /obj/item/clothing/mask/cigarette/get_temperature()
 	return lit * heat
 
+/obj/item/clothing/mask/cigarette/proc/make_mob_smoke(mob/living/smoker)
+	mob_smoke = new(smoker, /particles/smoke/cig)
+	update_particle_position(mob_smoke, smoker.dir)
+	return mob_smoke
+
+/obj/item/clothing/mask/cigarette/proc/make_cig_smoke()
+	cig_smoke = new(src, /particles/smoke/cig)
+	cig_smoke.particles.scale *= 1.5
+	return cig_smoke
 
 // Cigarette brands.
 /obj/item/clothing/mask/cigarette/space_cigarette
@@ -630,7 +697,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 	name = "smoking pipe"
 	desc = "A pipe, for smoking. Probably made of meerschaum or something."
 	icon_state = "pipeoff"
-	icon_on = "pipeon"  //Note - these are in masks.dmi
+	icon_on = "pipeoff"  //Note - these are in masks.dmi
 	icon_off = "pipeoff"
 	inhand_icon_state = null
 	inhand_icon_on = null
@@ -645,7 +712,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 
 /obj/item/clothing/mask/cigarette/pipe/Initialize(mapload)
 	. = ..()
-	update_name()
+	update_appearance(UPDATE_NAME)
 
 /obj/item/clothing/mask/cigarette/pipe/update_name()
 	. = ..()
@@ -660,11 +727,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 		if(user)
 			to_chat(user, span_notice("Your [name] goes out."))
 		packeditem = null
-	update_icon()
-
-	inhand_icon_state = icon_off
-	user?.update_worn_mask()
+	update_appearance(UPDATE_ICON)
 	STOP_PROCESSING(SSobj, src)
+	QDEL_NULL(cig_smoke)
 
 /obj/item/clothing/mask/cigarette/pipe/attackby(obj/item/thing, mob/user, params)
 	if(!istype(thing, /obj/item/food/grown))
@@ -703,7 +768,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
 	name = "corn cob pipe"
 	desc = "A nicotine delivery system popularized by folksy backwoodsmen and kept popular in the modern age and beyond by space hipsters. Can be loaded with objects."
 	icon_state = "cobpipeoff"
-	icon_on = "cobpipeon"  //Note - these are in masks.dmi
+	icon_on = "cobpipeoff"  //Note - these are in masks.dmi
 	icon_off = "cobpipeoff"
 	inhand_icon_on = null
 	inhand_icon_off = null
diff --git a/code/game/objects/items/stacks/tickets.dm b/code/game/objects/items/stacks/tickets.dm
index 20e6843b9770..d1bd7681b8a8 100644
--- a/code/game/objects/items/stacks/tickets.dm
+++ b/code/game/objects/items/stacks/tickets.dm
@@ -8,14 +8,9 @@
 	max_amount = 30
 	merge_type = /obj/item/stack/arcadeticket
 
-/obj/item/stack/arcadeticket/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1)
-	. = ..()
-	update_appearance()
-
 /obj/item/stack/arcadeticket/update_icon_state()
 	. = ..()
-	var/amount = get_amount()
-	switch(amount)
+	switch(get_amount())
 		if(12 to INFINITY)
 			icon_state = "arcade-ticket_4"
 		if(6 to 12)
@@ -25,10 +20,5 @@
 		else
 			icon_state = "arcade-ticket"
 
-/obj/item/stack/arcadeticket/proc/pay_tickets()
-	amount -= 2
-	if (amount == 0)
-		qdel(src)
-
 /obj/item/stack/arcadeticket/thirty
 	amount = 30
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index 439a2ce336e2..f6ace35c2ce7 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -163,10 +163,12 @@
 	if(!proximity)
 		return
 
-	if(isOn())
+	if(isOn() && ismovable(attacked_atom))
+		use(1)
+		var/turf/location = get_turf(user)
+		location.hotspot_expose(700, 50, 1)
 		. |= AFTERATTACK_PROCESSED_ITEM
 		if (!QDELETED(attacked_atom) && isliving(attacked_atom)) // can't ignite something that doesn't exist
-			handle_fuel_and_temps(1, user)
 			var/mob/living/attacked_mob = attacked_atom
 			if(attacked_mob.ignite_mob())
 				message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(attacked_mob)] on fire with [src] at [AREACOORD(user)]")
@@ -180,21 +182,6 @@
 
 	return .
 
-/obj/item/weldingtool/attack_qdeleted(atom/attacked_atom, mob/user, proximity)
-	. = ..()
-	if(!proximity)
-		return
-
-	if(isOn())
-		handle_fuel_and_temps(1, user)
-
-		if(!QDELETED(attacked_atom) && isliving(attacked_atom)) // can't ignite something that doesn't exist
-			var/mob/living/attacked_mob = attacked_atom
-			if(attacked_mob.ignite_mob())
-				message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(attacked_mob)] on fire with [src] at [AREACOORD(user)].")
-				user.log_message("set [key_name(attacked_mob)] on fire with [src]", LOG_ATTACK)
-
-
 /obj/item/weldingtool/attack_self(mob/user)
 	if(src.reagents.has_reagent(/datum/reagent/toxin/plasma))
 		message_admins("[ADMIN_LOOKUPFLW(user)] activated a rigged welder at [AREACOORD(user)].")
@@ -204,11 +191,6 @@
 
 	update_appearance()
 
-/obj/item/weldingtool/proc/handle_fuel_and_temps(used = 0, mob/living/user)
-	use(used)
-	var/turf/location = get_turf(user)
-	location.hotspot_expose(700, 50, 1)
-
 /// Returns the amount of fuel in the welder
 /obj/item/weldingtool/proc/get_fuel()
 	return reagents.get_reagent_amount(/datum/reagent/fuel)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
index d10d767f0ccc..ca931d4c6ab1 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm
@@ -31,7 +31,7 @@
 	for(var/i in 1 to 5)
 		new /obj/item/reagent_containers/cup/glass/colocup(src)
 
-/obj/structure/closet/secure/closet/bar/lavaland_bartender_clothes
+/obj/structure/closet/secure_closet/bar/lavaland_bartender_clothes
 	name = "bartender's closet"
 
 /obj/structure/closet/secure_closet/bar/lavaland_bartender_clothes/PopulateContents()
@@ -39,4 +39,3 @@
 	new /obj/item/clothing/glasses/sunglasses/reagent(src)
 	new /obj/item/clothing/suit/costume/hawaiian(src)
 	new /obj/item/clothing/shoes/sandal/beach(src)
-
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index 18a3e15c9871..3e45232fbaea 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -45,6 +45,8 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
 	var/locked = FALSE
 	///Cooldown between breakout msesages.
 	COOLDOWN_DECLARE(breakout_message_cooldown)
+	/// Cooldown between being able to slide the tray in or out.
+	COOLDOWN_DECLARE(open_close_cd)
 
 /obj/structure/bodycontainer/Initialize(mapload)
 	. = ..()
@@ -133,30 +135,90 @@ GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants an
 		user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 2)
 
 /obj/structure/bodycontainer/proc/open()
-	playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
+	if(!COOLDOWN_FINISHED(src, open_close_cd))
+		return FALSE
+
+	COOLDOWN_START(src, open_close_cd, 0.25 SECONDS)
+	playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
 	playsound(src, 'sound/effects/roll.ogg', 5, TRUE)
-	var/turf/T = get_step(src, dir)
-	if (connected)
-		connected.setDir(dir)
-	for(var/atom/movable/AM in src)
-		AM.forceMove(T)
+	var/turf/dump_turf = get_step(src, dir)
+	connected?.setDir(dir)
+	for(var/atom/movable/moving in src)
+		moving.forceMove(dump_turf)
+		animate_slide_out(moving)
 	update_appearance()
+	return TRUE
 
 /obj/structure/bodycontainer/proc/close()
+	if(!COOLDOWN_FINISHED(src, open_close_cd))
+		return FALSE
+
+	COOLDOWN_START(src, open_close_cd, 0.5 SECONDS)
 	playsound(src, 'sound/effects/roll.ogg', 5, TRUE)
 	playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
-	for(var/atom/movable/AM in connected.loc)
-		if(!AM.anchored || AM == connected)
-			if(isliving(AM))
-				var/mob/living/living_mob = AM
-				if(living_mob.incorporeal_move)
-					continue
-			else if(istype(AM, /obj/effect/dummy/phased_mob))
+	var/turf/close_loc = connected.loc
+	for(var/atom/movable/entering in close_loc)
+		if(entering.anchored && entering != connected)
+			continue
+		if(isliving(entering))
+			var/mob/living/living_mob = entering
+			if(living_mob.incorporeal_move)
 				continue
-			else if(isdead(AM))
-				continue
-			AM.forceMove(src)
+		else if(istype(entering, /obj/effect/dummy/phased_mob) || isdead(entering))
+			continue
+		animate_slide_in(entering, close_loc)
+		entering.forceMove(src)
 	update_appearance()
+	return TRUE
+
+#define SLIDE_LENGTH (0.3 SECONDS)
+
+/// Slides the passed object out of the morgue tray.
+/obj/structure/bodycontainer/proc/animate_slide_out(atom/movable/animated)
+	var/old_layer = animated.layer
+	animated.layer = layer - (animated == connected ? 0.03 : 0.01)
+	animated.pixel_x = animated.base_pixel_x + (x * 32) - (animated.x * 32)
+	animated.pixel_y = animated.base_pixel_y + (y * 32) - (animated.y * 32)
+	animate(
+		animated,
+		pixel_x = animated.base_pixel_x,
+		pixel_y = animated.base_pixel_y,
+		time = SLIDE_LENGTH,
+		easing = CUBIC_EASING|EASE_OUT,
+		flags = ANIMATION_PARALLEL,
+	)
+	addtimer(VARSET_CALLBACK(animated, layer, old_layer), SLIDE_LENGTH)
+
+/// Slides the passed object into the morgue tray from the passed turf.
+/obj/structure/bodycontainer/proc/animate_slide_in(atom/movable/animated, turf/from_loc)
+	// It's easier to just make a visual for entering than to animate the object itself
+	var/obj/effect/temp_visual/morgue_content/visual = new(from_loc, animated)
+	visual.layer = layer - (animated == connected ? 0.03 : 0.01)
+	animate(
+		visual,
+		pixel_x = visual.base_pixel_x + (x * 32) - (visual.x * 32),
+		pixel_y = visual.base_pixel_y + (y * 32) - (visual.y * 32),
+		time = SLIDE_LENGTH,
+		easing = CUBIC_EASING|EASE_IN,
+		flags = ANIMATION_PARALLEL,
+	)
+
+/// Used to mimic the appearance of an object sliding into a morgue tray.
+/obj/effect/temp_visual/morgue_content
+	duration = SLIDE_LENGTH
+
+/obj/effect/temp_visual/morgue_content/Initialize(mapload, atom/movable/sliding_in)
+	. = ..()
+	if(isnull(sliding_in))
+		return
+
+	appearance = sliding_in.appearance
+	dir = sliding_in.dir
+	alpha = sliding_in.alpha
+	base_pixel_x = sliding_in.base_pixel_x
+	base_pixel_y = sliding_in.base_pixel_y
+
+#undef SLIDE_LENGTH
 
 #define MORGUE_EMPTY 1
 #define MORGUE_NO_MOBS 2
@@ -536,6 +598,7 @@ GLOBAL_LIST_EMPTY(crematoriums)
 	name = "crematorium tray"
 	desc = "Apply body before burning."
 	icon_state = "cremat"
+	layer = /obj/structure/bodycontainer/crematorium::layer - 0.03
 
 /*
  * Morgue tray
@@ -546,6 +609,7 @@ GLOBAL_LIST_EMPTY(crematoriums)
 	icon = 'icons/obj/structures.dmi'
 	icon_state = "morguet"
 	pass_flags_self = PASSTABLE | LETPASSTHROW
+	layer = /obj/structure/bodycontainer/morgue::layer - 0.03
 
 /obj/structure/tray/m_tray/CanAllowThrough(atom/movable/mover, border_dir)
 	. = ..()
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index ad9695434169..52e694d4aa44 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -715,7 +715,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw
 
 /obj/structure/window/reinforced/fulltile
 	name = "full tile reinforced window"
-	desc = "A full tile reinforced window"
+	desc = "A full tile window that is reinforced with metal rods."
 	icon = 'icons/obj/smooth_structures/reinforced_window.dmi'
 	icon_state = "reinforced_window-0"
 	base_icon_state = "reinforced_window"
diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm
index 1a174723d85b..1ea32b0d0a4c 100644
--- a/code/game/turfs/open/lava.dm
+++ b/code/game/turfs/open/lava.dm
@@ -52,7 +52,8 @@
 
 /turf/open/lava/Destroy()
 	for(var/mob/living/leaving_mob in contents)
-		REMOVE_TRAIT(leaving_mob, TRAIT_PERMANENTLY_ONFIRE, TURF_TRAIT)
+		leaving_mob.RemoveElement(/datum/element/perma_fire_overlay)
+		REMOVE_TRAIT(leaving_mob, TRAIT_NO_EXTINGUISH, TURF_TRAIT)
 	return ..()
 
 /turf/open/lava/update_overlays()
@@ -144,7 +145,8 @@
 /turf/open/lava/Exited(atom/movable/gone, direction)
 	. = ..()
 	if(isliving(gone) && !islava(gone.loc))
-		REMOVE_TRAIT(gone, TRAIT_PERMANENTLY_ONFIRE, TURF_TRAIT)
+		gone.RemoveElement(/datum/element/perma_fire_overlay)
+		REMOVE_TRAIT(gone, TRAIT_NO_EXTINGUISH, TURF_TRAIT)
 
 /turf/open/lava/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
 	if(burn_stuff(AM))
@@ -296,7 +298,7 @@
 	if(isobj(burn_target))
 		var/obj/burn_obj = burn_target
 		if(burn_obj.resistance_flags & ON_FIRE) // already on fire; skip it.
-			return
+			return TRUE
 		if(!(burn_obj.resistance_flags & FLAMMABLE))
 			burn_obj.resistance_flags |= FLAMMABLE //Even fireproof things burn up in lava
 		if(burn_obj.resistance_flags & FIRE_PROOF)
@@ -305,17 +307,21 @@
 			burn_obj.set_armor_rating(FIRE, 50)
 		burn_obj.fire_act(temperature_damage, 1000 * seconds_per_tick)
 		if(istype(burn_obj, /obj/structure/closet))
-			var/obj/structure/closet/burn_closet = burn_obj
-			for(var/burn_content in burn_closet.contents)
+			for(var/burn_content in burn_target)
 				burn_stuff(burn_content)
-		return
+		return TRUE
 
-	var/mob/living/burn_living = burn_target
-	ADD_TRAIT(burn_living, TRAIT_PERMANENTLY_ONFIRE, TURF_TRAIT)
-	burn_living.ignite_mob()
-	burn_living.adjust_fire_stacks(lava_firestacks * seconds_per_tick)
-	burn_living.update_fire()
-	burn_living.adjustFireLoss(lava_damage * seconds_per_tick)
+	if(isliving(burn_target))
+		var/mob/living/burn_living = burn_target
+		if(!HAS_TRAIT_FROM(burn_living, TRAIT_NO_EXTINGUISH, TURF_TRAIT))
+			burn_living.AddElement(/datum/element/perma_fire_overlay)
+			ADD_TRAIT(burn_living, TRAIT_NO_EXTINGUISH, TURF_TRAIT)
+		burn_living.adjust_fire_stacks(lava_firestacks * seconds_per_tick)
+		burn_living.ignite_mob()
+		burn_living.adjustFireLoss(lava_damage * seconds_per_tick)
+		return TRUE
+
+	return FALSE
 
 /turf/open/lava/can_cross_safely(atom/movable/crossing)
 	return HAS_TRAIT(src, TRAIT_LAVA_STOPPED) || HAS_TRAIT(crossing, immunity_trait ) || HAS_TRAIT(crossing, TRAIT_MOVE_FLYING)
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 67271e7f0731..d158a53effa4 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -1174,8 +1174,7 @@ GLOBAL_PROTECT(admin_verbs_poll)
 
 	var/desired_mob = text2path(attempted_target_path)
 	if(!ispath(desired_mob))
-		var/static/list/mob_paths = make_types_fancy(subtypesof(/mob/living))
-		desired_mob = pick_closest_path(attempted_target_path, mob_paths)
+		desired_mob = pick_closest_path(attempted_target_path, make_types_fancy(subtypesof(/mob/living)))
 	if(isnull(desired_mob) || !ispath(desired_mob) || QDELETED(head))
 		return //The user pressed "Cancel"
 
diff --git a/code/modules/antagonists/nightmare/nightmare_species.dm b/code/modules/antagonists/nightmare/nightmare_species.dm
index 068bb2b6c5c1..38db2dfae865 100644
--- a/code/modules/antagonists/nightmare/nightmare_species.dm
+++ b/code/modules/antagonists/nightmare/nightmare_species.dm
@@ -39,7 +39,6 @@
 	. = ..()
 
 	C.fully_replace_character_name(null, pick(GLOB.nightmare_names))
-	C.set_safe_hunger_level()
 
 /datum/species/shadow/nightmare/check_roundstart_eligible()
 	return FALSE
diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm
index 237ebfdbabdd..a0c32b76977f 100644
--- a/code/modules/clothing/gloves/_gloves.dm
+++ b/code/modules/clothing/gloves/_gloves.dm
@@ -16,6 +16,7 @@
 	attack_verb_simple = list("challenge")
 	strip_delay = 20
 	equip_delay_other = 40
+	article = "a pair of"
 	blood_overlay_type = "glove" // NON-MODULE CHANGE
 	// Path variable. If defined, will produced the type through interaction with wirecutters.
 	var/cut_type = null
diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm
index 6dc4f119cbf0..009c29e12eb3 100644
--- a/code/modules/clothing/shoes/_shoes.dm
+++ b/code/modules/clothing/shoes/_shoes.dm
@@ -12,6 +12,7 @@
 	armor_type = /datum/armor/clothing_shoes
 	slowdown = SHOES_SLOWDOWN
 	strip_delay = 1 SECONDS
+	article = "a pair of"
 
 	blood_overlay_type = "shoe" // NON-MODULE CHANGE reworking clothing blood overlays
 
diff --git a/code/modules/food_and_drinks/machinery/stove_component.dm b/code/modules/food_and_drinks/machinery/stove_component.dm
index 697e27f58490..c9c710642236 100644
--- a/code/modules/food_and_drinks/machinery/stove_component.dm
+++ b/code/modules/food_and_drinks/machinery/stove_component.dm
@@ -249,7 +249,7 @@
 				return
 			// this gets badly murdered by sidemap
 			soup_smoke = new(parent, particle_type)
-			soup_smoke.set_particle_position(list(container_x, round(world.icon_size * 0.66), 0))
+			soup_smoke.set_particle_position(container_x, round(world.icon_size * 0.66), 0)
 		return
 
 	QDEL_NULL(soup_smoke)
diff --git a/code/modules/forensics/_forensics.dm b/code/modules/forensics/_forensics.dm
index 75cbc55df280..77ae7c2b3861 100644
--- a/code/modules/forensics/_forensics.dm
+++ b/code/modules/forensics/_forensics.dm
@@ -8,8 +8,8 @@
  * * List of clothing fibers on the atom
  */
 /datum/forensics
-	/// Weakref to the parent owning this datum
-	var/datum/weakref/parent
+	/// Ref to the parent owning this datum
+	var/atom/parent
 	/**
 	 * List of fingerprints on this atom
 	 *
@@ -39,15 +39,20 @@
 	 */
 	var/list/fibers
 
-/datum/forensics/New(atom/parent, fingerprints, hiddenprints, blood_DNA, fibers)
+/datum/forensics/New(atom/parent, list/fingerprints, list/hiddenprints, list/blood_DNA, list/fibers)
 	if(!isatom(parent))
 		stack_trace("We tried adding a forensics datum to something that isnt an atom. What the hell are you doing?")
 		qdel(src)
 		return
 
+	if(QDELING(parent))
+		stack_trace("Adding a forensics datum to a qdeling atom ([parent])")
+		qdel(src)
+		return
+
 	RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(clean_act))
 
-	src.parent = WEAKREF(parent)
+	src.parent = parent
 	src.fingerprints = fingerprints
 	src.hiddenprints = hiddenprints
 	src.blood_DNA = blood_DNA
@@ -67,9 +72,7 @@
 	check_blood()
 
 /datum/forensics/Destroy(force)
-	var/atom/parent_atom = parent.resolve()
-	if (!isnull(parent_atom))
-		UnregisterSignal(parent_atom, list(COMSIG_COMPONENT_CLEAN_ACT))
+	UnregisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT)
 	return ..()
 
 /// Empties the fingerprints list
@@ -147,8 +150,7 @@
 /// Adds a single fiber
 /datum/forensics/proc/add_fibers(mob/living/carbon/human/suspect)
 	var/fibertext
-	var/atom/actual_parent = parent.resolve()
-	var/item_multiplier = isitem(actual_parent) ? ITEM_FIBER_MULTIPLIER : NON_ITEM_FIBER_MULTIPLIER
+	var/item_multiplier = isitem(parent) ? ITEM_FIBER_MULTIPLIER : NON_ITEM_FIBER_MULTIPLIER
 	if(suspect.wear_suit)
 		fibertext = "Material from \a [suspect.wear_suit]."
 		if(prob(10 * item_multiplier) && !LAZYACCESS(fibers, fibertext))
@@ -214,8 +216,7 @@
 		if(last_stamp_pos)
 			LAZYSET(hiddenprints, suspect.key, copytext(hiddenprints[suspect.key], 1, last_stamp_pos))
 		hiddenprints[suspect.key] += "\nLast: \[[current_time]\] \"[suspect.real_name]\"[has_gloves]. Ckey: [suspect.ckey]" //made sure to be existing by if(!LAZYACCESS);else
-	var/atom/parent_atom = parent.resolve()
-	parent_atom.fingerprintslast = suspect.ckey
+	parent.fingerprintslast = suspect.ckey
 	return TRUE
 
 /// Adds the given list into blood_DNA
@@ -230,11 +231,8 @@
 
 /// Updates the blood displayed on parent
 /datum/forensics/proc/check_blood()
-	if(!parent || !isitem(parent.resolve()))
-		return
-	if(isorgan(parent.resolve())) // organs don't spawn with blood decals by default
+	if(!isitem(parent) || isorgan(parent)) // organs don't spawn with blood decals by default
 		return
 	if(!length(blood_DNA))
 		return
-	var/atom/parent_atom = parent.resolve()
-	parent_atom.AddElement(/datum/element/decal/blood)
+	parent.AddElement(/datum/element/decal/blood)
diff --git a/code/modules/forensics/forensics_helpers.dm b/code/modules/forensics/forensics_helpers.dm
index 72dc89c6a4ac..e7d71a037f1e 100644
--- a/code/modules/forensics/forensics_helpers.dm
+++ b/code/modules/forensics/forensics_helpers.dm
@@ -1,5 +1,7 @@
 /// Adds a list of fingerprints to the atom
 /atom/proc/add_fingerprint_list(list/fingerprints_to_add) //ASSOC LIST FINGERPRINT = FINGERPRINT
+	if (QDELING(src))
+		return FALSE
 	if (isnull(fingerprints_to_add))
 		return
 	if (forensics)
@@ -19,6 +21,8 @@
 
 /// Add a list of fibers to the atom
 /atom/proc/add_fiber_list(list/fibers_to_add) //ASSOC LIST FIBERTEXT = FIBERTEXT
+	if (QDELING(src))
+		return FALSE
 	if (isnull(fibers_to_add))
 		return
 	if (forensics)
@@ -29,6 +33,8 @@
 
 /// Adds a single fiber to the atom
 /atom/proc/add_fibers(mob/living/carbon/human/suspect)
+	if (QDELING(src))
+		return FALSE
 	var/old = 0
 	if(suspect.gloves && istype(suspect.gloves, /obj/item/clothing))
 		var/obj/item/clothing/gloves/suspect_gloves = suspect.gloves
@@ -47,6 +53,8 @@
 
 /// Adds a list of hiddenprints to the atom
 /atom/proc/add_hiddenprint_list(list/hiddenprints_to_add) //NOTE: THIS IS FOR ADMINISTRATION FINGERPRINTS, YOU MUST CUSTOM SET THIS TO INCLUDE CKEY/REAL NAMES! CHECK FORENSICS.DM
+	if (QDELING(src))
+		return FALSE
 	if (isnull(hiddenprints_to_add))
 		return
 	if (forensics)
@@ -57,6 +65,8 @@
 
 /// Adds a single hiddenprint to the atom
 /atom/proc/add_hiddenprint(mob/suspect)
+	if (QDELING(src))
+		return FALSE
 	if (isnull(forensics))
 		forensics = new(src)
 	forensics.add_hiddenprint(suspect)
@@ -92,6 +102,8 @@
 	return FALSE
 
 /obj/add_blood_DNA(list/blood_DNA_to_add)
+	if (QDELING(src))
+		return FALSE
 	if (isnull(blood_DNA_to_add))
 		return FALSE
 	if (forensics)
@@ -139,6 +151,8 @@
 	return FALSE
 
 /mob/living/carbon/human/add_blood_DNA(list/blood_DNA_to_add, list/datum/disease/diseases)
+	if(QDELING(src))
+		return FALSE
 	if(wear_suit)
 		wear_suit.add_blood_DNA(blood_DNA_to_add)
 		update_worn_oversuit()
diff --git a/code/modules/hallucination/fake_alert.dm b/code/modules/hallucination/fake_alert.dm
index 537f6e294909..6e10daf73aa9 100644
--- a/code/modules/hallucination/fake_alert.dm
+++ b/code/modules/hallucination/fake_alert.dm
@@ -63,10 +63,6 @@
 	alert_category = ALERT_TOO_MUCH_CO2
 	alert_type = /atom/movable/screen/alert/too_much_co2
 
-/datum/hallucination/fake_alert/nutrition
-	alert_category = ALERT_NUTRITION
-	alert_type = list(/atom/movable/screen/alert/fat, /atom/movable/screen/alert/starving)
-
 /datum/hallucination/fake_alert/gravity
 	alert_category = ALERT_GRAVITY
 	alert_type = /atom/movable/screen/alert/weightless
diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm
index 6a5d1b1d5c4e..d1f58f2e3ce0 100644
--- a/code/modules/library/bibles.dm
+++ b/code/modules/library/bibles.dm
@@ -88,7 +88,6 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
 		active_slots = ITEM_SLOT_SUITSTORE,\
 		on_intercepted = CALLBACK(src, PROC_REF(on_intercepted_bullet)),\
 	)
-	carve_out()
 
 /obj/item/book/bible/Destroy(force)
 	QDEL_NULL(bullet_catcher)
@@ -345,6 +344,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
 
 /obj/item/book/bible/booze/Initialize(mapload)
 	. = ..()
+	carve_out()
 	new /obj/item/reagent_containers/cup/glass/bottle/whiskey(src)
 
 /obj/item/book/bible/syndicate
diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm
index 7676801a0a92..e0b8c322a748 100644
--- a/code/modules/mapping/mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers.dm
@@ -856,6 +856,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
 	var/list/blacklisted_from_rng_placement = list(
 		SPECIES_ETHEREAL, // they revive on death which is bad juju
 		SPECIES_HUMAN,  // already have a 50% chance of being selected
+		SPECIES_LIZARD_SILVER, // NON-MODULE CHANGE - Nope
 	)
 
 /obj/effect/mapping_helpers/dead_body_placer/Initialize(mapload)
diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm
index 8d7db7f8e850..615eb55898c9 100644
--- a/code/modules/mob/dead/dead.dm
+++ b/code/modules/mob/dead/dead.dm
@@ -14,7 +14,6 @@ INITIALIZE_IMMEDIATE(/mob/dead)
 	flags_1 |= INITIALIZED_1
 	// Initial is non standard here, but ghosts move before they get here so it's needed. this is a cold path too so it's ok
 	SET_PLANE_IMPLICIT(src, initial(plane))
-	tag = "mob_[next_mob_id++]"
 	add_to_mob_list()
 
 	prepare_huds()
diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm
index ba07c944652e..d69665d6bcde 100644
--- a/code/modules/mob/living/basic/basic.dm
+++ b/code/modules/mob/living/basic/basic.dm
@@ -270,17 +270,17 @@
 /mob/living/basic/on_fire_stack(seconds_per_tick, datum/status_effect/fire_handler/fire_stacks/fire_handler)
 	adjust_bodytemperature((maximum_survivable_temperature + (fire_handler.stacks * 12)) * 0.5 * seconds_per_tick)
 
-/mob/living/basic/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
-	var/mutable_appearance/fire_overlay = mutable_appearance('icons/mob/effects/onfire.dmi', "generic_fire")
-	if(on_fire && isnull(last_icon_state))
-		add_overlay(fire_overlay)
-		return fire_overlay
-	else if(!on_fire && !isnull(last_icon_state))
-		cut_overlay(fire_overlay)
-		return null
-	else if(on_fire && !isnull(last_icon_state))
-		return last_icon_state
-	return null
+/mob/living/basic/get_fire_overlay(stacks, on_fire)
+	var/fire_icon = "generic_fire"
+	if(!GLOB.fire_appearances[fire_icon])
+		GLOB.fire_appearances[fire_icon] = mutable_appearance(
+			'icons/mob/effects/onfire.dmi',
+			fire_icon,
+			-HIGHEST_LAYER,
+			appearance_flags = RESET_COLOR,
+		)
+
+	return GLOB.fire_appearances[fire_icon]
 
 /mob/living/basic/put_in_hands(obj/item/I, del_on_fail = FALSE, merge_stacks = TRUE, ignore_animation = TRUE)
 	. = ..()
diff --git a/code/modules/mob/living/basic/bots/bot_ai.dm b/code/modules/mob/living/basic/bots/bot_ai.dm
index ca6a61931889..5e53977c4a22 100644
--- a/code/modules/mob/living/basic/bots/bot_ai.dm
+++ b/code/modules/mob/living/basic/bots/bot_ai.dm
@@ -2,9 +2,7 @@
 	blackboard = list(
 		BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
 		BB_SALUTE_MESSAGES = list(
-			"salutes",
-			"nods in appreciation towards",
-			"fist bumps",
+			"performs an elaborate salute for",
 		)
 	)
 
@@ -213,17 +211,13 @@
 
 /datum/ai_behavior/find_and_set/valid_authority
 	behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
-	action_cooldown = 30 SECONDS
+	action_cooldown = BOT_COMMISSIONED_SALUTE_DELAY
 
 /datum/ai_behavior/find_and_set/valid_authority/search_tactic(datum/ai_controller/controller, locate_path, search_range)
-	for(var/mob/living/robot in oview(search_range, controller.pawn))
-		if(istype(robot, /mob/living/simple_animal/bot/secbot))
+	for(var/mob/living/basic/bot/cleanbot/robot in oview(search_range, controller.pawn))
+		// NON-MODULE CHANGE - reverts basic bots to only salute commissioned cleanbots, not beepsky
+		if(robot.comissioned)
 			return robot
-		if(!istype(robot, /mob/living/basic/bot/cleanbot))
-			continue
-		var/mob/living/basic/bot/cleanbot/potential_bot = robot
-		if(potential_bot.comissioned)
-			return potential_bot
 	return null
 
 /datum/ai_behavior/salute_authority
@@ -243,7 +237,7 @@
 	if(our_hat)
 		salute_list += "tips [our_hat] at "
 
-	bot_pawn.manual_emote(pick(salute_list) + " [controller.blackboard[target_key]]")
+	bot_pawn.manual_emote(pick(salute_list) + " [controller.blackboard[target_key]]!")
 	finish_action(controller, TRUE, target_key)
 	return
 
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 2bc1ef8d245c..1a84a3ebcd7c 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -398,6 +398,9 @@
 	if((HAS_TRAIT(src, TRAIT_NOHUNGER) || HAS_TRAIT(src, TRAIT_TOXINLOVER)) && !force)
 		return TRUE
 
+	if(!force && HAS_TRAIT(src, TRAIT_STRONG_STOMACH))
+		lost_nutrition *= 0.5
+
 	SEND_SIGNAL(src, COMSIG_CARBON_VOMITED, distance, force)
 
 	// cache some stuff that we'll need later (at least multiple times)
@@ -414,7 +417,10 @@
 				span_userdanger("You try to throw up, but there's nothing in your stomach!"),
 			)
 		if(stun)
-			Stun(20 SECONDS)
+			var/stun_time = 20 SECONDS
+			if(HAS_TRAIT(src, TRAIT_STRONG_STOMACH))
+				stun_time *= 0.5
+			Stun(stun_time)
 		if(knockdown)
 			Knockdown(20 SECONDS)
 		return TRUE
@@ -437,11 +443,14 @@
 				add_mood_event("vomit", /datum/mood_event/vomit)
 
 	if(stun)
-		Stun(8 SECONDS)
+		var/stun_time = 8 SECONDS
+		if(!blood && HAS_TRAIT(src, TRAIT_STRONG_STOMACH))
+			stun_time *= 0.5
+		Stun(stun_time)
 	if(knockdown)
 		Knockdown(8 SECONDS)
 
-	playsound(get_turf(src), 'sound/effects/splat.ogg', 50, TRUE)
+	playsound(src, 'sound/effects/splat.ogg', 50, TRUE)
 
 	var/need_mob_update = FALSE
 	var/turf/location = get_turf(src)
@@ -802,8 +811,7 @@
 			hud_used.stamina.icon_state = "stamina_full"
 
 /mob/living/carbon/proc/update_spacesuit_hud_icon(cell_state = "empty")
-	if(hud_used?.spacesuit)
-		hud_used.spacesuit.icon_state = "spacesuit_[cell_state]"
+	hud_used?.spacesuit?.icon_state = "spacesuit_[cell_state]"
 
 /mob/living/carbon/set_health(new_value)
 	. = ..()
@@ -883,7 +891,11 @@
 	if(!HAS_TRAIT(src, TRAIT_LIVERLESS_METABOLISM) && !isnull(dna?.species.mutantliver) && !get_organ_slot(ORGAN_SLOT_LIVER))
 		return FALSE
 
-	return ..()
+	. = ..()
+	if(.) // if revived successfully
+		set_heartattack(FALSE)
+
+	return .
 
 /mob/living/carbon/fully_heal(heal_flags = HEAL_ALL)
 
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 01d45b0686dd..89183f095f45 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -618,7 +618,7 @@
 
 /obj/item/hand_item/self_grasp/Destroy()
 	if(user)
-		to_chat(user, span_warning("You stop holding onto your[grasped_part ? " [grasped_part.name]" : "self"]."))
+		to_chat(user, span_warning("You stop holding onto your[grasped_part ? " [grasped_part.plaintext_zone]" : "self"]."))
 		UnregisterSignal(user, COMSIG_QDELETING)
 	if(grasped_part)
 		UnregisterSignal(grasped_part, list(COMSIG_CARBON_REMOVE_LIMB, COMSIG_QDELETING))
@@ -649,7 +649,7 @@
 
 	var/bleed_rate = grasped_part.get_modified_bleed_rate()
 	var/bleeding_text = (bleed_rate ? ", trying to stop the bleeding" : "")
-	user.visible_message(span_danger("[user] grasps at [user.p_their()] [grasped_part.name][bleeding_text]."), span_notice("You grab hold of your [grasped_part.name] tightly."), vision_distance=COMBAT_MESSAGE_RANGE)
+	user.visible_message(span_danger("[user] grasps at [user.p_their()] [grasped_part.plaintext_zone][bleeding_text]."), span_notice("You grab hold of your [grasped_part.plaintext_zone] tightly."), vision_distance=COMBAT_MESSAGE_RANGE)
 	playsound(get_turf(src), 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
 	return TRUE
 
diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm
index 6f82be475e70..1a5b79bd86ab 100644
--- a/code/modules/mob/living/carbon/carbon_movement.dm
+++ b/code/modules/mob/living/carbon/carbon_movement.dm
@@ -8,27 +8,30 @@
 
 /mob/living/carbon/Move(NewLoc, direct)
 	. = ..()
-	if(. && !(movement_type & FLOATING)) //floating is easy
-		if(HAS_TRAIT(src, TRAIT_NOHUNGER))
-			set_nutrition(NUTRITION_LEVEL_FED - 1) //just less than feeling vigorous
-		else if(nutrition && stat != DEAD)
-			adjust_nutrition(-(HUNGER_FACTOR/10))
-			if(move_intent == MOVE_INTENT_RUN)
-				adjust_nutrition(-(HUNGER_FACTOR/10))
+	if(!. || (movement_type & FLOATING)) //floating is easy
+		return
+	if(stat == DEAD)
+		return
 
-		// NON-MODULE CHANGE START
-		if(move_intent == MOVE_INTENT_RUN && !(movement_type & FLYING) && (mobility_flags & (MOBILITY_MOVE|MOBILITY_STAND)) && !pulledby)
-			drain_sprint()
-		if(momentum_dir & direct)
-			momentum_distance++
-			if(!has_momentum && momentum_distance >= 4 && add_movespeed_modifier(/datum/movespeed_modifier/momentum))
-				has_momentum = TRUE
-		else
-			momentum_dir = direct
-			momentum_distance = 0
-			if(has_momentum && remove_movespeed_modifier(/datum/movespeed_modifier/momentum))
-				has_momentum = FALSE
-		// NON-MODULE CHANGE END
+	if(nutrition > 0)
+		var/hunger_loss = HUNGER_FACTOR / 10
+		if(move_intent == MOVE_INTENT_RUN)
+			hunger_loss *= 2
+		adjust_nutrition(-1 * hunger_loss)
+
+	// NON-MODULE CHANGE START
+	if(move_intent == MOVE_INTENT_RUN && !(movement_type & FLYING) && (mobility_flags & (MOBILITY_MOVE|MOBILITY_STAND)) && !pulledby)
+		drain_sprint()
+	if(momentum_dir & direct)
+		momentum_distance++
+		if(!has_momentum && momentum_distance >= 4 && add_movespeed_modifier(/datum/movespeed_modifier/momentum))
+			has_momentum = TRUE
+	else
+		momentum_dir = direct
+		momentum_distance = 0
+		if(has_momentum && remove_movespeed_modifier(/datum/movespeed_modifier/momentum))
+			has_momentum = FALSE
+	// NON-MODULE CHANGE END
 
 /mob/living/carbon/set_usable_legs(new_value)
 	. = ..()
diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm
index 08e734a01f40..cebeab7cfcd3 100644
--- a/code/modules/mob/living/carbon/carbon_update_icons.dm
+++ b/code/modules/mob/living/carbon/carbon_update_icons.dm
@@ -278,8 +278,8 @@
 	update_held_items()
 	update_worn_handcuffs()
 	update_worn_legcuffs()
-	update_fire()
 	update_body()
+	update_appearance(UPDATE_OVERLAYS)
 
 /mob/living/carbon/update_held_items()
 	. = ..()
@@ -315,27 +315,18 @@
 		hands += I.build_worn_icon(default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE)
 	return hands
 
-/mob/living/carbon/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
-	var/fire_icon = "[dna?.species.fire_overlay || "human"]_[stacks > MOB_BIG_FIRE_STACK_THRESHOLD ? "big_fire" : "small_fire"][suffix]"
+/mob/living/carbon/get_fire_overlay(stacks, on_fire)
+	var/fire_icon = "[dna?.species.fire_overlay || "human"]_[stacks > MOB_BIG_FIRE_STACK_THRESHOLD ? "big_fire" : "small_fire"]"
 
 	if(!GLOB.fire_appearances[fire_icon])
-		GLOB.fire_appearances[fire_icon] = mutable_appearance('icons/mob/effects/onfire.dmi', fire_icon, -FIRE_LAYER, appearance_flags = RESET_COLOR)
-
-	if((stacks > 0 && on_fire) || HAS_TRAIT(src, TRAIT_PERMANENTLY_ONFIRE))
-		if(fire_icon == last_icon_state)
-			return last_icon_state
-
-		remove_overlay(FIRE_LAYER)
-		overlays_standing[FIRE_LAYER] = GLOB.fire_appearances[fire_icon]
-		apply_overlay(FIRE_LAYER)
-		return fire_icon
-
-	if(!last_icon_state)
-		return last_icon_state
-
-	remove_overlay(FIRE_LAYER)
-	apply_overlay(FIRE_LAYER)
-	return null
+		GLOB.fire_appearances[fire_icon] = mutable_appearance(
+			'icons/mob/effects/onfire.dmi',
+			fire_icon,
+			-HIGHEST_LAYER,
+			appearance_flags = RESET_COLOR,
+		)
+
+	return GLOB.fire_appearances[fire_icon]
 
 /mob/living/carbon/update_damage_overlays()
 	remove_overlay(DAMAGE_LAYER)
diff --git a/code/modules/mob/living/carbon/emote.dm b/code/modules/mob/living/carbon/emote.dm
index 9ba533a33b5d..e01315094a11 100644
--- a/code/modules/mob/living/carbon/emote.dm
+++ b/code/modules/mob/living/carbon/emote.dm
@@ -160,7 +160,7 @@
 	key_third_person = "snaps"
 	message = "snaps their fingers."
 	message_param = "snaps their fingers at %t."
-	emote_type = EMOTE_AUDIBLE
+	emote_type = EMOTE_AUDIBLE | EMOTE_VISIBLE
 	hands_use_check = TRUE
 	muzzle_ignore = TRUE
 
diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm
index 273ba1e185d3..17cb76551066 100644
--- a/code/modules/mob/living/carbon/human/_species.dm
+++ b/code/modules/mob/living/carbon/human/_species.dm
@@ -32,8 +32,11 @@ GLOBAL_LIST_EMPTY(features_by_species)
 
 	///The maximum number of bodyparts this species can have.
 	var/max_bodypart_count = 6
-	///This allows races to have specific hair colors. If null, it uses the H's hair/facial hair colors. If "mutcolor", it uses the H's mutant_color. If "fixedmutcolor", it uses fixedmutcolor
-	var/hair_color
+	/// This allows races to have specific hair colors.
+	/// If null, it uses the mob's hair/facial hair colors.
+	/// If USE_MUTANT_COLOR, it uses the mob's mutant_color.
+	/// If USE_FIXED_MUTANT_COLOR, it uses fixedmutcolor
+	var/hair_color_mode
 	///The alpha used by the hair. 255 is completely solid, 0 is invisible.
 	var/hair_alpha = 255
 	///The alpha used by the facial hair. 255 is completely solid, 0 is invisible.
@@ -113,8 +116,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
 	var/siemens_coeff = 1
 	///To use MUTCOLOR with a fixed color that's independent of the mcolor feature in DNA.
 	var/fixed_mut_color = ""
-	///A fixed hair color that's independent of the mcolor feature in DNA.
-	var/fixed_hair_color = ""
 	///Special mutation that can be found in the genepool exclusively in this species. Dont leave empty or changing species will be a headache
 	var/inert_mutation = /datum/mutation/human/dwarfism
 	///Used to set the mob's death_sound upon species change
@@ -768,19 +769,11 @@ GLOBAL_LIST_EMPTY(features_by_species)
 				if(!forced_colour)
 					switch(accessory.color_src)
 						if(MUTANT_COLOR)
-							if(fixed_mut_color)
-								accessory_overlay.color = fixed_mut_color
-							else
-								accessory_overlay.color = source.dna.features["mcolor"]
+							accessory_overlay.color = fixed_mut_color || source.dna.features["mcolor"]
 						if(HAIR_COLOR)
-							if(hair_color == "mutcolor")
-								accessory_overlay.color = source.dna.features["mcolor"]
-							else if(hair_color == "fixedmutcolor")
-								accessory_overlay.color = fixed_hair_color
-							else
-								accessory_overlay.color = source.hair_color
+							accessory_overlay.color = get_fixed_hair_color(source) || source.hair_color
 						if(FACIAL_HAIR_COLOR)
-							accessory_overlay.color = source.facial_hair_color
+							accessory_overlay.color = get_fixed_hair_color(source) || source.facial_hair_color
 						if(EYE_COLOR)
 							accessory_overlay.color = source.eye_color_left
 				else
@@ -2181,3 +2174,21 @@ GLOBAL_LIST_EMPTY(features_by_species)
 		return
 	harddel_deets_dumped = TRUE
 	return "Gained / Owned: [properly_gained ? "Yes" : "No"]"
+
+/**
+ * Get what hair color is used by this species for a mob.
+ *
+ * Arguments
+ * * for_mob - The mob to get the hair color for. Required.
+ *
+ * Returns a color string or null.
+ */
+/datum/species/proc/get_fixed_hair_color(mob/living/carbon/human/for_mob)
+	ASSERT(!isnull(for_mob))
+	switch(hair_color_mode)
+		if(USE_MUTANT_COLOR)
+			return for_mob.dna.features["mcolor"]
+		if(USE_FIXED_MUTANT_COLOR)
+			return fixed_mut_color
+
+	return null
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 5e697f74b9c9..1325587a5e4b 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -58,8 +58,14 @@
 	if(gloves && !(obscured & ITEM_SLOT_GLOVES) && !(gloves.item_flags & EXAMINE_SKIP))
 		. += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands."
 	else if(GET_ATOM_BLOOD_DNA_LENGTH(src))
+		var/list/all_dna = GET_ATOM_BLOOD_DNA(src)
+		var/list/all_blood_names = list()
+		for(var/dna_sample in all_dna)
+			var/datum/blood_type/blood = GLOB.blood_types[all_dna[dna_sample]]
+			all_blood_names |= lowertext(initial(blood.reagent_type.name))
+
 		if(num_hands)
-			. += span_warning("[t_He] [t_has] [num_hands > 1 ? "" : "a"] blood-stained hand[num_hands > 1 ? "s" : ""]!")
+			. += span_warning("[t_He] [t_has] [num_hands > 1 ? "" : "a "][english_list(all_blood_names, nothing_text = "blood")] stained hand[num_hands > 1 ? "s" : ""]!")
 
 	//handcuffed?
 	if(handcuffed)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 167f059ed420..f0e5183c7b62 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -41,10 +41,11 @@
 /mob/living/carbon/human/proc/setup_mood()
 	if (CONFIG_GET(flag/disable_human_mood))
 		return
-	if (isdummy(src))
-		return
 	mob_mood = new /datum/mood(src)
 
+/mob/living/carbon/human/dummy/setup_mood()
+	return
+
 /// This proc is for holding effects applied when a mob is missing certain organs
 /// It is called very, very early in human init because all humans innately spawn with no organs and gain them during init
 /// Gaining said organs removes these effects
@@ -975,16 +976,6 @@
 		remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown)
 		remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying)
 
-/mob/living/carbon/human/adjust_nutrition(change) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
-	if(HAS_TRAIT(src, TRAIT_NOHUNGER))
-		return FALSE
-	return ..()
-
-/mob/living/carbon/human/set_nutrition(change) //Seriously fuck you oldcoders.
-	if(HAS_TRAIT(src, TRAIT_NOHUNGER))
-		return FALSE
-	return ..()
-
 /mob/living/carbon/human/get_exp_list(minutes)
 	. = ..()
 
diff --git a/code/modules/mob/living/carbon/human/init_signals.dm b/code/modules/mob/living/carbon/human/init_signals.dm
index 9a4a55bb7ac1..89cf7e01ce6f 100644
--- a/code/modules/mob/living/carbon/human/init_signals.dm
+++ b/code/modules/mob/living/carbon/human/init_signals.dm
@@ -5,6 +5,9 @@
 	RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_DWARF), SIGNAL_REMOVETRAIT(TRAIT_DWARF)), PROC_REF(on_dwarf_trait))
 	RegisterSignal(src, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, PROC_REF(get_name_part))
 
+	RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_FAT), SIGNAL_REMOVETRAIT(TRAIT_FAT)), PROC_REF(on_fat))
+	RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_NOHUNGER), SIGNAL_REMOVETRAIT(TRAIT_NOHUNGER)), PROC_REF(on_nohunger))
+
 /// Gaining or losing [TRAIT_UNKNOWN] updates our name and our sechud
 /mob/living/carbon/human/proc/on_unknown_trait(datum/source)
 	SIGNAL_HANDLER
@@ -38,3 +41,25 @@
 	if(name != voice_name)
 		voice_name += " (as [get_id_name("Unknown")])"
 	stored_name[NAME_PART_INDEX] = voice_name
+
+/mob/living/carbon/human/proc/on_fat(datum/source)
+	SIGNAL_HANDLER
+	hud_used?.hunger?.update_appearance()
+	mob_mood?.update_nutrition_moodlets()
+
+	if(HAS_TRAIT(src, TRAIT_FAT))
+		add_movespeed_modifier(/datum/movespeed_modifier/obesity)
+	else
+		remove_movespeed_modifier(/datum/movespeed_modifier/obesity)
+
+/mob/living/carbon/human/proc/on_nohunger(datum/source)
+	SIGNAL_HANDLER
+	// When gaining NOHUNGER, we restore nutrition to normal levels, since we no longer interact with the hunger system
+	if(HAS_TRAIT(src, TRAIT_NOHUNGER))
+		set_nutrition(NUTRITION_LEVEL_FED, forced = TRUE)
+		satiety = 0
+		overeatduration = 0
+		REMOVE_TRAIT(src, TRAIT_FAT, OBESITY)
+	else
+		hud_used?.hunger?.update_appearance()
+		mob_mood?.update_nutrition_moodlets()
diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm
index 74d2bedf3a70..67f1b3e66d2c 100644
--- a/code/modules/mob/living/carbon/human/species_types/abductors.dm
+++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm
@@ -40,8 +40,6 @@
 	var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
 	abductor_hud.show_to(C)
 
-	C.set_safe_hunger_level()
-
 /datum/species/abductor/on_species_loss(mob/living/carbon/C)
 	. = ..()
 	var/datum/atom_hud/abductor_hud = GLOB.huds[DATA_HUD_ABDUCTOR]
diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm
index 2c006d2e936b..b7a6c532106f 100644
--- a/code/modules/mob/living/carbon/human/species_types/android.dm
+++ b/code/modules/mob/living/carbon/human/species_types/android.dm
@@ -47,11 +47,6 @@
 		BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/robot/android,
 	)
 
-/datum/species/android/on_species_gain(mob/living/carbon/C)
-	. = ..()
-	// Androids don't eat, hunger or metabolise foods. Let's do some cleanup.
-	C.set_safe_hunger_level()
-
 /datum/species/android/get_physical_attributes()
 	return "Androids are almost, but not quite, identical to fully augmented humans. \
 	Unlike those, though, they're completely immune to toxin damage, don't have blood or organs (besides their head), don't get hungry, and can reattach their limbs! \
diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
index 1407ba80f755..1d7c328f8823 100644
--- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm
+++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm
@@ -58,7 +58,6 @@
 	eyes.bodypart_insert(my_head)
 	human.update_body()
 	head.update_icon_dropped()
-	human.set_safe_hunger_level()
 	RegisterSignal(head, COMSIG_QDELETING, PROC_REF(on_head_destroyed))
 
 /// If we gained a new body part, it had better not be a head
diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
index 5d911d293521..9fc68a635095 100644
--- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
@@ -25,7 +25,7 @@
 	bodytemp_heat_damage_limit = FIRE_MINIMUM_TEMPERATURE_TO_SPREAD // about 150C
 	// Cold temperatures hurt faster as it is harder to move with out the heat energy
 	bodytemp_cold_damage_limit = (T20C - 10) // about 10c
-	hair_color = "fixedmutcolor"
+	hair_color_mode = USE_FIXED_MUTANT_COLOR
 	hair_alpha = 140
 	facial_hair_alpha = 140
 
@@ -59,7 +59,6 @@
 	if(!ishuman(new_ethereal))
 		return
 	default_color = new_ethereal.dna.features["ethcolor"]
-	fixed_hair_color = default_color
 	r1 = GETREDPART(default_color)
 	g1 = GETGREENPART(default_color)
 	b1 = GETBLUEPART(default_color)
@@ -70,7 +69,6 @@
 	RegisterSignal(new_ethereal, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(refresh_light_color))
 	ethereal_light = new_ethereal.mob_light(light_type = /obj/effect/dummy/lighting_obj/moblight/species)
 	refresh_light_color(new_ethereal)
-	new_ethereal.set_safe_hunger_level()
 	// update_mail_goodies(new_ethereal) // NON-MODULE CHANGE
 
 	var/obj/item/organ/internal/heart/ethereal/ethereal_heart = new_ethereal.get_organ_slot(ORGAN_SLOT_HEART)
@@ -128,7 +126,6 @@
 		ethereal_light.set_light_range_power_color(1 + (2 * healthpercent), 1 + (1 * healthpercent), current_color)
 		ethereal_light.set_light_on(TRUE)
 		fixed_mut_color = current_color
-		fixed_hair_color = current_color
 		ethereal.update_body()
 		ethereal.set_facial_haircolor(current_color, override = TRUE, update = FALSE)
 		ethereal.set_haircolor(current_color, override = TRUE,  update = TRUE)
@@ -136,7 +133,6 @@
 		ethereal_light.set_light_on(FALSE)
 		var/dead_color = rgb(128,128,128)
 		fixed_mut_color = dead_color
-		fixed_hair_color = dead_color
 		ethereal.update_body()
 		ethereal.set_facial_haircolor(dead_color, override = TRUE, update = FALSE)
 		ethereal.set_haircolor(dead_color, override = TRUE, update = TRUE)
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 7870dcd618cc..2574420b49ce 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -31,7 +31,9 @@
 	inherent_factions = list(FACTION_SLIME)
 	species_language_holder = /datum/language_holder/jelly
 	ass_image = 'icons/ass/assslime.png'
-
+	hair_color_mode = USE_MUTANT_COLOR
+	hair_alpha = 150
+	facial_hair_alpha = 150
 	bodypart_overrides = list(
 		BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/jelly,
 		BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/jelly,
@@ -213,9 +215,7 @@
 	name = "\improper Slimeperson"
 	plural_form = "Slimepeople"
 	id = SPECIES_SLIMEPERSON
-	hair_color = "mutcolor"
-	hair_alpha = 150
-	facial_hair_alpha = 150
+	hair_color_mode = USE_MUTANT_COLOR
 	changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT
 	mutanteyes = /obj/item/organ/internal/eyes
 	var/datum/action/innate/split_body/slime_split
@@ -223,12 +223,12 @@
 	var/datum/action/innate/swap_body/swap_body
 
 	bodypart_overrides = list(
-		BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/slime,
-		BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/slime,
-		BODY_ZONE_HEAD = /obj/item/bodypart/head/slime,
-		BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/slime,
-		BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/slime,
-		BODY_ZONE_CHEST = /obj/item/bodypart/chest/slime,
+		BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/jelly/slime,
+		BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/jelly/slime,
+		BODY_ZONE_HEAD = /obj/item/bodypart/head/jelly/slime,
+		BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/jelly/slime,
+		BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/jelly/slime,
+		BODY_ZONE_CHEST = /obj/item/bodypart/chest/jelly/slime,
 	)
 
 /datum/species/jelly/slime/get_physical_attributes()
@@ -523,12 +523,12 @@
 	id = SPECIES_LUMINESCENT
 	examine_limb_id = SPECIES_LUMINESCENT
 	bodypart_overrides = list(
-		BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/luminescent,
-		BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/luminescent,
-		BODY_ZONE_HEAD = /obj/item/bodypart/head/luminescent,
-		BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/luminescent,
-		BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/luminescent,
-		BODY_ZONE_CHEST = /obj/item/bodypart/chest/luminescent,
+		BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/jelly/luminescent,
+		BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/jelly/luminescent,
+		BODY_ZONE_HEAD = /obj/item/bodypart/head/jelly/luminescent,
+		BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/jelly/luminescent,
+		BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/jelly/luminescent,
+		BODY_ZONE_CHEST = /obj/item/bodypart/chest/jelly/luminescent,
 	)
 	mutanteyes = /obj/item/organ/internal/eyes
 	/// How strong is our glow
diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
index 141ad48de8aa..173bf2474cce 100644
--- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
@@ -5,7 +5,6 @@
 	changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN
 
 	fixed_mut_color = "#DBBF92"
-	hair_color = "#FF4B19" //cap color, spot color uses eye color
 
 	external_organs = list(/obj/item/organ/external/mushroom_cap = "Round")
 
@@ -57,6 +56,9 @@
 	if(chem.type == /datum/reagent/toxin/plantbgone/weedkiller)
 		affected.adjustToxLoss(3 * REM * seconds_per_tick)
 
+/datum/species/mush/get_fixed_hair_color(mob/living/carbon/human/for_mob)
+	return "#FF4B19" //cap color, spot color uses eye color
+
 /// A mushpersons mushroom cap organ
 /obj/item/organ/external/mushroom_cap
 	name = "mushroom cap"
@@ -87,4 +89,3 @@
 		return FALSE
 
 	return TRUE
-
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index 8ce8be6f6d6b..ff1fcc4f6254 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -62,10 +62,6 @@
 	/// If the bones themselves are burning clothes won't help you much
 	var/internal_fire = FALSE
 
-/datum/species/plasmaman/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
-	. = ..()
-	C.set_safe_hunger_level()
-
 /datum/species/plasmaman/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired)
 	. = ..()
 	var/atmos_sealed = TRUE
@@ -115,7 +111,7 @@
 	else
 		internal_fire = FALSE
 
-	H.update_fire()
+	H.update_appearance(UPDATE_OVERLAYS)
 
 /datum/species/plasmaman/handle_fire(mob/living/carbon/human/H, seconds_per_tick, no_protection = FALSE)
 	if(internal_fire)
diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
index a20e240529fb..4718645b5634 100644
--- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm
+++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
@@ -44,10 +44,6 @@
 		BODY_ZONE_CHEST = /obj/item/bodypart/chest/skeleton,
 	)
 
-/datum/species/skeleton/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
-	. = ..()
-	C.set_safe_hunger_level()
-
 /datum/species/skeleton/check_roundstart_eligible()
 	if(check_holidays(HALLOWEEN))
 		return TRUE
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 59c0fbad6239..427c71b9bd00 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -39,7 +39,6 @@
 	to_chat(new_vampire, "[info_text]")
 	new_vampire.skin_tone = "albino"
 	new_vampire.update_body(0)
-	new_vampire.set_safe_hunger_level()
 	RegisterSignal(new_vampire, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, PROC_REF(damage_weakness))
 
 /datum/species/vampire/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
diff --git a/code/modules/mob/living/carbon/init_signals.dm b/code/modules/mob/living/carbon/init_signals.dm
index 190fe9d84534..e64410ab6357 100644
--- a/code/modules/mob/living/carbon/init_signals.dm
+++ b/code/modules/mob/living/carbon/init_signals.dm
@@ -13,12 +13,6 @@
 	RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_TOXIMMUNE), PROC_REF(on_toximmune_trait_gain))
 	RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_GENELESS), PROC_REF(on_geneless_trait_gain))
 
-
-	RegisterSignals(src, list(
-		SIGNAL_ADDTRAIT(TRAIT_PERMANENTLY_ONFIRE),
-		SIGNAL_REMOVETRAIT(TRAIT_PERMANENTLY_ONFIRE),
-	), PROC_REF(update_permanently_on_fire))
-
 /**
  * On gain of TRAIT_AGENDER
  *
@@ -90,12 +84,6 @@
 
 	reagents.end_metabolization(keep_liverless = TRUE)
 
-///On gain of TRAIT_PERMANENTLY_ONFIRE, update the visuals if not on fire
-/mob/living/carbon/proc/update_permanently_on_fire(datum/source)
-	SIGNAL_HANDLER
-	if(!on_fire)
-		update_fire()
-
 /**
  * On gain of TRAIT_VIRUSIMMUNE
  *
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index db8302b49dfa..63f698a3e3fa 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -72,12 +72,10 @@
 	key_third_person = "coughs"
 	message = "coughs!"
 	message_mime = "acts out an exaggerated cough!"
-	emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
+	emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE | EMOTE_RUNECHAT
 
 /datum/emote/living/cough/can_run_emote(mob/user, status_check = TRUE , intentional)
-	. = ..()
-	if(HAS_TRAIT(user, TRAIT_SOOTHED_THROAT))
-		return FALSE
+	return !HAS_TRAIT(user, TRAIT_SOOTHED_THROAT) && ..()
 
 /datum/emote/living/dance
 	key = "dance"
@@ -539,7 +537,7 @@
 /// The base chance for your yawn to propagate to someone else if they're on the same tile as you
 #define YAWN_PROPAGATE_CHANCE_BASE 20
 /// The amount the base chance to propagate yawns falls for each tile of distance
-#define YAWN_PROPAGATE_CHANCE_DECAY 4
+#define YAWN_PROPAGATE_CHANCE_DECAY 8
 
 /datum/emote/living/yawn
 	key = "yawn"
@@ -548,7 +546,7 @@
 	message_mime = "acts out an exaggerated silent yawn."
 	message_robot = "symphathetically yawns."
 	message_AI = "symphathetically yawns."
-	emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE
+	emote_type = EMOTE_VISIBLE | EMOTE_AUDIBLE | EMOTE_RUNECHAT
 	cooldown = 5 SECONDS
 
 /datum/emote/living/yawn/run_emote(mob/user, params, type_override, intentional)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index f1569bb6b00a..eb5584373ce3 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -929,12 +929,14 @@
 	if(heal_flags & HEAL_STAM)
 		setStaminaLoss(0, updating_stamina = FALSE, forced = TRUE)
 
-	// I don't really care to keep this under a flag
-	set_nutrition(NUTRITION_LEVEL_FED + 50)
+	if(heal_flags & HEAL_STATUS) // NON-MODULE CHANGE
+		set_nutrition(NUTRITION_LEVEL_FED + 50)
+		overeatduration = 0
+		satiety = 0
+		set_disgust(0)
+	if(heal_flags & (HEAL_STATUS|HEAL_OXY)) // NON-MODULE CHANGE
+		losebreath = 0
 
-	// These should be tracked by status effects
-	losebreath = 0
-	set_disgust(0)
 	cure_husk()
 
 	if(heal_flags & HEAL_TEMP)
@@ -1581,11 +1583,6 @@ GLOBAL_LIST_EMPTY(fire_appearances)
 
 	return fire_status.ignite(silent)
 
-/mob/living/proc/update_fire()
-	var/datum/status_effect/fire_handler/fire_stacks/fire_stacks = has_status_effect(/datum/status_effect/fire_handler/fire_stacks)
-	if(fire_stacks)
-		fire_stacks.update_overlay()
-
 /**
  * Extinguish all fire on the mob
  *
@@ -1593,7 +1590,7 @@ GLOBAL_LIST_EMPTY(fire_appearances)
  * Signals the extinguishing.
  */
 /mob/living/proc/extinguish_mob()
-	if(HAS_TRAIT(src, TRAIT_PERMANENTLY_ONFIRE)) //The everlasting flames will not be extinguished
+	if(HAS_TRAIT(src, TRAIT_NO_EXTINGUISH)) //The everlasting flames will not be extinguished
 		return
 	var/datum/status_effect/fire_handler/fire_stacks/fire_status = has_status_effect(/datum/status_effect/fire_handler/fire_stacks)
 	if(!fire_status || !fire_status.on_fire)
@@ -1612,13 +1609,13 @@ GLOBAL_LIST_EMPTY(fire_appearances)
 
 /mob/living/proc/adjust_fire_stacks(stacks, fire_type = /datum/status_effect/fire_handler/fire_stacks)
 	if(stacks < 0)
-		if(HAS_TRAIT(src, TRAIT_PERMANENTLY_ONFIRE)) //You can't reduce fire stacks of the everlasting flames
+		if(HAS_TRAIT(src, TRAIT_NO_EXTINGUISH)) //You can't reduce fire stacks of the everlasting flames
 			return
 		stacks = max(-fire_stacks, stacks)
 	apply_status_effect(fire_type, stacks)
 
 /mob/living/proc/adjust_wet_stacks(stacks, wet_type = /datum/status_effect/fire_handler/wet_stacks)
-	if(HAS_TRAIT(src, TRAIT_PERMANENTLY_ONFIRE)) //The everlasting flames will not be extinguished
+	if(HAS_TRAIT(src, TRAIT_NO_EXTINGUISH)) //The everlasting flames will not be extinguished
 		return
 	if(stacks < 0)
 		stacks = max(fire_stacks, stacks)
@@ -1696,19 +1693,18 @@ GLOBAL_LIST_EMPTY(fire_appearances)
 	ignite_mob()
 
 /**
- * Sets fire overlay of the mob.
+ * Gets the fire overlay to use for this mob
  *
- * Vars:
+ * Args:
  * * stacks: Current amount of fire_stacks
  * * on_fire: If we're lit on fire
- * * last_icon_state: Holds last fire overlay icon state, used for optimization
- * * suffix: Suffix for the fire icon state for special fire types
  *
- * This should return last_icon_state for the fire status efect
+ * Return a mutable appearance, the overlay that will be applied.
  */
 
-/mob/living/proc/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
-	return last_icon_state
+/mob/living/proc/get_fire_overlay(stacks, on_fire) as /mutable_appearance
+	RETURN_TYPE(/mutable_appearance)
+	return null
 
 /**
  * Handles effects happening when mob is on normal fire
@@ -2335,27 +2331,6 @@ GLOBAL_LIST_EMPTY(fire_appearances)
 /mob/living/carbon/human/will_escape_storage()
 	return TRUE
 
-/// Sets the mob's hunger levels to a safe overall level. Useful for TRAIT_NOHUNGER species changes.
-/mob/living/proc/set_safe_hunger_level()
-	// Nutrition reset and alert clearing.
-	nutrition = NUTRITION_LEVEL_FED
-	clear_alert(ALERT_NUTRITION)
-	satiety = 0
-
-	// Trait removal if obese
-	if(HAS_TRAIT_FROM(src, TRAIT_FAT, OBESITY))
-		if(overeatduration >= (200 SECONDS))
-			to_chat(src, span_notice("Your transformation restores your body's natural fitness!"))
-
-		REMOVE_TRAIT(src, TRAIT_FAT, OBESITY)
-		remove_movespeed_modifier(/datum/movespeed_modifier/obesity)
-		update_worn_undersuit()
-		update_worn_oversuit()
-
-	// Reset overeat duration.
-	overeatduration = 0
-
-
 /// Changes the value of the [living/body_position] variable. Call this before set_lying_angle()
 /mob/living/proc/set_body_position(new_value)
 	if(body_position == new_value)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index ed9cbe09352c..f73336fe963d 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -352,7 +352,7 @@
 		var/mutable_appearance/head_overlay = hat.build_worn_icon(default_layer = 20, default_icon_file = 'icons/mob/clothing/head/default.dmi')
 		head_overlay.pixel_z += hat_offset
 		add_overlay(head_overlay)
-	update_fire()
+	update_appearance(UPDATE_OVERLAYS)
 
 /mob/living/silicon/robot/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
 	if(same_z_layer)
@@ -1017,25 +1017,19 @@
 /mob/living/silicon/robot/proc/untip_roleplay()
 	to_chat(src, span_notice("Your frustration has empowered you! You can now right yourself faster!"))
 
-/mob/living/silicon/robot/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
-	var/fire_icon = "generic_fire[suffix]"
+/mob/living/silicon/robot/get_fire_overlay(stacks, on_fire)
+	var/fire_icon = "generic_fire"
 
 	if(!GLOB.fire_appearances[fire_icon])
-		var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/effects/onfire.dmi', fire_icon, -FIRE_LAYER)
-		new_fire_overlay.appearance_flags = RESET_COLOR
+		var/mutable_appearance/new_fire_overlay = mutable_appearance(
+			'icons/mob/effects/onfire.dmi',
+			fire_icon,
+			-HIGHEST_LAYER,
+			appearance_flags = RESET_COLOR,
+		)
 		GLOB.fire_appearances[fire_icon] = new_fire_overlay
 
-	if(stacks && on_fire)
-		if(last_icon_state == fire_icon)
-			return last_icon_state
-		add_overlay(GLOB.fire_appearances[fire_icon])
-		return fire_icon
-
-	if(!last_icon_state)
-		return last_icon_state
-
-	cut_overlay(GLOB.fire_appearances[fire_icon])
-	return null
+	return GLOB.fire_appearances[fire_icon]
 
 /// Draw power from the robot
 /mob/living/silicon/robot/proc/draw_power(power_to_draw)
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index 22c7439ec803..210554f137fa 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -397,7 +397,7 @@
 		COOLDOWN_START(src, next_salute_check, BOT_COMMISSIONED_SALUTE_DELAY)
 		for(var/mob/living/simple_animal/bot/B in view(5, src))
 			if(!B.commissioned && B.bot_mode_flags & BOT_MODE_ON)
-				visible_message("<b>[B]</b> performs an elaborate salute for [src]!")
+				manual_emote("performs an elaborate salute for [src]!")
 				break
 
 	switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command.
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index d870a121ee4c..f83334e93c3d 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -262,10 +262,12 @@
  * message is output to anyone who can see, e.g. `"The [src] does something!"`
  *
  * Vars:
+ * * message is the message output to anyone who can see.
  * * self_message (optional) is what the src mob sees e.g. "You do something!"
  * * blind_message (optional) is what blind people will hear e.g. "You hear something!"
  * * vision_distance (optional) define how many tiles away the message can be seen.
- * * ignored_mob (optional) doesn't show any message to a given mob if TRUE.
+ * * ignored_mobs (optional) doesn't show any message to any mob in this list.
+ * * visible_message_flags (optional) is the type of message being sent.
  */
 /atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE)
 	var/turf/T = get_turf(src)
@@ -314,8 +316,22 @@
 ///Adds the functionality to self_message.
 /mob/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs, visible_message_flags = NONE)
 	. = ..()
-	if(self_message)
-		show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE)
+	if(!self_message)
+		return
+	var/raw_self_message = self_message
+	var/self_runechat = FALSE
+	if(visible_message_flags & EMOTE_MESSAGE)
+		self_message = "<span class='emote'><b>[src]</b> [self_message]</span>" // May make more sense as "You do x"
+
+	if(visible_message_flags & ALWAYS_SHOW_SELF_MESSAGE)
+		to_chat(src, self_message)
+		self_runechat = TRUE
+
+	else
+		self_runechat = show_message(self_message, MSG_VISUAL, blind_message, MSG_AUDIBLE)
+
+	if(self_runechat && (visible_message_flags & EMOTE_MESSAGE) && runechat_prefs_check(src, visible_message_flags))
+		create_chat_message(src, raw_message = raw_self_message, runechat_flags = visible_message_flags)
 
 /**
  * Show a message to all mobs in earshot of this atom
@@ -326,6 +342,8 @@
  * * message is the message output to anyone who can hear.
  * * deaf_message (optional) is what deaf people will see.
  * * hearing_distance (optional) is the range, how many tiles away the message can be heard.
+ * * self_message (optional) is what the src mob hears.
+ * * audible_message_flags (optional) is the type of message being sent.
  */
 /atom/proc/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, audible_message_flags = NONE)
 	var/list/hearers = get_hearers_in_view(hearing_distance, src)
@@ -352,9 +370,20 @@
  */
 /mob/audible_message(message, deaf_message, hearing_distance = DEFAULT_MESSAGE_RANGE, self_message, audible_message_flags = NONE)
 	. = ..()
-	if(self_message)
-		show_message(self_message, MSG_AUDIBLE, deaf_message, MSG_VISUAL)
+	if(!self_message)
+		return
+	var/raw_self_message = self_message
+	var/self_runechat = FALSE
+	if(audible_message_flags & EMOTE_MESSAGE)
+		self_message = "<span class='emote'><b>[src]</b> [self_message]</span>"
+	if(audible_message_flags & ALWAYS_SHOW_SELF_MESSAGE)
+		to_chat(src, self_message)
+		self_runechat = TRUE
+	else
+		self_runechat = show_message(self_message, MSG_AUDIBLE, deaf_message, MSG_VISUAL)
 
+	if(self_runechat && (audible_message_flags & EMOTE_MESSAGE) && runechat_prefs_check(src, audible_message_flags))
+		create_chat_message(src, raw_message = raw_self_message, runechat_flags = audible_message_flags)
 
 ///Returns the client runechat visible messages preference according to the message type.
 /atom/proc/runechat_prefs_check(mob/target, visible_message_flags = NONE)
@@ -1514,12 +1543,28 @@
 	get_language_holder().open_language_menu(usr)
 
 ///Adjust the nutrition of a mob
-/mob/proc/adjust_nutrition(change) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
+/mob/proc/adjust_nutrition(change, forced = FALSE) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
+	if(HAS_TRAIT(src, TRAIT_NOHUNGER) && !forced)
+		return
+
 	nutrition = max(0, nutrition + change)
+	hud_used?.hunger?.update_appearance()
+
+/mob/living/adjust_nutrition(change, forced)
+	. = ..()
+	mob_mood?.update_nutrition_moodlets()
 
 ///Force set the mob nutrition
-/mob/proc/set_nutrition(change) //Seriously fuck you oldcoders.
-	nutrition = max(0, change)
+/mob/proc/set_nutrition(set_to, forced = FALSE) //Seriously fuck you oldcoders.
+	if(HAS_TRAIT(src, TRAIT_NOHUNGER) && !forced)
+		return
+
+	nutrition = max(0, set_to)
+	hud_used?.hunger?.update_appearance()
+
+/mob/living/set_nutrition(set_to, forced)
+	. = ..()
+	mob_mood?.update_nutrition_moodlets()
 
 /mob/proc/update_equipment_speed_mods()
 	var/speedies = equipped_speed_mods()
diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm
index b8a45656644b..5a65b038401d 100644
--- a/code/modules/mod/mod_activation.dm
+++ b/code/modules/mod/mod_activation.dm
@@ -238,7 +238,8 @@
 		for(var/obj/item/mod/module/module as anything in modules)
 			module.on_suit_deactivation()
 	update_speed()
-	update_icon_state()
+	update_appearance(UPDATE_ICON_STATE)
+	update_charge_alert()
 	wearer.update_clothing(slot_flags)
 
 /// Quickly deploys all the suit parts and if successful, seals them and turns on the suit. Intended mostly for outfits.
diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm
index 39111684f62f..f3f2d93017dc 100644
--- a/code/modules/mod/mod_control.dm
+++ b/code/modules/mod/mod_control.dm
@@ -243,7 +243,6 @@
 	if(malfunctioning)
 		malfunctioning_charge_drain = rand(1,20)
 	subtract_charge((charge_drain + malfunctioning_charge_drain) * seconds_per_tick)
-	update_charge_alert()
 	for(var/obj/item/mod/module/module as anything in modules)
 		if(malfunctioning && module.active && SPT_PROB(5, seconds_per_tick))
 			module.on_deactivation(display_message = TRUE)
@@ -319,7 +318,6 @@
 		wrench.play_tool_sound(src, 100)
 		balloon_alert(user, "core removed")
 		core.forceMove(drop_location())
-		update_charge_alert()
 		return TRUE
 	return ..()
 
@@ -402,7 +400,6 @@
 		attacking_core.install(src)
 		balloon_alert(user, "core installed")
 		playsound(src, 'sound/machines/click.ogg', 50, TRUE, SILENCED_SOUND_EXTRARANGE)
-		update_charge_alert()
 		return TRUE
 	else if(is_wire_tool(attacking_item) && open)
 		wires.interact(user)
@@ -413,11 +410,9 @@
 	return ..()
 
 /obj/item/mod/control/get_cell()
-	if(!open)
-		return
 	var/obj/item/stock_parts/cell/cell = get_charge_source()
 	if(!istype(cell))
-		return
+		return null
 	return cell
 
 /obj/item/mod/control/GetAccess()
@@ -488,8 +483,8 @@
 	for(var/obj/item/mod/module/module as anything in modules)
 		module.on_unequip()
 	UnregisterSignal(wearer, list(COMSIG_ATOM_EXITED, COMSIG_SPECIES_GAIN))
-	wearer.clear_alert(ALERT_MODSUIT_CHARGE)
 	SEND_SIGNAL(src, COMSIG_MOD_WEARER_UNSET, wearer)
+	wearer.update_spacesuit_hud_icon("0")
 	wearer = null
 
 /obj/item/mod/control/proc/clean_up()
@@ -632,13 +627,21 @@
 /obj/item/mod/control/proc/check_charge(amount)
 	return core?.check_charge(amount) || FALSE
 
+/**
+ * Updates the wearer's hud according to the current state of the MODsuit
+ */
 /obj/item/mod/control/proc/update_charge_alert()
-	if(!wearer)
+	if(isnull(wearer))
 		return
-	if(!core)
-		wearer.throw_alert(ALERT_MODSUIT_CHARGE, /atom/movable/screen/alert/nocore)
-		return
-	core.update_charge_alert()
+	var/state_to_use
+	if(!active)
+		state_to_use = "0"
+	else if(isnull(core))
+		state_to_use = "coreless"
+	else
+		state_to_use = core.get_charge_icon_state()
+
+	wearer.update_spacesuit_hud_icon(state_to_use || "0")
 
 /obj/item/mod/control/proc/update_speed()
 	var/list/all_parts = mod_parts + src
@@ -704,7 +707,6 @@
 		return
 	if(part == core)
 		core.uninstall()
-		update_charge_alert()
 		return
 	if(part.loc == wearer)
 		return
diff --git a/code/modules/mod/mod_core.dm b/code/modules/mod/mod_core.dm
index d5c43497982a..0287c0a23851 100644
--- a/code/modules/mod/mod_core.dm
+++ b/code/modules/mod/mod_core.dm
@@ -18,9 +18,11 @@
 	mod = mod_unit
 	mod.core = src
 	forceMove(mod)
+	mod.update_charge_alert()
 
 /obj/item/mod/core/proc/uninstall()
 	mod.core = null
+	mod.update_charge_alert()
 	mod = null
 
 /obj/item/mod/core/proc/charge_source()
@@ -41,8 +43,11 @@
 /obj/item/mod/core/proc/check_charge(amount)
 	return FALSE
 
-/obj/item/mod/core/proc/update_charge_alert()
-	mod.wearer.clear_alert(ALERT_MODSUIT_CHARGE)
+/**
+ * Gets what icon state to display on the HUD for the charge level of this core
+ */
+/obj/item/mod/core/proc/get_charge_icon_state()
+	return "0"
 
 /obj/item/mod/core/infinite
 	name = "MOD infinite core"
@@ -68,6 +73,9 @@
 /obj/item/mod/core/infinite/check_charge(amount)
 	return TRUE
 
+/obj/item/mod/core/infinite/get_charge_icon_state()
+	return "high"
+
 /obj/item/mod/core/standard
 	name = "MOD standard core"
 	icon_state = "mod-core-standard"
@@ -80,8 +88,7 @@
 	var/obj/item/stock_parts/cell/cell
 
 /obj/item/mod/core/standard/Destroy()
-	if(cell)
-		QDEL_NULL(cell)
+	QDEL_NULL(cell)
 	return ..()
 
 /obj/item/mod/core/standard/install(obj/item/mod/control/mod_unit)
@@ -116,54 +123,57 @@
 
 /obj/item/mod/core/standard/add_charge(amount)
 	var/obj/item/stock_parts/cell/charge_source = charge_source()
-	if(!charge_source)
+	if(isnull(charge_source))
 		return FALSE
-	return charge_source.give(amount)
+	. = charge_source.give(amount)
+	if(.)
+		mod.update_charge_alert()
+	return .
 
 /obj/item/mod/core/standard/subtract_charge(amount)
 	var/obj/item/stock_parts/cell/charge_source = charge_source()
-	if(!charge_source)
+	if(isnull(charge_source))
 		return FALSE
-	return charge_source.use(amount, TRUE)
+	. = charge_source.use(amount, TRUE)
+	if(.)
+		mod.update_charge_alert()
+	return .
 
 /obj/item/mod/core/standard/check_charge(amount)
 	return charge_amount() >= amount
 
-/obj/item/mod/core/standard/update_charge_alert()
-	var/obj/item/stock_parts/cell/charge_source = charge_source()
-	if(!charge_source)
-		mod.wearer.throw_alert(ALERT_MODSUIT_CHARGE, /atom/movable/screen/alert/nocell)
-		return
-	var/remaining_cell = charge_amount() / max_charge_amount()
-	switch(remaining_cell)
+/obj/item/mod/core/standard/get_charge_icon_state()
+	if(isnull(charge_source()))
+		return "missing"
+
+	switch(round(charge_amount() / max_charge_amount(), 0.01))
 		if(0.75 to INFINITY)
-			mod.wearer.clear_alert(ALERT_MODSUIT_CHARGE)
+			return "high"
 		if(0.5 to 0.75)
-			mod.wearer.throw_alert(ALERT_MODSUIT_CHARGE, /atom/movable/screen/alert/lowcell, 1)
+			return "mid"
 		if(0.25 to 0.5)
-			mod.wearer.throw_alert(ALERT_MODSUIT_CHARGE, /atom/movable/screen/alert/lowcell, 2)
-		if(0.01 to 0.25)
-			mod.wearer.throw_alert(ALERT_MODSUIT_CHARGE, /atom/movable/screen/alert/lowcell, 3)
-		else
-			mod.wearer.throw_alert(ALERT_MODSUIT_CHARGE, /atom/movable/screen/alert/emptycell)
+			return "low"
+		if(0.02 to 0.25)
+			return "very_low"
+
+	return "empty"
 
 /obj/item/mod/core/standard/proc/install_cell(new_cell)
 	cell = new_cell
 	cell.forceMove(src)
-	RegisterSignal(src, COMSIG_ATOM_EXITED, PROC_REF(on_exit))
+	mod.update_charge_alert()
 
 /obj/item/mod/core/standard/proc/uninstall_cell()
 	if(!cell)
 		return
+	cell.update_appearance()
 	cell = null
-	UnregisterSignal(src, COMSIG_ATOM_EXITED)
-
-/obj/item/mod/core/standard/proc/on_exit(datum/source, obj/item/stock_parts/cell, direction)
-	SIGNAL_HANDLER
+	mod.update_charge_alert()
 
-	if(!istype(cell) || cell.loc == src)
-		return
-	uninstall_cell()
+/obj/item/mod/core/standard/Exited(atom/movable/gone, direction)
+	. = ..()
+	if(gone == cell)
+		uninstall_cell()
 
 /obj/item/mod/core/standard/proc/on_examine(datum/source, mob/examiner, list/examine_text)
 	SIGNAL_HANDLER
@@ -195,7 +205,6 @@
 	var/obj/item/cell_to_move = cell
 	cell_to_move.forceMove(drop_location())
 	user.put_in_hands(cell_to_move)
-	mod.update_charge_alert()
 
 /obj/item/mod/core/standard/proc/on_attackby(datum/source, obj/item/attacking_item, mob/user)
 	SIGNAL_HANDLER
@@ -212,7 +221,6 @@
 		install_cell(attacking_item)
 		mod.balloon_alert(user, "cell installed")
 		playsound(mod, 'sound/machines/click.ogg', 50, TRUE, SILENCED_SOUND_EXTRARANGE)
-		mod.update_charge_alert()
 		return COMPONENT_NO_AFTERATTACK
 	return NONE
 
@@ -272,12 +280,8 @@
 /obj/item/mod/core/ethereal/check_charge(amount)
 	return charge_amount() >= amount*charge_modifier
 
-/obj/item/mod/core/ethereal/update_charge_alert()
-	var/obj/item/organ/internal/stomach/ethereal/charge_source = charge_source()
-	if(charge_source)
-		mod.wearer.clear_alert(ALERT_MODSUIT_CHARGE)
-		return
-	mod.wearer.throw_alert(ALERT_MODSUIT_CHARGE, /atom/movable/screen/alert/nocell)
+/obj/item/mod/core/ethereal/get_charge_icon_state()
+	return charge_source() ? "0" : "missing"
 
 #define PLASMA_CORE_ORE_CHARGE 1500
 #define PLASMA_CORE_SHEET_CHARGE 2000
@@ -318,28 +322,29 @@
 
 /obj/item/mod/core/plasma/add_charge(amount)
 	charge = min(maxcharge, charge + amount)
+	mod.update_charge_alert()
 	return TRUE
 
 /obj/item/mod/core/plasma/subtract_charge(amount)
 	charge = max(0, charge - amount)
+	mod.update_charge_alert()
 	return TRUE
 
 /obj/item/mod/core/plasma/check_charge(amount)
 	return charge_amount() >= amount
 
-/obj/item/mod/core/plasma/update_charge_alert()
-	var/remaining_plasma = charge_amount() / max_charge_amount()
-	switch(remaining_plasma)
+/obj/item/mod/core/plasma/get_charge_icon_state()
+	switch(round(charge_amount() / max_charge_amount(), 0.01))
 		if(0.75 to INFINITY)
-			mod.wearer.clear_alert(ALERT_MODSUIT_CHARGE)
+			return "high"
 		if(0.5 to 0.75)
-			mod.wearer.throw_alert(ALERT_MODSUIT_CHARGE, /atom/movable/screen/alert/lowcell/plasma, 1)
+			return "mid"
 		if(0.25 to 0.5)
-			mod.wearer.throw_alert(ALERT_MODSUIT_CHARGE, /atom/movable/screen/alert/lowcell/plasma, 2)
-		if(0.01 to 0.25)
-			mod.wearer.throw_alert(ALERT_MODSUIT_CHARGE, /atom/movable/screen/alert/lowcell/plasma, 3)
-		else
-			mod.wearer.throw_alert(ALERT_MODSUIT_CHARGE, /atom/movable/screen/alert/emptycell/plasma)
+			return "low"
+		if(0.02 to 0.25)
+			return "very_low"
+
+	return "empty"
 
 /obj/item/mod/core/plasma/proc/on_attackby(datum/source, obj/item/attacking_item, mob/user)
 	SIGNAL_HANDLER
diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm
index aabd872a40f2..32a8f2e6cbd1 100644
--- a/code/modules/mod/modules/_module.dm
+++ b/code/modules/mod/modules/_module.dm
@@ -225,7 +225,6 @@
 	if(!check_power(amount))
 		return FALSE
 	mod.subtract_charge(amount)
-	mod.update_charge_alert()
 	return TRUE
 
 /// Checks if there is enough power in the suit
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 2523a6c2545a..ac144938ea7f 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -314,6 +314,12 @@
 	list_reagents = list(/datum/reagent/gravitum = 5)
 	rename_with_volume = TRUE
 
+/obj/item/reagent_containers/pill/ondansetron
+	name = "ondansetron pill"
+	desc = "Alleviates nausea. May cause drowsiness."
+	icon_state = "pill11"
+	list_reagents = list(/datum/reagent/medicine/ondansetron = 10)
+
 // Pill styles for chem master
 
 /obj/item/reagent_containers/pill/style
diff --git a/code/modules/reagents/withdrawal/generic_addictions.dm b/code/modules/reagents/withdrawal/generic_addictions.dm
index 5c9dd636309c..e3103fe0f0e0 100644
--- a/code/modules/reagents/withdrawal/generic_addictions.dm
+++ b/code/modules/reagents/withdrawal/generic_addictions.dm
@@ -183,7 +183,7 @@
 
 /datum/addiction/medicine/withdrawal_stage_1_process(mob/living/carbon/affected_carbon, seconds_per_tick)
 	. = ..()
-	if(SPT_PROB(10, seconds_per_tick))
+	if(SPT_PROB(1, seconds_per_tick))
 		affected_carbon.emote("cough")
 
 /datum/addiction/medicine/withdrawal_enters_stage_2(mob/living/carbon/affected_carbon)
@@ -216,6 +216,9 @@
 
 /datum/addiction/medicine/withdrawal_stage_2_process(mob/living/carbon/affected_carbon, seconds_per_tick)
 	. = ..()
+	if(SPT_PROB(2, seconds_per_tick))
+		affected_carbon.emote("cough")
+
 	var/datum/hallucination/fake_health_doll/hallucination = health_doll_ref?.resolve()
 	if(QDELETED(hallucination))
 		health_doll_ref = null
@@ -235,15 +238,14 @@
 
 /datum/addiction/medicine/withdrawal_stage_3_process(mob/living/carbon/affected_carbon, seconds_per_tick)
 	. = ..()
+	if(SPT_PROB(5, seconds_per_tick))
+		affected_carbon.emote("cough")
+
 	var/datum/hallucination/fake_health_doll/hallucination = health_doll_ref?.resolve()
 	if(!QDELETED(hallucination) && SPT_PROB(5, seconds_per_tick))
 		hallucination.increment_fake_damage()
 		return
 
-	if(SPT_PROB(15, seconds_per_tick))
-		affected_carbon.emote("cough")
-		return
-
 	if(SPT_PROB(65, seconds_per_tick))
 		return
 
@@ -283,11 +285,11 @@
 /datum/addiction/nicotine/withdrawal_stage_2_process(mob/living/carbon/affected_carbon, seconds_per_tick)
 	. = ..()
 	affected_carbon.set_jitter_if_lower(20 SECONDS * seconds_per_tick)
-	if(SPT_PROB(10, seconds_per_tick))
+	if(SPT_PROB(2, seconds_per_tick))
 		affected_carbon.emote("cough")
 
 /datum/addiction/nicotine/withdrawal_stage_3_process(mob/living/carbon/affected_carbon, seconds_per_tick)
 	. = ..()
 	affected_carbon.set_jitter_if_lower(30 SECONDS * seconds_per_tick)
-	if(SPT_PROB(15, seconds_per_tick))
+	if(SPT_PROB(5, seconds_per_tick))
 		affected_carbon.emote("cough")
diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm
index ba3e86e1015e..357b69e59a2d 100644
--- a/code/modules/surgery/bodyparts/_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/_bodyparts.dm
@@ -232,7 +232,7 @@
 	refresh_bleed_rate()
 
 /obj/item/bodypart/Destroy()
-	if(owner && !QDELETED(owner))
+	if(!QDELETED(owner))
 		forced_removal(special = FALSE, dismembered = TRUE, move_to_floor = FALSE)
 		update_owner(null)
 	for(var/wound in wounds)
@@ -250,6 +250,13 @@
 
 	return ..()
 
+/obj/item/bodypart/dump_harddel_info()
+	var/list/all_part_info = list()
+	for(var/obj/item/organ/organ in src)
+		all_part_info += "| [organ]: [organ.dump_harddel_info()]"
+
+	return "Owner: [owner || "null"] [jointext(all_part_info, "")]"
+
 /obj/item/bodypart/ex_act(severity, target)
 	if(owner) //trust me bro you dont want this
 		return FALSE
diff --git a/code/modules/surgery/bodyparts/head_hair_and_lips.dm b/code/modules/surgery/bodyparts/head_hair_and_lips.dm
index 624370536f75..c6e141cf7a46 100644
--- a/code/modules/surgery/bodyparts/head_hair_and_lips.dm
+++ b/code/modules/surgery/bodyparts/head_hair_and_lips.dm
@@ -70,7 +70,7 @@
 	facial_hairstyle = human_head_owner.facial_hairstyle
 	facial_hair_alpha = owner_species.facial_hair_alpha
 	facial_hair_color = human_head_owner.facial_hair_color
-	fixed_hair_color = owner_species.fixed_hair_color //Can be null
+	fixed_hair_color = owner_species.get_fixed_hair_color(human_head_owner) //Can be null
 	gradient_styles = human_head_owner.grad_style?.Copy()
 	gradient_colors = human_head_owner.grad_color?.Copy()
 
diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm
index c657e89cefdb..2031ea4c7230 100644
--- a/code/modules/surgery/bodyparts/parts.dm
+++ b/code/modules/surgery/bodyparts/parts.dm
@@ -227,7 +227,7 @@
 		if(bodypart_disabled)
 			owner.set_usable_hands(owner.usable_hands - 1)
 			if(owner.stat < UNCONSCIOUS)
-				to_chat(owner, span_userdanger("You lose control of your [name]!"))
+				to_chat(owner, span_userdanger("You lose control of your [plaintext_zone]!"))
 			if(held_index)
 				owner.dropItemToGround(owner.get_item_for_held_index(held_index))
 	else if(!bodypart_disabled)
@@ -324,7 +324,7 @@
 		if(bodypart_disabled)
 			owner.set_usable_hands(owner.usable_hands - 1)
 			if(owner.stat < UNCONSCIOUS)
-				to_chat(owner, span_userdanger("You lose control of your [name]!"))
+				to_chat(owner, span_userdanger("You lose control of your [plaintext_zone]!"))
 			if(held_index)
 				owner.dropItemToGround(owner.get_item_for_held_index(held_index))
 	else if(!bodypart_disabled)
@@ -443,7 +443,7 @@
 		if(bodypart_disabled)
 			owner.set_usable_legs(owner.usable_legs - 1)
 			if(owner.stat < UNCONSCIOUS)
-				to_chat(owner, span_userdanger("You lose control of your [name]!"))
+				to_chat(owner, span_userdanger("You lose control of your [plaintext_zone]!"))
 	else if(!bodypart_disabled)
 		owner.set_usable_legs(owner.usable_legs + 1)
 
@@ -532,7 +532,7 @@
 		if(bodypart_disabled)
 			owner.set_usable_legs(owner.usable_legs - 1)
 			if(owner.stat < UNCONSCIOUS)
-				to_chat(owner, span_userdanger("You lose control of your [name]!"))
+				to_chat(owner, span_userdanger("You lose control of your [plaintext_zone]!"))
 	else if(!bodypart_disabled)
 		owner.set_usable_legs(owner.usable_legs + 1)
 
diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
index 83758f920c4c..ab56084b8d1a 100644
--- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm
@@ -85,7 +85,7 @@
 	is_dimorphic = TRUE
 	dmg_overlay_type = null
 	burn_modifier = 0.5 // = 1/2x generic burn damage
-	head_flags = HEAD_ALL_FEATURES
+	head_flags = HEAD_EYECOLOR | HEAD_EYESPRITES | HEAD_HAIR | HEAD_FACIAL_HAIR
 
 /obj/item/bodypart/chest/jelly
 	biological_state = (BIO_FLESH|BIO_BLOODED)
@@ -120,60 +120,49 @@
 	burn_modifier = 0.5 // = 1/2x generic burn damage
 
 ///SLIME
-/obj/item/bodypart/head/slime
-	biological_state = (BIO_FLESH|BIO_BLOODED)
+/obj/item/bodypart/head/jelly/slime
 	limb_id = SPECIES_SLIMEPERSON
 	is_dimorphic = FALSE
-	head_flags = HEAD_ALL_FEATURES
 
-/obj/item/bodypart/chest/slime
-	biological_state = (BIO_FLESH|BIO_BLOODED)
+/obj/item/bodypart/chest/jelly/slime
 	limb_id = SPECIES_SLIMEPERSON
-	is_dimorphic = TRUE
-	wing_types = list(/obj/item/organ/external/wings/functional/slime)
 
-/obj/item/bodypart/arm/left/slime
-	biological_state = (BIO_FLESH|BIO_BLOODED)
+/obj/item/bodypart/arm/left/jelly/slime
 	limb_id = SPECIES_SLIMEPERSON
 
-/obj/item/bodypart/arm/right/slime
+/obj/item/bodypart/arm/right/jelly/slime
 	biological_state = (BIO_FLESH|BIO_BLOODED)
 	limb_id = SPECIES_SLIMEPERSON
 
-/obj/item/bodypart/leg/left/slime
+/obj/item/bodypart/leg/left/jelly/slime
 	biological_state = (BIO_FLESH|BIO_BLOODED)
 	limb_id = SPECIES_SLIMEPERSON
 
-/obj/item/bodypart/leg/right/slime
+/obj/item/bodypart/leg/right/jelly/slime
 	biological_state = (BIO_FLESH|BIO_BLOODED)
 	limb_id = SPECIES_SLIMEPERSON
 
 ///LUMINESCENT
-/obj/item/bodypart/head/luminescent
-	biological_state = (BIO_FLESH|BIO_BLOODED)
+/obj/item/bodypart/head/jelly/luminescent
 	limb_id = SPECIES_LUMINESCENT
-	is_dimorphic = TRUE
 	head_flags = HEAD_ALL_FEATURES
 
-/obj/item/bodypart/chest/luminescent
-	biological_state = (BIO_FLESH|BIO_BLOODED)
+/obj/item/bodypart/chest/jelly/luminescent
 	limb_id = SPECIES_LUMINESCENT
-	is_dimorphic = TRUE
-	wing_types = list(/obj/item/organ/external/wings/functional/slime)
 
-/obj/item/bodypart/arm/left/luminescent
+/obj/item/bodypart/arm/left/jelly/luminescent
 	biological_state = (BIO_FLESH|BIO_BLOODED)
 	limb_id = SPECIES_LUMINESCENT
 
-/obj/item/bodypart/arm/right/luminescent
+/obj/item/bodypart/arm/right/jelly/luminescent
 	biological_state = (BIO_FLESH|BIO_BLOODED)
 	limb_id = SPECIES_LUMINESCENT
 
-/obj/item/bodypart/leg/left/luminescent
+/obj/item/bodypart/leg/left/jelly/luminescent
 	biological_state = (BIO_FLESH|BIO_BLOODED)
 	limb_id = SPECIES_LUMINESCENT
 
-/obj/item/bodypart/leg/right/luminescent
+/obj/item/bodypart/leg/right/jelly/luminescent
 	biological_state = (BIO_FLESH|BIO_BLOODED)
 	limb_id = SPECIES_LUMINESCENT
 
diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm
index 276f8b470231..2fc0f1711574 100644
--- a/code/modules/surgery/organs/_organ.dm
+++ b/code/modules/surgery/organs/_organ.dm
@@ -80,9 +80,9 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
 			after_eat = CALLBACK(src, PROC_REF(OnEatFrom)))
 
 /obj/item/organ/Destroy()
-	if(bodypart_owner && !owner && !QDELETED(bodypart_owner))
+	if(isnull(owner) && !isnull(bodypart_owner))
 		bodypart_remove(bodypart_owner)
-	else if(owner)
+	else if(!isnull(owner))
 		// The special flag is important, because otherwise mobs can die
 		// while undergoing transformation into different mobs.
 		Remove(owner, special=TRUE)
@@ -90,6 +90,9 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
 		STOP_PROCESSING(SSobj, src)
 	return ..()
 
+/obj/item/organ/dump_harddel_info()
+	return "Owner: [owner || "null"] | Bodypart Owner: [bodypart_owner || "null"] | Loc: [loc || "nullspace"]"
+
 /// Add a Trait to an organ that it will give its owner.
 /obj/item/organ/proc/add_organ_trait(trait)
 	LAZYADD(organ_traits, trait)
diff --git a/code/modules/surgery/organs/internal/ears/_ears.dm b/code/modules/surgery/organs/internal/ears/_ears.dm
index ad48645e8936..e95cb94637e0 100644
--- a/code/modules/surgery/organs/internal/ears/_ears.dm
+++ b/code/modules/surgery/organs/internal/ears/_ears.dm
@@ -15,17 +15,16 @@
 	now_fixed = "<span class='info'>Noise slowly begins filling your ears once more.</span>"
 	low_threshold_cleared = "<span class='info'>The ringing in your ears has died down.</span>"
 
-	// `deaf` measures "ticks" of deafness. While > 0, the person is unable
-	// to hear anything.
+	/// `deaf` measures "ticks" of deafness. While > 0, the person is unable to hear anything.
 	var/deaf = 0
 
 	// `damage` in this case measures long term damage to the ears, if too high,
 	// the person will not have either `deaf` or `ear_damage` decrease
 	// without external aid (earmuffs, drugs)
 
-	//Resistance against loud noises
+	/// Resistance against loud noises
 	var/bang_protect = 0
-	// Multiplier for both long term and short term ear damage
+	/// Multiplier for both long term and short term ear damage
 	var/damage_multiplier = 1
 
 /obj/item/organ/internal/ears/on_life(seconds_per_tick, times_fired)
@@ -34,28 +33,98 @@
 		to_chat(owner, span_warning("The ringing in your ears grows louder, blocking out any external noises for a moment."))
 
 	. = ..()
-	// if we have non-damage related deafness like mutations, quirks or clothing (earmuffs), don't bother processing here. Ear healing from earmuffs or chems happen elsewhere
+	// if we have non-damage related deafness like mutations, quirks or clothing (earmuffs), don't bother processing here.
+	// Ear healing from earmuffs or chems happen elsewhere
 	if(HAS_TRAIT_NOT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
 		return
+	// no healing if failing
+	if(organ_flags & ORGAN_FAILING)
+		return
+	adjustEarDamage(0, -0.5 * seconds_per_tick)
+	if((damage > low_threshold) && SPT_PROB(damage / 60, seconds_per_tick))
+		adjustEarDamage(0, 4)
+		SEND_SOUND(owner, sound('sound/weapons/flash_ring.ogg'))
+
+/obj/item/organ/internal/ears/apply_organ_damage(damage_amount, maximum, required_organ_flag)
+	. = ..()
+	update_temp_deafness()
+
+/obj/item/organ/internal/ears/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags)
+	. = ..()
+	update_temp_deafness()
+
+/obj/item/organ/internal/ears/on_mob_remove(mob/living/carbon/organ_owner, special)
+	. = ..()
+	UnregisterSignal(organ_owner, COMSIG_MOB_SAY)
+	REMOVE_TRAIT(organ_owner, TRAIT_DEAF, EAR_DAMAGE)
+
+/**
+ * Snowflake proc to handle temporary deafness
+ *
+ * * ddmg: Handles normal organ damage
+ * * ddeaf: Handles temporary deafness, 1 ddeaf = 2 seconds of deafness, by default (with no multiplier)
+ */
+/obj/item/organ/internal/ears/proc/adjustEarDamage(ddmg = 0, ddeaf = 0)
+	if(owner.status_flags & GODMODE)
+		update_temp_deafness()
+		return
+
+	var/mod_damage = ddmg > 0 ? (ddmg * damage_multiplier) : ddmg
+	if(mod_damage)
+		apply_organ_damage(mod_damage)
+	var/mod_deaf = ddeaf > 0 ? (ddeaf * damage_multiplier) : ddeaf
+	if(mod_deaf)
+		deaf = max(deaf + mod_deaf, 0)
+	update_temp_deafness()
+
+/// Updates status of deafness
+/obj/item/organ/internal/ears/proc/update_temp_deafness()
+	// if we're failing we always have at least some deaf stacks (and thus deafness)
+	if(organ_flags & ORGAN_FAILING)
+		deaf = max(deaf, 1 * damage_multiplier)
+
+	if(isnull(owner))
+		return
 
-	if((organ_flags & ORGAN_FAILING))
-		deaf = max(deaf, 1) // if we're failing we always have at least 1 deaf stack (and thus deafness)
-	else // only clear deaf stacks if we're not failing
-		deaf = max(deaf - (0.5 * seconds_per_tick), 0)
-		if((damage > low_threshold) && SPT_PROB(damage / 60, seconds_per_tick))
-			adjustEarDamage(0, 4)
-			SEND_SOUND(owner, sound('sound/weapons/flash_ring.ogg'))
+	if(owner.status_flags & GODMODE)
+		deaf = 0
 
-	if(deaf)
-		ADD_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE)
+	if(deaf > 0)
+		if(!HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
+			RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(adjust_speech))
+			ADD_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE)
 	else
 		REMOVE_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE)
+		UnregisterSignal(owner, COMSIG_MOB_SAY)
 
-/obj/item/organ/internal/ears/proc/adjustEarDamage(ddmg, ddeaf)
-	if(owner.status_flags & GODMODE)
+/// Being deafened by loud noises makes you shout
+/obj/item/organ/internal/ears/proc/adjust_speech(datum/source, list/speech_args)
+	SIGNAL_HANDLER
+
+	if(HAS_TRAIT_NOT_FROM(source, TRAIT_DEAF, EAR_DAMAGE))
 		return
-	set_organ_damage(clamp(damage + (ddmg * damage_multiplier), 0, maxHealth))
-	deaf = max(deaf + (ddeaf * damage_multiplier), 0)
+	if(HAS_TRAIT(source, TRAIT_SIGN_LANG))
+		return
+
+	var/message = speech_args[SPEECH_MESSAGE]
+	// Replace only end-of-sentence punctuation with exclamation marks (hence the empty space)
+	// We don't wanna mess with things like ellipses
+	message = replacetext(message, ". ", "! ")
+	message = replacetext(message, "? ", "?! ")
+	// Special case for the last character
+	switch(copytext_char(message, -1))
+		if(".")
+			if(copytext_char(message, -2) != "..") // Once again ignoring ellipses, let people trail off
+				message = copytext_char(message, 1, -1) + "!"
+		if("?")
+			message = copytext_char(message, 1, -1) + "?!"
+		if("!")
+			pass()
+		else
+			message += "!"
+
+	speech_args[SPEECH_MESSAGE] = message
+	return COMPONENT_UPPERCASE_SPEECH
 
 /obj/item/organ/internal/ears/invincible
 	damage_multiplier = 0
diff --git a/code/modules/surgery/organs/internal/lungs/_lungs.dm b/code/modules/surgery/organs/internal/lungs/_lungs.dm
index 874ec320648b..f70519c74ed3 100644
--- a/code/modules/surgery/organs/internal/lungs/_lungs.dm
+++ b/code/modules/surgery/organs/internal/lungs/_lungs.dm
@@ -753,31 +753,85 @@
 
 	if(!HAS_TRAIT(breather, TRAIT_RESISTCOLD)) // COLD DAMAGE
 		var/cold_modifier = breather.dna.species.coldmod
+		var/breath_effect_prob = 0
 		if(breath_temperature < cold_level_3_threshold)
-			breather.apply_damage(cold_level_3_damage*cold_modifier, cold_damage_type, spread_damage = TRUE)
+			breather.apply_damage(cold_level_3_damage * cold_modifier, cold_damage_type, spread_damage = TRUE)
+			breath_effect_prob = 100
 		if(breath_temperature > cold_level_3_threshold && breath_temperature < cold_level_2_threshold)
-			breather.apply_damage(cold_level_2_damage*cold_modifier, cold_damage_type, spread_damage = TRUE)
+			breather.apply_damage(cold_level_2_damage * cold_modifier, cold_damage_type, spread_damage = TRUE)
+			breath_effect_prob = 50
 		if(breath_temperature > cold_level_2_threshold && breath_temperature < cold_level_1_threshold)
-			breather.apply_damage(cold_level_1_damage*cold_modifier, cold_damage_type, spread_damage = TRUE)
+			breather.apply_damage(cold_level_1_damage * cold_modifier, cold_damage_type, spread_damage = TRUE)
+			breath_effect_prob = 25
 		if(breath_temperature < cold_level_1_threshold)
-			if(prob(20))
+			if(prob(sqrt(breath_effect_prob) * 4))
 				to_chat(breather, span_warning("You feel [cold_message] in your [name]!"))
+				if(prob(50))
+					breather.emote("shiver")
+			if(prob(breath_effect_prob))
+				// Breathing into your mask, no particle. We can add fogged up glasses later
+				if(breather.is_mouth_covered())
+					return
+				// Even though breathing via internals TECHNICALLY exhales into the environment, we'll still block it
+				if(breather.internal || breather.external)
+					return
+				emit_breath_particle(breather, /particles/fog/breath)
 
 	if(!HAS_TRAIT(breather, TRAIT_RESISTHEAT)) // HEAT DAMAGE
 		var/heat_modifier = breather.dna.species.heatmod
+		var/heat_message_prob = 0
 		if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold)
-			breather.apply_damage(heat_level_1_damage*heat_modifier, heat_damage_type, spread_damage = TRUE)
+			breather.apply_damage(heat_level_1_damage * heat_modifier, heat_damage_type, spread_damage = TRUE)
+			heat_message_prob = 100
 		if(breath_temperature > heat_level_2_threshold && breath_temperature < heat_level_3_threshold)
-			breather.apply_damage(heat_level_2_damage*heat_modifier, heat_damage_type, spread_damage = TRUE)
+			breather.apply_damage(heat_level_2_damage * heat_modifier, heat_damage_type, spread_damage = TRUE)
+			heat_message_prob = 50
 		if(breath_temperature > heat_level_3_threshold)
-			breather.apply_damage(heat_level_3_damage*heat_modifier, heat_damage_type, spread_damage = TRUE)
+			breather.apply_damage(heat_level_3_damage * heat_modifier, heat_damage_type, spread_damage = TRUE)
+			heat_message_prob = 25
 		if(breath_temperature > heat_level_1_threshold)
-			if(prob(20))
+			if(prob(sqrt(heat_message_prob) * 4))
 				to_chat(breather, span_warning("You feel [hot_message] in your [name]!"))
 
 	// The air you breathe out should match your body temperature
 	breath.temperature = breather.bodytemperature
 
+/// Creates a particle effect off the mouth of the passed mob.
+/obj/item/organ/internal/lungs/proc/emit_breath_particle(mob/living/carbon/human/breather, particle_type)
+	ASSERT(ispath(particle_type, /particles))
+
+	var/obj/effect/abstract/particle_holder/holder = new(breather, particle_type)
+	var/particles/breath_particle = holder.particles
+	var/breath_dir = breather.dir
+
+	var/list/particle_grav = list(0, 0.1, 0)
+	var/list/particle_pos = list(0, breather.get_mob_height() + 2, 0)
+	if(breath_dir & NORTH)
+		particle_grav[2] = 0.2
+		breath_particle.rotation = pick(-45, 45)
+		// Layer it behind the mob since we're facing away from the camera
+		holder.pixel_w -= 4
+		holder.pixel_y += 4
+	if(breath_dir & WEST)
+		particle_grav[1] = -0.2
+		particle_pos[1] = -5
+		breath_particle.rotation = -45
+	if(breath_dir & EAST)
+		particle_grav[1] = 0.2
+		particle_pos[1] = 5
+		breath_particle.rotation = 45
+	if(breath_dir & SOUTH)
+		particle_grav[2] = 0.2
+		breath_particle.rotation = pick(-45, 45)
+		// Shouldn't be necessary but just for parity
+		holder.pixel_w += 4
+		holder.pixel_y -= 4
+
+	breath_particle.gravity = particle_grav
+	breath_particle.position = particle_pos
+
+	QDEL_IN(holder, breath_particle.lifespan)
+
 /obj/item/organ/internal/lungs/on_life(seconds_per_tick, times_fired)
 	. = ..()
 	if(failed && !(organ_flags & ORGAN_FAILING))
diff --git a/code/modules/surgery/organs/internal/stomach/_stomach.dm b/code/modules/surgery/organs/internal/stomach/_stomach.dm
index 6e985e26329b..56ebf09f44e0 100644
--- a/code/modules/surgery/organs/internal/stomach/_stomach.dm
+++ b/code/modules/surgery/organs/internal/stomach/_stomach.dm
@@ -128,16 +128,10 @@
 		if(human.overeatduration < (200 SECONDS))
 			to_chat(human, span_notice("You feel fit again!"))
 			REMOVE_TRAIT(human, TRAIT_FAT, OBESITY)
-			human.remove_movespeed_modifier(/datum/movespeed_modifier/obesity)
-			human.update_worn_undersuit()
-			human.update_worn_oversuit()
 	else
 		if(human.overeatduration >= (200 SECONDS))
 			to_chat(human, span_danger("You suddenly feel blubbery!"))
 			ADD_TRAIT(human, TRAIT_FAT, OBESITY)
-			human.add_movespeed_modifier(/datum/movespeed_modifier/obesity)
-			human.update_worn_undersuit()
-			human.update_worn_oversuit()
 
 	// nutrition decrease and satiety
 	if (human.nutrition > 0 && human.stat != DEAD)
@@ -189,18 +183,6 @@
 	if(CONFIG_GET(flag/disable_human_mood))
 		handle_hunger_slowdown(human)
 
-	// If we did anything more then just set and throw alerts here I would add bracketing
-	// But well, it is all we do, so there's not much point bothering with it you get me?
-	switch(nutrition)
-		if(NUTRITION_LEVEL_FULL to INFINITY)
-			human.throw_alert(ALERT_NUTRITION, /atom/movable/screen/alert/fat)
-		if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FULL)
-			human.clear_alert(ALERT_NUTRITION)
-		if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
-			human.throw_alert(ALERT_NUTRITION, /atom/movable/screen/alert/hungry)
-		if(0 to NUTRITION_LEVEL_STARVING)
-			human.throw_alert(ALERT_NUTRITION, /atom/movable/screen/alert/starving)
-
 ///for when mood is disabled and hunger should handle slowdowns
 /obj/item/organ/internal/stomach/proc/handle_hunger_slowdown(mob/living/carbon/human/human)
 	var/hungry = (500 - human.nutrition) / 5 //So overeat would be 100 and default level would be 80
@@ -262,13 +244,16 @@
 			disgusted.throw_alert(ALERT_DISGUST, /atom/movable/screen/alert/disgusted)
 			disgusted.add_mood_event("disgust", /datum/mood_event/disgusted)
 
+/obj/item/organ/internal/stomach/Insert(mob/living/carbon/receiver, special, movement_flags)
+	. = ..()
+	receiver.hud_used?.hunger?.update_appearance()
+
 /obj/item/organ/internal/stomach/Remove(mob/living/carbon/stomach_owner, special, movement_flags)
 	if(ishuman(stomach_owner))
 		var/mob/living/carbon/human/human_owner = owner
 		human_owner.clear_alert(ALERT_DISGUST)
 		human_owner.clear_mood_event("disgust")
-		human_owner.clear_alert(ALERT_NUTRITION)
-
+	stomach_owner.hud_used?.hunger?.update_appearance()
 	return ..()
 
 /obj/item/organ/internal/stomach/bone
diff --git a/code/modules/unit_tests/screenshot_humanoids.dm b/code/modules/unit_tests/screenshot_humanoids.dm
index 63e2c1788a1f..1b7e39f03bb1 100644
--- a/code/modules/unit_tests/screenshot_humanoids.dm
+++ b/code/modules/unit_tests/screenshot_humanoids.dm
@@ -2,6 +2,8 @@
 /datum/unit_test/screenshot_humanoids
 
 /datum/unit_test/screenshot_humanoids/Run()
+	var/list/testable_species = subtypesof(/datum/species)
+
 	// Test lizards as their own thing so we can get more coverage on their features
 	var/mob/living/carbon/human/lizard = allocate(/mob/living/carbon/human/dummy/consistent)
 	lizard.dna.features["mcolor"] = "#099"
@@ -13,6 +15,7 @@
 	lizard.set_species(/datum/species/lizard)
 	lizard.equipOutfit(/datum/outfit/job/engineer)
 	test_screenshot("[/datum/species/lizard]", get_flat_icon_for_all_directions(lizard))
+	testable_species -= /datum/species/lizard
 
 	// let me have this
 	var/mob/living/carbon/human/moth = allocate(/mob/living/carbon/human/dummy/consistent)
@@ -22,9 +25,21 @@
 	moth.set_species(/datum/species/moth)
 	moth.equipOutfit(/datum/outfit/job/cmo, visualsOnly = TRUE)
 	test_screenshot("[/datum/species/moth]", get_flat_icon_for_all_directions(moth))
+	testable_species -= /datum/species/moth
+
+	// More in depth test for slimes since they have a lot going on
+	for (var/datum/species/slime_type as anything in typesof(/datum/species/jelly))
+		var/mob/living/carbon/human/slime = allocate(/mob/living/carbon/human/dummy/consistent)
+		slime.dna.features["mcolor"] = COLOR_PINK
+		slime.hairstyle = "Bob Hair 2"
+		slime.hair_color = COLOR_RED // Should be forced to pink
+		slime.set_species(slime_type)
+		slime.equipOutfit(/datum/outfit/job/scientist/consistent)
+		test_screenshot("[slime_type]", get_flat_icon_for_all_directions(slime))
+		testable_species -= slime_type
 
 	// The rest of the species
-	for (var/datum/species/species_type as anything in subtypesof(/datum/species) - /datum/species/moth - /datum/species/lizard)
+	for (var/datum/species/species_type as anything in testable_species)
 		test_screenshot("[species_type]", get_flat_icon_for_all_directions(make_dummy(species_type, /datum/outfit/job/assistant/consistent)))
 
 /datum/unit_test/screenshot_humanoids/proc/make_dummy(species, job_outfit)
diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly.png
index 56205255d879..34288a8a8e5d 100644
Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly.png differ
diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_luminescent.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_luminescent.png
index d46cbea8cd86..641c9050ee46 100644
Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_luminescent.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_luminescent.png differ
diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_slime.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_slime.png
index 56205255d879..34288a8a8e5d 100644
Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_slime.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_slime.png differ
diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_stargazer.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_stargazer.png
index 8ebd5b8eea2d..eaee84fed494 100644
Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_stargazer.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_jelly_stargazer.png differ
diff --git a/icons/effects/particles/smoke.dmi b/icons/effects/particles/smoke.dmi
index 4a3239499b96..99123beeb59a 100644
Binary files a/icons/effects/particles/smoke.dmi and b/icons/effects/particles/smoke.dmi differ
diff --git a/icons/hud/screen_alert.dmi b/icons/hud/screen_alert.dmi
index dc95d505ce6b..e1c5db84d22a 100644
Binary files a/icons/hud/screen_alert.dmi and b/icons/hud/screen_alert.dmi differ
diff --git a/icons/hud/screen_gen.dmi b/icons/hud/screen_gen.dmi
index 1484e3f4042a..9792124d1b68 100644
Binary files a/icons/hud/screen_gen.dmi and b/icons/hud/screen_gen.dmi differ
diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi
index 375de2462691..c877c2fcb882 100644
Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ
diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi
index 20951b3264f0..5cb090978ae7 100644
Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ
diff --git a/maplestation.dme b/maplestation.dme
index e0963de00574..da33d403e6fc 100644
--- a/maplestation.dme
+++ b/maplestation.dme
@@ -1434,6 +1434,7 @@
 #include "code\datums\elements\openspace_item_click_handler.dm"
 #include "code\datums\elements\ore_collecting.dm"
 #include "code\datums\elements\organ_set_bonus.dm"
+#include "code\datums\elements\permanent_fire_overlay.dm"
 #include "code\datums\elements\pet_bonus.dm"
 #include "code\datums\elements\plant_backfire.dm"
 #include "code\datums\elements\point_of_interest.dm"
@@ -1702,6 +1703,7 @@
 #include "code\datums\quirks\positive_quirks\skittish.dm"
 #include "code\datums\quirks\positive_quirks\spacer.dm"
 #include "code\datums\quirks\positive_quirks\spiritual.dm"
+#include "code\datums\quirks\positive_quirks\strong_stomach.dm"
 #include "code\datums\quirks\positive_quirks\tagger.dm"
 #include "code\datums\quirks\positive_quirks\throwing_arm.dm"
 #include "code\datums\quirks\positive_quirks\voracious.dm"
diff --git a/maplestation_modules/code/datums/pain/pain.dm b/maplestation_modules/code/datums/pain/pain.dm
index 30689dcdcafd..e682fb900e79 100644
--- a/maplestation_modules/code/datums/pain/pain.dm
+++ b/maplestation_modules/code/datums/pain/pain.dm
@@ -832,8 +832,9 @@
 /datum/pain/proc/on_parent_statchance(mob/source)
 	SIGNAL_HANDLER
 
-	if(source.stat == DEAD && (datum_flags & DF_ISPROCESSING))
-		STOP_PROCESSING(SSpain, src)
+	if(source.stat == DEAD)
+		if(datum_flags & DF_ISPROCESSING)
+			STOP_PROCESSING(SSpain, src)
 	else
 		START_PROCESSING(SSpain, src)
 
diff --git a/maplestation_modules/code/modules/mob/living/blood.dm b/maplestation_modules/code/modules/mob/living/blood.dm
index 7b467369172e..21f207d702be 100644
--- a/maplestation_modules/code/modules/mob/living/blood.dm
+++ b/maplestation_modules/code/modules/mob/living/blood.dm
@@ -223,10 +223,18 @@ PROCESSING_SUBSYSTEM_DEF(blood_drying)
 /datum/blood_type/crew/lizard
 	name = "L"
 	color = "#047200" // Some species of lizards have mutated green blood due to biliverdin build up
+	compatible_types = list(/datum/blood_type/crew/lizard/silver)
+
+/datum/blood_type/crew/lizard/silver
+	color = "#ffffff63"
+	compatible_types = list(/datum/blood_type/crew/lizard)
+
+/datum/blood_type/crew/lizard/silver/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat)
+	blood.add_filter("silver_glint", 3, list("type" = "outline", "color" = "#c9c9c963", "size" = 1.5))
 
 /datum/blood_type/crew/skrell
 	name = "S"
-	color = "#009696" // Did you know octopi have blood blood, thanks to hemocyanin rather than hemoglobin? It binds to copper instead of Iron
+	color = "#009696" // Did you know octopi have blue blood, as it contains hemocyanin rather than hemoglobin? It binds to copper instead of Iron
 	restoration_chem = /datum/reagent/copper
 
 /datum/blood_type/crew/ethereal
diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index c2d2e9e01cb7..9059602ff19d 100644
--- a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -1,9 +1,16 @@
 // -- Various slime people additions. --
 /datum/species/jelly
 	species_pain_mod = 0.5
-	hair_color = "mutcolor"
-	hair_alpha = 150
+	// Makes Jellypeople look like Slimepeople and not Stargazers
 	mutanteyes = /obj/item/organ/internal/eyes
+	bodypart_overrides = list(
+		BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/jelly/slime,
+		BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/jelly/slime,
+		BODY_ZONE_HEAD = /obj/item/bodypart/head/jelly/slime,
+		BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/jelly/slime,
+		BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/jelly/slime,
+		BODY_ZONE_CHEST = /obj/item/bodypart/chest/jelly/slime,
+	)
 
 /datum/species/jelly/prepare_human_for_preview(mob/living/carbon/human/human)
 	human.dna.features["mcolor"] = COLOR_PINK
@@ -40,64 +47,14 @@
 		"As of 2562, Nanotrasen is aware of less than 50 Slimepeople in existence, with 14 of these being under their employ."
 		)
 
-// Changes jellypeople to look like slimepeople instead of stargazers
-// (Because slimepeople are more customizable / less ugly)
-/obj/item/bodypart/arm/left/jelly
-	limb_id = SPECIES_SLIMEPERSON
-
-/obj/item/bodypart/arm/right/jelly
-	limb_id = SPECIES_SLIMEPERSON
-
-/obj/item/bodypart/head/jelly
-	limb_id = SPECIES_SLIMEPERSON
-	is_dimorphic = FALSE
-
-/obj/item/bodypart/leg/left/jelly
-	limb_id = SPECIES_SLIMEPERSON
-
-/obj/item/bodypart/leg/right/jelly
-	limb_id = SPECIES_SLIMEPERSON
-
-/obj/item/bodypart/chest/jelly
-	limb_id = SPECIES_SLIMEPERSON
-
-/datum/species/jelly/luminescent
-	mutanteyes = /obj/item/organ/internal/eyes
-
-// Stargazers inherent jelly limbs so we gotta do this too
 /datum/species/jelly/stargazer
+	// Makes Stargazers look like Stargazers
 	mutanteyes = /obj/item/organ/internal/eyes/jelly
 	bodypart_overrides = list(
-		BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/stargazer,
-		BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/stargazer,
-		BODY_ZONE_HEAD = /obj/item/bodypart/head/stargazer,
-		BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/stargazer,
-		BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/stargazer,
-		BODY_ZONE_CHEST = /obj/item/bodypart/chest/stargazer,
+		BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/jelly,
+		BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/jelly,
+		BODY_ZONE_HEAD = /obj/item/bodypart/head/jelly,
+		BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/jelly,
+		BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/jelly,
+		BODY_ZONE_CHEST = /obj/item/bodypart/chest/jelly,
 	)
-
-/obj/item/bodypart/head/stargazer
-	limb_id = SPECIES_JELLYPERSON
-	is_dimorphic = TRUE
-	dmg_overlay_type = null
-
-/obj/item/bodypart/chest/stargazer
-	limb_id = SPECIES_JELLYPERSON
-	is_dimorphic = TRUE
-	dmg_overlay_type = null
-
-/obj/item/bodypart/arm/left/stargazer
-	limb_id = SPECIES_JELLYPERSON
-	dmg_overlay_type = null
-
-/obj/item/bodypart/arm/right/stargazer
-	limb_id = SPECIES_JELLYPERSON
-	dmg_overlay_type = null
-
-/obj/item/bodypart/leg/left/stargazer
-	limb_id = SPECIES_JELLYPERSON
-	dmg_overlay_type = null
-
-/obj/item/bodypart/leg/right/stargazer
-	limb_id = SPECIES_JELLYPERSON
-	dmg_overlay_type = null
diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/reploid.dm b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/reploid.dm
index 8b55c2f2f21e..7d6454f4a85f 100644
--- a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/reploid.dm
+++ b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/reploid.dm
@@ -19,7 +19,6 @@
 
 /datum/species/reploid/on_species_gain(mob/living/carbon/C)
 	. = ..()
-	C.set_safe_hunger_level()
 	// Adds robot wings to chest wing options (if it is not already robotic)
 	var/obj/item/bodypart/chest/chest = C.get_bodypart(BODY_ZONE_CHEST)
 	if(!IS_ROBOTIC_LIMB(chest))
diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/silverscale.dm b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/silverscale.dm
index 178b6bab326c..bed6e63e47c7 100644
--- a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/silverscale.dm
+++ b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/silverscale.dm
@@ -77,7 +77,7 @@
 	he_who_was_blessed_with_silver.add_filter("silver_glint", 2, list("type" = "outline", "color" = "#ffffff63", "size" = 2))
 
 	he_who_was_blessed_with_silver.physiology?.damage_resistance += 10
-
+	he_who_was_blessed_with_silver.dna.species.exotic_bloodtype = /datum/blood_type/crew/lizard/silver
 	organ_owner.update_body(TRUE)
 
 /obj/item/organ/internal/tongue/lizard/silver/on_mob_remove(mob/living/carbon/organ_owner, special)
@@ -106,6 +106,7 @@
 	old_eye_color_right = null
 
 	he_who_has_been_outcast.physiology?.damage_resistance -= 10
+	he_who_has_been_outcast.dna.species.exotic_bloodtype = initial(he_who_has_been_outcast.dna.species.exotic_bloodtype)
 
 	organ_owner.update_body(TRUE)
 
diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/synth.dm b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/synth.dm
index 003bb57be166..c3e3eb93b240 100644
--- a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/synth.dm
+++ b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/synth/synth.dm
@@ -74,7 +74,6 @@
 /datum/species/synth/on_species_gain(mob/living/carbon/human/synth, datum/species/old_species)
 	. = ..()
 	synth.AddComponent(/datum/component/ion_storm_randomization)
-	synth.set_safe_hunger_level()
 
 	if(limb_updates_on_change)
 		RegisterSignal(synth, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(disguise_damage))
@@ -192,7 +191,7 @@
 	sexes = disguise_species.sexes
 	name = disguise_species.name
 	fixed_mut_color = disguise_species.fixed_mut_color
-	hair_color = disguise_species.hair_color
+	hair_color_mode = disguise_species.hair_color_mode
 
 	if(isnull(synth.client?.prefs) || synth.client.prefs.read_preference(/datum/preference/choiced/synth_blood) == "As Disguise")
 		exotic_bloodtype = disguise_species.exotic_bloodtype
@@ -218,7 +217,7 @@
 	sexes = initial(sexes)
 	name = initial(name)
 	fixed_mut_color = initial(fixed_mut_color)
-	hair_color = initial(hair_color)
+	hair_color_mode = initial(hair_color_mode)
 
 	exotic_bloodtype = /datum/blood_type/oil
 
diff --git a/tgstation.dme b/tgstation.dme
index 1fa80723aea0..e7fbbb706285 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1434,6 +1434,7 @@
 #include "code\datums\elements\openspace_item_click_handler.dm"
 #include "code\datums\elements\ore_collecting.dm"
 #include "code\datums\elements\organ_set_bonus.dm"
+#include "code\datums\elements\permanent_fire_overlay.dm"
 #include "code\datums\elements\pet_bonus.dm"
 #include "code\datums\elements\plant_backfire.dm"
 #include "code\datums\elements\point_of_interest.dm"
@@ -1702,6 +1703,7 @@
 #include "code\datums\quirks\positive_quirks\skittish.dm"
 #include "code\datums\quirks\positive_quirks\spacer.dm"
 #include "code\datums\quirks\positive_quirks\spiritual.dm"
+#include "code\datums\quirks\positive_quirks\strong_stomach.dm"
 #include "code\datums\quirks\positive_quirks\tagger.dm"
 #include "code\datums\quirks\positive_quirks\throwing_arm.dm"
 #include "code\datums\quirks\positive_quirks\voracious.dm"