diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index 5e10a84417c..4d2eab10640 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -550,6 +550,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_CULT_HALO "cult_halo"
/// Their eyes glow an unnatural red colour. Currently used to set special examine text on humans. Does not guarantee the mob's eyes are coloured red, nor that there is any visible glow on their character sprite.
#define TRAIT_UNNATURAL_RED_GLOWY_EYES "unnatural_red_glowy_eyes"
+/// Their eyes glow in the dark (aka emissive appearance)
+#define TRAIT_LUMINESCENT_EYES "luminescent_eyes"
+/// Their eyes reflect light, making them shine faintly in dim, shadowy areas. Kinda like nocturnal animals.
+#define TRAIT_REFLECTIVE_EYES "reflective_eyes"
/// Their eyes are bloodshot. Currently used to set special examine text on humans. Examine text is overridden by TRAIT_UNNATURAL_RED_GLOWY_EYES.
#define TRAIT_BLOODSHOT_EYES "bloodshot_eyes"
/// This mob should never close UI even if it doesn't have a client
diff --git a/code/__HELPERS/honkerblast.dm b/code/__HELPERS/honkerblast.dm
index ea8eea00e59..e76d8178228 100644
--- a/code/__HELPERS/honkerblast.dm
+++ b/code/__HELPERS/honkerblast.dm
@@ -23,8 +23,7 @@
victim.Stun(100)
victim.adjust_stutter(30 SECONDS)
victim.set_jitter_if_lower(1000 SECONDS)
- var/obj/item/organ/ears/ears = victim.get_organ_slot(ORGAN_SLOT_EARS)
- ears?.adjustEarDamage(10, 15)
+ victim.sound_damage(10, 30 SECONDS)
to_chat(victim, "HONK")
var/obj/item/clothing/shoes/victim_shoes = victim.get_item_by_slot(ITEM_SLOT_FEET)
if(!victim_shoes || victim_shoes.fastening_type == SHOES_SLIPON)
@@ -35,13 +34,11 @@
victim.Paralyze(20)
victim.Stun(50)
victim.set_jitter_if_lower(500 SECONDS)
- var/obj/item/organ/ears/ears = victim.get_organ_slot(ORGAN_SLOT_EARS)
- ears?.adjustEarDamage(7, 10)
+ victim.sound_damage(7, 20 SECONDS)
to_chat(victim, "HONK")
for(var/mob/living/carbon/victim in lightly_honked)
victim.Knockdown(20)
victim.set_jitter_if_lower(200 SECONDS)
- var/obj/item/organ/ears/ears = victim.get_organ_slot(ORGAN_SLOT_EARS)
- ears?.adjustEarDamage(4, 5)
+ victim.sound_damage(4, 10 SECONDS)
to_chat(victim, "HONK")
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index 22969385579..73bd13ff62c 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -372,6 +372,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_LITERATE" = TRAIT_LITERATE,
"TRAIT_LIVERLESS_METABOLISM" = TRAIT_LIVERLESS_METABOLISM,
"TRAIT_LOUD_BINARY" = TRAIT_LOUD_BINARY,
+ "TRAIT_LUMINESCENT_EYES" = TRAIT_LUMINESCENT_EYES,
"TRAIT_MADNESS_IMMUNE" = TRAIT_MADNESS_IMMUNE,
"TRAIT_MAFIAINITIATE" = TRAIT_MAFIAINITIATE,
"TRAIT_MAGICALLY_GIFTED" = TRAIT_MAGICALLY_GIFTED,
@@ -498,6 +499,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_REAGENT_SCANNER" = TRAIT_REAGENT_SCANNER,
"TRAIT_RECENTLY_BLOCKED_MAGIC" = TRAIT_RECENTLY_BLOCKED_MAGIC,
"TRAIT_RECENTLY_TREATED" = TRAIT_RECENTLY_TREATED,
+ "TRAIT_REFLECTIVE_EYES" = TRAIT_REFLECTIVE_EYES,
"TRAIT_REGEN_SHIELD" = TRAIT_REGEN_SHIELD,
"TRAIT_RELAYING_ATTACKER" = TRAIT_RELAYING_ATTACKER,
"TRAIT_REMOTE_TASTING" = TRAIT_REMOTE_TASTING,
diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm
index 40241195347..eb54b2259dd 100644
--- a/code/_globalvars/traits/admin_tooling.dm
+++ b/code/_globalvars/traits/admin_tooling.dm
@@ -170,6 +170,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_LIMBATTACHMENT" = TRAIT_LIMBATTACHMENT,
"TRAIT_LITERATE" = TRAIT_LITERATE,
"TRAIT_LIVERLESS_METABOLISM" = TRAIT_LIVERLESS_METABOLISM,
+ "TRAIT_LUMINESCENT_EYES" = TRAIT_LUMINESCENT_EYES,
"TRAIT_MADNESS_IMMUNE" = TRAIT_MADNESS_IMMUNE,
"TRAIT_MAGICALLY_GIFTED" = TRAIT_MAGICALLY_GIFTED,
"TRAIT_MARTIAL_ARTS_IMMUNE" = TRAIT_MARTIAL_ARTS_IMMUNE,
@@ -256,6 +257,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_QUICK_CARRY" = TRAIT_QUICK_CARRY,
"TRAIT_QUICKER_CARRY" = TRAIT_QUICKER_CARRY,
"TRAIT_RADIMMUNE" = TRAIT_RADIMMUNE,
+ "TRAIT_REFLECTIVE_EYES" = TRAIT_REFLECTIVE_EYES,
"TRAIT_REMOTE_TASTING" = TRAIT_REMOTE_TASTING,
"TRAIT_RESISTCOLD" = TRAIT_RESISTCOLD,
"TRAIT_RESISTHEAT" = TRAIT_RESISTHEAT,
diff --git a/code/datums/diseases/advance/symptoms/deafness.dm b/code/datums/diseases/advance/symptoms/deafness.dm
index bf096a9fb4a..89755c17c4b 100644
--- a/code/datums/diseases/advance/symptoms/deafness.dm
+++ b/code/datums/diseases/advance/symptoms/deafness.dm
@@ -45,7 +45,6 @@
return
var/mob/living/carbon/infected_mob = advanced_disease.affected_mob
- var/obj/item/organ/ears/ears = infected_mob.get_organ_slot(ORGAN_SLOT_EARS)
switch(advanced_disease.stage)
if(3, 4)
@@ -53,15 +52,18 @@
to_chat(infected_mob, span_warning("[pick("You hear a ringing in your ear.", "Your ears pop.")]"))
if(5)
if(causes_permanent_deafness)
- if(ears.damage < ears.maxHealth)
+ if(!HAS_TRAIT_FROM(infected_mob, TRAIT_DEAF, DISEASE_TRAIT))
to_chat(infected_mob, span_userdanger("Your ears pop painfully and start bleeding!"))
// Just absolutely murder me man
- ears.apply_organ_damage(ears.maxHealth)
+ infected_mob.adjustOrganLoss(ORGAN_SLOT_EARS, INFINITY)
infected_mob.emote("scream")
ADD_TRAIT(infected_mob, TRAIT_DEAF, DISEASE_TRAIT)
else
to_chat(infected_mob, span_userdanger("Your ears pop and begin ringing loudly!"))
- ears.deaf = min(20, ears.deaf + 15)
+ var/obj/item/organ/ears/ears = infected_mob.get_organ_slot(ORGAN_SLOT_EARS)
+ var/deafness_to_add = min(40 SECONDS - ears.temporary_deafness, 30 SECONDS)
+ if(deafness_to_add > 0)
+ ears.adjust_temporary_deafness(deafness_to_add)
/datum/symptom/deafness/on_stage_change(datum/disease/advance/advanced_disease)
. = ..()
diff --git a/code/datums/diseases/advance/symptoms/sensory.dm b/code/datums/diseases/advance/symptoms/sensory.dm
index 2848ec484b3..e0677571599 100644
--- a/code/datums/diseases/advance/symptoms/sensory.dm
+++ b/code/datums/diseases/advance/symptoms/sensory.dm
@@ -96,7 +96,8 @@
if(4, 5)
if(advanced_disease.has_required_infectious_organ(infected_mob, ORGAN_SLOT_EARS))
var/obj/item/organ/ears/ears = infected_mob.get_organ_slot(ORGAN_SLOT_EARS)
- ears.adjustEarDamage(-4, -4)
+ ears?.apply_organ_damage(-4)
+ ears?.adjust_temporary_deafness(-8 SECONDS)
if(!advanced_disease.has_required_infectious_organ(infected_mob, ORGAN_SLOT_EYES))
return
diff --git a/code/datums/elements/earhealing.dm b/code/datums/elements/earhealing.dm
index ac69e8cc18e..33e599eddbe 100644
--- a/code/datums/elements/earhealing.dm
+++ b/code/datums/elements/earhealing.dm
@@ -27,8 +27,9 @@
for(var/i in user_by_item)
var/mob/living/carbon/user = user_by_item[i]
var/obj/item/organ/ears/ears = user.get_organ_slot(ORGAN_SLOT_EARS)
- if(!ears || !ears.damage || (ears.organ_flags & ORGAN_FAILING) || IS_ROBOTIC_ORGAN(ears))
+ if(!ears || (ears.organ_flags & ORGAN_FAILING) || IS_ROBOTIC_ORGAN(ears))
continue
- ears.deaf = max(ears.deaf - 0.25 * seconds_per_tick, (ears.damage < ears.maxHealth ? 0 : 1)) // Do not clear deafness if our ears are too damaged
+
+ ears.adjust_temporary_deafness(-0.5 SECONDS * seconds_per_tick)
ears.apply_organ_damage(-0.025 * seconds_per_tick)
CHECK_TICK
diff --git a/code/modules/antagonists/changeling/powers/shriek.dm b/code/modules/antagonists/changeling/powers/shriek.dm
index 09ebee22d59..2a704e0baac 100644
--- a/code/modules/antagonists/changeling/powers/shriek.dm
+++ b/code/modules/antagonists/changeling/powers/shriek.dm
@@ -18,9 +18,7 @@
if(iscarbon(M))
var/mob/living/carbon/C = M
if(!IS_CHANGELING(C))
- var/obj/item/organ/ears/ears = C.get_organ_slot(ORGAN_SLOT_EARS)
- if(ears)
- ears.adjustEarDamage(0, 30)
+ C.sound_damage(deafen = 30 SECONDS)
C.adjust_confusion(25 SECONDS)
C.set_jitter_if_lower(100 SECONDS)
else
diff --git a/code/modules/antagonists/heretic/items/corrupted_organs.dm b/code/modules/antagonists/heretic/items/corrupted_organs.dm
index 5ffe055de80..59cd6ccc067 100644
--- a/code/modules/antagonists/heretic/items/corrupted_organs.dm
+++ b/code/modules/antagonists/heretic/items/corrupted_organs.dm
@@ -264,8 +264,7 @@
hearer.adjust_timed_status_effect(15 SECONDS, /datum/status_effect/speech/slurring/heretic)
hearer.emote("scream")
hearer.add_mood_event("gates_of_mansus", /datum/mood_event/gates_of_mansus)
- var/obj/item/organ/ears/regret = hearer.get_organ_slot(ORGAN_SLOT_EARS)
- regret?.adjustEarDamage(10,20)
+ hearer.sound_damage(10, 40 SECONDS)
return "[owner.p_Their()] lungs emit [span_hypnophrase(breath_noise)]"
/// It's full of worms
diff --git a/code/modules/antagonists/heretic/magic/mind_gate.dm b/code/modules/antagonists/heretic/magic/mind_gate.dm
index 81215979468..cf6a48f4a62 100644
--- a/code/modules/antagonists/heretic/magic/mind_gate.dm
+++ b/code/modules/antagonists/heretic/magic/mind_gate.dm
@@ -44,16 +44,14 @@
/// The duration of these effects are based on sanity, mainly for flavor but also to make it a weaker alpha strike
var/maximum_duration = 15 SECONDS
- var/mind_gate_duration = ((SANITY_MAXIMUM - cast_on.mob_mood.sanity) / (SANITY_MAXIMUM - SANITY_INSANE)) * maximum_duration
+ var/mind_gate_duration = ((SANITY_MAXIMUM - cast_on.mob_mood.sanity) / (SANITY_MAXIMUM - SANITY_INSANE)) * maximum_duration + 1 SECONDS
to_chat(cast_on, span_warning("Your eyes cry out in pain, your ears bleed and your lips seal! THE MOON SMILES UPON YOU!"))
- cast_on.adjust_temp_blindness(mind_gate_duration + 1 SECONDS)
- cast_on.set_eye_blur_if_lower(mind_gate_duration + 2 SECONDS)
+ cast_on.adjust_temp_blindness(mind_gate_duration)
+ cast_on.set_eye_blur_if_lower(mind_gate_duration + 1 SECONDS)
- var/obj/item/organ/ears/ears = cast_on.get_organ_slot(ORGAN_SLOT_EARS)
- //adjustEarDamage takes deafness duration parameter in one unit per two seconds, instead of the normal time, so we divide by two seconds
- ears?.adjustEarDamage(0, (mind_gate_duration + 1 SECONDS) / (2 SECONDS))
+ cast_on.sound_damage(0, mind_gate_duration)
- cast_on.adjust_silence(mind_gate_duration + 1 SECONDS)
+ cast_on.adjust_silence(mind_gate_duration)
cast_on.add_mood_event("moon_smile", /datum/mood_event/moon_smile)
// Only knocksdown if the target has a low enough sanity
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index 61285e3801b..03f1df6a268 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -740,7 +740,7 @@
else
var/obj/item/organ/ears/has_ears = human_examined.get_organ_slot(ORGAN_SLOT_EARS)
if(has_ears)
- if(has_ears.deaf)
+ if(has_ears.temporary_deafness)
final_message += "\tDamaged eardrums in [examining.p_their()] ear canals."
else
final_message += "\tA set of [has_ears.damage ? "" : "healthy "][has_ears.name]."
diff --git a/code/modules/fishing/fish/types/rift.dm b/code/modules/fishing/fish/types/rift.dm
index ba6a0142ed4..530a32ced23 100644
--- a/code/modules/fishing/fish/types/rift.dm
+++ b/code/modules/fishing/fish/types/rift.dm
@@ -815,7 +815,7 @@
/obj/item/organ/ears/babbelfish/proc/on_drain_magic(mob/user)
to_chat(user, span_noticealien("Your [src] pop as they protect your mind from psychic phenomena!"))
- adjustEarDamage(ddeaf = 20)
+ adjust_temporary_deafness(40 SECONDS)
/obj/item/organ/ears/babbelfish/proc/on_expire(mob/user)
to_chat(user, span_noticealien("Your [src] suddenly burst apart!"))
diff --git a/code/modules/mob/living/basic/bots/honkbots/honkbot.dm b/code/modules/mob/living/basic/bots/honkbots/honkbot.dm
index 68fdb431a96..cc4469f8971 100644
--- a/code/modules/mob/living/basic/bots/honkbots/honkbot.dm
+++ b/code/modules/mob/living/basic/bots/honkbots/honkbot.dm
@@ -83,8 +83,7 @@
if(HAS_TRAIT(current_target, TRAIT_DEAF))
return
- var/obj/item/organ/ears/target_ears = current_target.get_organ_slot(ORGAN_SLOT_EARS)
- target_ears?.adjustEarDamage(0, 5)
+ sound_damage(deafen = 10 SECONDS)
/mob/living/basic/bot/honkbot/ui_data(mob/user)
var/list/data = ..()
diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm
index 3505f7a368a..c6b5f574532 100644
--- a/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm
+++ b/code/modules/mob/living/basic/lavaland/legion/legion_tumour.dm
@@ -31,14 +31,10 @@
. = ..()
animate_pulse()
-/obj/item/organ/legion_tumour/apply_organ_damage(damage_amount, maximum, required_organ_flag)
- var/was_failing = organ_flags & ORGAN_FAILING
- . = ..()
- if (was_failing != (organ_flags & ORGAN_FAILING))
- animate_pulse()
+/obj/item/organ/legion_tumour/on_begin_failure()
+ animate_pulse()
-/obj/item/organ/legion_tumour/set_organ_damage(damage_amount, required_organ_flag)
- . = ..()
+/obj/item/organ/legion_tumour/on_failure_recovery()
animate_pulse()
/// Do a heartbeat animation depending on if we're failing or not
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index 1a35fe9cedf..a1e5affe573 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -25,8 +25,6 @@
var/mob/living/brain/brainmob = null
/// If it's a fake brain with no brainmob assigned. Feedback messages will be faked as if it does have a brainmob. See changelings & dullahans.
var/decoy_override = FALSE
- /// Two variables necessary for calculating whether we get a brain trauma or not
- var/damage_delta = 0
var/list/datum/brain_trauma/traumas = list()
@@ -345,34 +343,42 @@
owner.investigate_log("has been killed by brain damage.", INVESTIGATE_DEATHS)
owner.death()
-/obj/item/organ/brain/check_damage_thresholds(mob/M)
+/obj/item/organ/brain/apply_organ_damage(damage_amount, maximum = maxHealth, required_organ_flag = NONE)
. = ..()
+ var/delta_dam = . //for the sake of clarity
+ if(delta_dam <= 0 || damage < BRAIN_DAMAGE_MILD)
+ return
+
+ if(prob(delta_dam * (1 + max(0, (damage - BRAIN_DAMAGE_MILD)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1% //learn how to do your bloody math properly goddamnit
+ gain_trauma_type(BRAIN_TRAUMA_MILD, natural_gain = TRUE)
+
+ var/is_boosted = (owner && HAS_TRAIT(owner, TRAIT_SPECIAL_TRAUMA_BOOST))
+ if(damage < BRAIN_DAMAGE_SEVERE)
+ return
+ if(prob(delta_dam * (1 + max(0, (damage - BRAIN_DAMAGE_SEVERE)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1%
+ if(prob(20 + (is_boosted * 30)))
+ gain_trauma_type(BRAIN_TRAUMA_SPECIAL, is_boosted ? TRAUMA_RESILIENCE_SURGERY : null, natural_gain = TRUE)
+ else
+ gain_trauma_type(BRAIN_TRAUMA_SEVERE, natural_gain = TRUE)
+
+/obj/item/organ/brain/check_damage_thresholds()
+ . = ..()
+ if(!owner)
+ return
// If we crossed blinking brain damage thresholds either way, update our blinking
- if (owner && ((prev_damage > BRAIN_DAMAGE_ASYNC_BLINKING && damage < BRAIN_DAMAGE_ASYNC_BLINKING) || (prev_damage < BRAIN_DAMAGE_ASYNC_BLINKING && damage > BRAIN_DAMAGE_ASYNC_BLINKING)))
+ if((prev_damage >= BRAIN_DAMAGE_ASYNC_BLINKING && damage < BRAIN_DAMAGE_ASYNC_BLINKING) || (prev_damage < BRAIN_DAMAGE_ASYNC_BLINKING && damage >= BRAIN_DAMAGE_ASYNC_BLINKING))
var/obj/item/organ/eyes/eyes = owner.get_organ_slot(ORGAN_SLOT_EYES)
if(eyes?.blink_animation)
eyes.animate_eyelids(owner)
+ if(damage >= 60 && prev_damage < 60)
+ owner.add_mood_event("brain_damage", /datum/mood_event/brain_damage)
+ else if(prev_damage >= 60 && damage < 60)
+ owner.clear_mood_event("brain_damage")
// If we're not more injured than before, return without gambling for a trauma
if(damage <= prev_damage)
return
- damage_delta = damage - prev_damage
- if(damage > BRAIN_DAMAGE_MILD)
- if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_MILD)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1% //learn how to do your bloody math properly goddamnit
- gain_trauma_type(BRAIN_TRAUMA_MILD, natural_gain = TRUE)
-
- var/is_boosted = (owner && HAS_TRAIT(owner, TRAIT_SPECIAL_TRAUMA_BOOST))
- if(damage > BRAIN_DAMAGE_SEVERE)
- if(prob(damage_delta * (1 + max(0, (damage - BRAIN_DAMAGE_SEVERE)/100)))) //Base chance is the hit damage; for every point of damage past the threshold the chance is increased by 1%
- if(prob(20 + (is_boosted * 30)))
- gain_trauma_type(BRAIN_TRAUMA_SPECIAL, is_boosted ? TRAUMA_RESILIENCE_SURGERY : null, natural_gain = TRUE)
- else
- gain_trauma_type(BRAIN_TRAUMA_SEVERE, natural_gain = TRUE)
-
- if (!owner || owner.stat > UNCONSCIOUS)
- return
-
// Conscious or soft-crit
var/brain_message
if(prev_damage < BRAIN_DAMAGE_MILD && damage >= BRAIN_DAMAGE_MILD)
@@ -665,15 +671,6 @@
amount_cured++
return amount_cured
-/obj/item/organ/brain/apply_organ_damage(damage_amount, maximum = maxHealth, required_organ_flag = NONE)
- . = ..()
- if(!owner)
- return FALSE
- if(damage >= 60)
- owner.add_mood_event("brain_damage", /datum/mood_event/brain_damage)
- else
- owner.clear_mood_event("brain_damage")
-
/// This proc lets the mob's brain decide what bodypart to attack with in an unarmed strike.
/obj/item/organ/brain/proc/get_attacking_limb(mob/living/carbon/human/target)
var/obj/item/bodypart/arm/active_hand = owner.get_active_hand()
diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm
index e5c5731dc03..e0892cbaf8e 100644
--- a/code/modules/mob/living/carbon/alien/alien_defense.dm
+++ b/code/modules/mob/living/carbon/alien/alien_defense.dm
@@ -71,22 +71,19 @@ In all, this is a lot like the monkey code. /N
if(!. || QDELETED(src))
return FALSE
- var/obj/item/organ/ears/ears = get_organ_slot(ORGAN_SLOT_EARS)
switch (severity)
if (EXPLODE_DEVASTATE)
gib(DROP_ALL_REMAINS)
if (EXPLODE_HEAVY)
take_overall_damage(60, 60)
- if(ears)
- ears.adjustEarDamage(30,120)
+ sound_damage(30, 240 SECONDS)
if(EXPLODE_LIGHT)
take_overall_damage(30,0)
if(prob(50))
Unconscious(20)
- if(ears)
- ears.adjustEarDamage(15,60)
+ sound_damage(15, 120 SECONDS)
return TRUE
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 518ba53e769..ed9c794ce54 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -16,6 +16,17 @@
if(isclothing(wear_mask)) //Mask
. += wear_mask.flash_protect
+/mob/living/carbon/sound_damage(damage, deafen)
+ if(HAS_TRAIT(src, TRAIT_GODMODE))
+ return
+ var/obj/item/organ/ears/ears = get_organ_slot(ORGAN_SLOT_EARS)
+ if(QDELETED(ears))
+ return
+ if(damage)
+ ears.apply_organ_damage(damage * ears.damage_multiplier)
+ if(deafen)
+ ears.adjust_temporary_deafness(deafen)
+
/mob/living/carbon/get_ear_protection()
. = ..()
if(HAS_TRAIT(src, TRAIT_DEAF))
@@ -523,8 +534,8 @@
if(ears && (deafen_pwr || damage_pwr))
var/ear_damage = damage_pwr * effect_amount
- var/deaf = deafen_pwr * effect_amount
- ears.adjustEarDamage(ear_damage,deaf)
+ var/deaf = deafen_pwr * effect_amount * 2 SECONDS
+ sound_damage(ear_damage, deaf)
. = effect_amount //how soundbanged we are
SEND_SOUND(src, sound('sound/items/weapons/flash_ring.ogg',0,1,0,250))
diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm
index 78f5d38205b..8a5f9abd050 100644
--- a/code/modules/mob/living/carbon/carbon_update_icons.dm
+++ b/code/modules/mob/living/carbon/carbon_update_icons.dm
@@ -20,7 +20,7 @@
if(OFFSET_HEAD)
update_worn_head()
if(OFFSET_FACE)
- dna?.species?.update_face_offset(src) // updates eye and lipstick icon
+ update_face_offset() // updates eye and lipstick icon
update_worn_mask()
if(OFFSET_BELT)
update_worn_belt()
@@ -49,7 +49,6 @@
SEND_SIGNAL(src, COMSIG_CARBON_REMOVE_OVERLAY, cache_index, I)
/mob/living/carbon/update_body(is_creating = FALSE)
- dna?.species.handle_body(src)
update_body_parts(is_creating)
/mob/living/carbon/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
@@ -504,6 +503,9 @@
apply_overlay(BODYPARTS_LAYER)
+/mob/living/carbon/proc/update_face_offset()
+ return
+
/////////////////////////
// Limb Icon Cache 2.0 //
/////////////////////////
diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm
index 485dc3ca0f8..6db14908e70 100644
--- a/code/modules/mob/living/carbon/human/_species.dm
+++ b/code/modules/mob/living/carbon/human/_species.dm
@@ -485,84 +485,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
human.living_flags &= ~STOP_OVERLAY_UPDATE_BODY_PARTS
-/**
- * Handles the body of a human
- *
- * Handles lipstick, having no eyes, eye color, undergarnments like underwear, undershirts, and socks, and body layers.
- * Arguments:
- * * species_human - Human, whoever we're handling the body for
- */
-/datum/species/proc/handle_body(mob/living/carbon/human/species_human)
- species_human.remove_overlay(BODY_LAYER)
- species_human.remove_overlay(EYES_LAYER)
-
- if(HAS_TRAIT(species_human, TRAIT_INVISIBLE_MAN))
- return
-
- if(!HAS_TRAIT(species_human, TRAIT_HUSK))
- var/obj/item/bodypart/head/noggin = species_human.get_bodypart(BODY_ZONE_HEAD)
- if(noggin?.head_flags & HEAD_EYESPRITES)
- // eyes (missing eye sprites get handled by the head itself, but sadly we have to do this stupid shit here, for now)
- var/obj/item/organ/eyes/eye_organ = species_human.get_organ_slot(ORGAN_SLOT_EYES)
- if(eye_organ)
- eye_organ.refresh(call_update = FALSE)
- species_human.overlays_standing[EYES_LAYER] = eye_organ.generate_body_overlay(species_human)
- species_human.apply_overlay(EYES_LAYER)
-
- if(HAS_TRAIT(species_human, TRAIT_NO_UNDERWEAR))
- return
-
- // Underwear, Undershirts & Socks
- var/list/standing = list()
- if(species_human.underwear)
- var/datum/sprite_accessory/underwear/underwear = SSaccessories.underwear_list[species_human.underwear]
- var/mutable_appearance/underwear_overlay
- if(underwear)
- if(species_human.dna.species.sexes && species_human.physique == FEMALE && (underwear.gender == MALE))
- underwear_overlay = mutable_appearance(wear_female_version(underwear.icon_state, underwear.icon, FEMALE_UNIFORM_FULL), layer = -BODY_LAYER)
- else
- underwear_overlay = mutable_appearance(underwear.icon, underwear.icon_state, -BODY_LAYER)
- if(!underwear.use_static)
- underwear_overlay.color = species_human.underwear_color
- standing += underwear_overlay
-
- if(species_human.undershirt)
- var/datum/sprite_accessory/undershirt/undershirt = SSaccessories.undershirt_list[species_human.undershirt]
- if(undershirt)
- var/mutable_appearance/working_shirt
- if(species_human.dna.species.sexes && species_human.physique == FEMALE)
- working_shirt = mutable_appearance(wear_female_version(undershirt.icon_state, undershirt.icon), layer = -BODY_LAYER)
- else
- working_shirt = mutable_appearance(undershirt.icon, undershirt.icon_state, layer = -BODY_LAYER)
- standing += working_shirt
-
- if(species_human.socks && species_human.num_legs >= 2 && !(species_human.bodyshape & BODYSHAPE_DIGITIGRADE))
- var/datum/sprite_accessory/socks/socks = SSaccessories.socks_list[species_human.socks]
- if(socks)
- standing += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER)
-
- if(standing.len)
- species_human.overlays_standing[BODY_LAYER] = standing
-
- species_human.apply_overlay(BODY_LAYER)
-
-/// Updates face (as of now, only eye) offsets
-/datum/species/proc/update_face_offset(mob/living/carbon/human/species_human)
- var/list/eye_overlays = species_human.overlays_standing[EYES_LAYER]
- species_human.remove_overlay(EYES_LAYER)
-
- if(HAS_TRAIT(species_human, TRAIT_INVISIBLE_MAN) || HAS_TRAIT(species_human, TRAIT_HUSK) || !length(eye_overlays))
- return
-
- var/obj/item/bodypart/head/noggin = species_human.get_bodypart(BODY_ZONE_HEAD)
- for (var/mutable_appearance/overlay as anything in eye_overlays)
- overlay.pixel_w = 0
- overlay.pixel_z = 0
- noggin.worn_face_offset.apply_offset(overlay)
-
- species_human.overlays_standing[EYES_LAYER] = eye_overlays
- species_human.apply_overlay(EYES_LAYER)
-
// This exists so sprite accessories can still be per-layer without having to include that layer's
// number in their sprite name, which causes issues when those numbers change.
/datum/species/proc/mutant_bodyparts_layertext(layer)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index d4cac5e8c9a..95bb123c67a 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -271,7 +271,6 @@
//200 max knockdown for EXPLODE_HEAVY
//160 max knockdown for EXPLODE_LIGHT
- var/obj/item/organ/ears/ears = get_organ_slot(ORGAN_SLOT_EARS)
switch (severity)
if (EXPLODE_DEVASTATE)
if(bomb_armor < EXPLODE_GIB_THRESHOLD) //gibs the mob if their bomb armor is lower than EXPLODE_GIB_THRESHOLD
@@ -299,8 +298,8 @@
brute_loss = 30*(2 - round(bomb_armor*0.01, 0.05))
burn_loss = brute_loss //damage gets reduced from 120 to up to 60 combined brute+burn
damage_clothes(200 - bomb_armor, BRUTE, BOMB)
- if (ears && !HAS_TRAIT_FROM_ONLY(src, TRAIT_DEAF, EAR_DAMAGE))
- ears.adjustEarDamage(30, 120)
+ if (!HAS_TRAIT_FROM(src, TRAIT_DEAF, EAR_DAMAGE))
+ sound_damage(30, 240 SECONDS)
Unconscious(20) //short amount of time for follow up attacks against elusive enemies like wizards
Knockdown(200 - (bomb_armor * 1.6)) //between ~4 and ~20 seconds of knockdown depending on bomb armor
@@ -309,8 +308,8 @@
if(bomb_armor)
brute_loss = 15*(2 - round(bomb_armor*0.01, 0.05))
damage_clothes(max(50 - bomb_armor, 0), BRUTE, BOMB)
- if (ears && !HAS_TRAIT_FROM_ONLY(src, TRAIT_DEAF, EAR_DAMAGE))
- ears.adjustEarDamage(15,60)
+ if (!HAS_TRAIT_FROM(src, TRAIT_DEAF, EAR_DAMAGE))
+ sound_damage(15, 120 SECONDS)
Knockdown(160 - (bomb_armor * 1.6)) //100 bomb armor will prevent knockdown altogether
take_overall_damage(brute_loss,burn_loss)
diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm
index 044315bd2b8..64698c9422a 100644
--- a/code/modules/mob/living/carbon/human/human_update_icons.dm
+++ b/code/modules/mob/living/carbon/human/human_update_icons.dm
@@ -859,6 +859,82 @@ generate/load female uniform sprites matching all previously decided variables
observers = null
break
+/mob/living/carbon/human/update_body(is_creating = FALSE)
+ update_eyes()
+ update_underwear()
+ return ..()
+
+/mob/living/carbon/human/proc/update_underwear()
+ remove_overlay(BODY_LAYER)
+ if(HAS_TRAIT(src, TRAIT_HUSK) || HAS_TRAIT(src, TRAIT_INVISIBLE_MAN))
+ return
+ // Underwear, Undershirts & Socks
+ var/list/standing = list()
+ if(underwear)
+ var/datum/sprite_accessory/underwear/undie_accessory = SSaccessories.underwear_list[underwear]
+ var/mutable_appearance/underwear_overlay
+ if(undie_accessory)
+ if(dna.species.sexes && physique == FEMALE && (undie_accessory.gender == MALE))
+ underwear_overlay = mutable_appearance(wear_female_version(undie_accessory.icon_state, undie_accessory.icon, FEMALE_UNIFORM_FULL), layer = -BODY_LAYER)
+ else
+ underwear_overlay = mutable_appearance(undie_accessory.icon, undie_accessory.icon_state, -BODY_LAYER)
+ if(!undie_accessory.use_static)
+ underwear_overlay.color = underwear_color
+ standing += underwear_overlay
+
+ if(undershirt)
+ var/datum/sprite_accessory/undershirt/undie_accessory = SSaccessories.undershirt_list[undershirt]
+ if(undie_accessory)
+ var/mutable_appearance/working_shirt
+ if(dna.species.sexes && physique == FEMALE)
+ working_shirt = mutable_appearance(wear_female_version(undie_accessory.icon_state, undie_accessory.icon), layer = -BODY_LAYER)
+ else
+ working_shirt = mutable_appearance(undie_accessory.icon, undie_accessory.icon_state, layer = -BODY_LAYER)
+ standing += working_shirt
+
+ if(socks && num_legs >= 2 && !(bodyshape & BODYSHAPE_DIGITIGRADE))
+ var/datum/sprite_accessory/socks/undie_accessory = SSaccessories.socks_list[socks]
+ if(undie_accessory)
+ standing += mutable_appearance(undie_accessory.icon, undie_accessory.icon_state, -BODY_LAYER)
+
+ if(standing.len)
+ overlays_standing[BODY_LAYER] = standing
+
+ apply_overlay(BODY_LAYER)
+
+/mob/living/carbon/human/proc/update_eyes()
+ remove_overlay(EYES_LAYER)
+ if(HAS_TRAIT(src, TRAIT_HUSK) || HAS_TRAIT(src, TRAIT_INVISIBLE_MAN))
+ return
+ var/obj/item/bodypart/head/noggin = get_bodypart(BODY_ZONE_HEAD)
+ if(!(noggin?.head_flags & HEAD_EYESPRITES))
+ return
+ // eyes (missing eye sprites get handled by the head itself, but sadly we have to do this stupid shit here, for now)
+ var/obj/item/organ/eyes/eye_organ = get_organ_slot(ORGAN_SLOT_EYES)
+ if(eye_organ)
+ eye_organ.refresh(call_update = FALSE)
+ overlays_standing[EYES_LAYER] = eye_organ.generate_body_overlay(src)
+ apply_overlay(EYES_LAYER)
+
+/// Updates face (as of now, only eye) offsets
+/mob/living/carbon/human/update_face_offset()
+ var/list/eye_overlays = overlays_standing[EYES_LAYER]
+
+ if(HAS_TRAIT(src, TRAIT_INVISIBLE_MAN) || HAS_TRAIT(src, TRAIT_HUSK) || !length(eye_overlays))
+ return
+
+ remove_overlay(EYES_LAYER)
+
+ var/obj/item/bodypart/head/noggin = get_bodypart(BODY_ZONE_HEAD)
+ for (var/mutable_appearance/overlay as anything in eye_overlays)
+ overlay.pixel_w = 0
+ overlay.pixel_z = 0
+ noggin.worn_face_offset.apply_offset(overlay)
+
+ overlays_standing[EYES_LAYER] = eye_overlays
+ apply_overlay(EYES_LAYER)
+
+
// Only renders the head of the human
/mob/living/carbon/human/proc/update_body_parts_head_only(update_limb_data)
if(!dna?.species)
diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm
index e288bb6b146..f15f65c1972 100644
--- a/code/modules/mob/living/carbon/human/species_types/felinid.dm
+++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm
@@ -6,6 +6,7 @@
mutantbrain = /obj/item/organ/brain/felinid
mutanttongue = /obj/item/organ/tongue/cat
mutantears = /obj/item/organ/ears/cat
+ mutanteyes = /obj/item/organ/eyes/felinid
mutant_organs = list(
/obj/item/organ/tail/cat = "Cat",
)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 3496ffabf3e..821ad98dd78 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -35,6 +35,10 @@
/mob/living/proc/get_eye_protection()
return 0
+///A easy to use proc to apply both organ damage and temporary deafness at once, so you don't have to get the ears everytime.
+/mob/living/proc/sound_damage(damage, deafen)
+ return
+
//this returns the mob's protection against ear damage (0:no protection; 1: some ear protection; 2: has no ears)
/mob/living/proc/get_ear_protection()
var/turf/current_turf = get_turf(src)
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index 9a01339012d..9dda07ae412 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -829,7 +829,7 @@
if(eyes.apply_organ_damage(-2 * REM * seconds_per_tick * normalise_creation_purity(), required_organ_flag = affected_organ_flags))
. = UPDATE_MOB_HEALTH
// If our eyes are seriously damaged, we have a probability of causing eye blur while healing depending on purity
- if(eyes.damaged && IS_ORGANIC_ORGAN(eyes) && SPT_PROB(16 - min(normalized_purity * 6, 12), seconds_per_tick))
+ if(eyes.damage >= eyes.low_threshold && IS_ORGANIC_ORGAN(eyes) && SPT_PROB(16 - min(normalized_purity * 6, 12), seconds_per_tick))
// While healing, gives some eye blur
if(affected_mob.is_blind_from(EYE_DAMAGE))
to_chat(affected_mob, span_warning("Your vision slowly returns..."))
@@ -929,7 +929,9 @@
var/obj/item/organ/ears/ears = affected_mob.get_organ_slot(ORGAN_SLOT_EARS)
if(!ears)
return
- ears.adjustEarDamage(-4 * REM * seconds_per_tick * normalise_creation_purity(), -4 * REM * seconds_per_tick * normalise_creation_purity())
+ var/multiplier = REM * seconds_per_tick * normalise_creation_purity()
+ ears.apply_organ_damage(-4 * multiplier)
+ ears.adjust_temporary_deafness(-8 * multiplier)
return UPDATE_MOB_HEALTH
/datum/reagent/medicine/inacusiate/on_mob_delete(mob/living/affected_mob)
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 48d16e3644c..9d6baed2e51 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -3230,8 +3230,7 @@
RegisterSignal(affected_human, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(on_organ_removed))
var/obj/item/organ/eyes/eyes = affected_human.get_organ_slot(ORGAN_SLOT_EYES)
if (eyes && !IS_ROBOTIC_ORGAN(eyes))
- prev_ignore_lighting = eyes.overlay_ignore_lighting
- eyes.overlay_ignore_lighting = TRUE
+ ADD_TRAIT(affected_human, TRAIT_LUMINESCENT_EYES, REF(src))
/datum/reagent/luminescent_fluid/on_mob_end_metabolize(mob/living/affected_mob)
. = ..()
@@ -3243,7 +3242,7 @@
affected_human.remove_eye_color(EYE_COLOR_LUMINESCENT_PRIORITY)
var/obj/item/organ/eyes/eyes = affected_human.get_organ_slot(ORGAN_SLOT_EYES)
if (eyes && !IS_ROBOTIC_ORGAN(eyes) && !overdosed)
- eyes.overlay_ignore_lighting = prev_ignore_lighting
+ REMOVE_TRAIT(affected_human, TRAIT_LUMINESCENT_EYES, REF(src))
/datum/reagent/luminescent_fluid/on_mob_life(mob/living/affected_mob, seconds_per_tick, times_fired)
. = ..()
@@ -3262,14 +3261,13 @@
SIGNAL_HANDLER
if (istype(new_eyes) && !IS_ROBOTIC_ORGAN(new_eyes))
- prev_ignore_lighting = new_eyes.overlay_ignore_lighting
- new_eyes.overlay_ignore_lighting = TRUE
+ ADD_TRAIT(source, TRAIT_LUMINESCENT_EYES, REF(src))
/datum/reagent/luminescent_fluid/proc/on_organ_removed(mob/living/source, obj/item/organ/eyes/old_eyes)
SIGNAL_HANDLER
if (istype(old_eyes) && !IS_ROBOTIC_ORGAN(old_eyes) && !overdosed)
- old_eyes.overlay_ignore_lighting = prev_ignore_lighting
+ REMOVE_TRAIT(source, TRAIT_LUMINESCENT_EYES, REF(src))
/datum/reagent/luminescent_fluid/overdose_start(mob/living/affected_mob)
. = ..()
diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm
index 79524d43a12..5dc46ddea0c 100644
--- a/code/modules/surgery/bodyparts/head.dm
+++ b/code/modules/surgery/bodyparts/head.dm
@@ -176,35 +176,37 @@
. += get_hair_and_lips_icon(dropped)
// We need to get the eyes if we are dropped (ugh)
- if(dropped)
- var/obj/item/organ/eyes/eyes = locate(/obj/item/organ/eyes) in src
- // This is a bit of copy/paste code from eyes.dm:generate_body_overlay
- if(eyes?.eye_icon_state && (head_flags & HEAD_EYESPRITES))
- var/image/eye_left = image('icons/mob/human/human_face.dmi', "[eyes.eye_icon_state]_l", -EYES_LAYER, SOUTH)
- var/image/eye_right = image('icons/mob/human/human_face.dmi', "[eyes.eye_icon_state]_r", -EYES_LAYER, SOUTH)
- if(head_flags & HEAD_EYECOLOR)
- if(eyes.eye_color_left)
- eye_left.color = eyes.eye_color_left
- if(eyes.eye_color_right)
- eye_right.color = eyes.eye_color_right
- if(eyes.overlay_ignore_lighting)
- eye_left.overlays += emissive_appearance(eye_left.icon, eye_left.icon_state, src, alpha = eye_left.alpha)
- eye_right.overlays += emissive_appearance(eye_right.icon, eye_right.icon_state, src, alpha = eye_right.alpha)
- else if(blocks_emissive != EMISSIVE_BLOCK_NONE)
- var/atom/location = loc || owner || src
- eye_left.overlays += emissive_blocker(eye_left.icon, eye_left.icon_state, location, alpha = eye_left.alpha)
- eye_right.overlays += emissive_blocker(eye_right.icon, eye_right.icon_state, location, alpha = eye_right.alpha)
- if(worn_face_offset)
- worn_face_offset.apply_offset(eye_left)
- worn_face_offset.apply_offset(eye_right)
- . += eye_left
- . += eye_right
- else if(!eyes && (head_flags & HEAD_EYEHOLES))
- var/image/no_eyes = image('icons/mob/human/human_face.dmi', "eyes_missing", -EYES_LAYER, SOUTH)
- worn_face_offset?.apply_offset(no_eyes)
- . += no_eyes
+ if(!dropped)
+ return
+ var/obj/item/organ/eyes/eyes = locate(/obj/item/organ/eyes) in src
+ // This is a bit of copy/paste code from eyes.dm:generate_body_overlay
+ if(eyes?.eye_icon_state && (head_flags & HEAD_EYESPRITES))
+ var/image/eye_left = image('icons/mob/human/human_face.dmi', "[eyes.eye_icon_state]_l", -EYES_LAYER, SOUTH)
+ var/image/eye_right = image('icons/mob/human/human_face.dmi', "[eyes.eye_icon_state]_r", -EYES_LAYER, SOUTH)
+ if(head_flags & HEAD_EYECOLOR)
+ if(eyes.eye_color_left)
+ eye_left.color = eyes.eye_color_left
+ if(eyes.eye_color_right)
+ eye_right.color = eyes.eye_color_right
- return
+ var/list/emissive_overlays = eyes.get_emissive_overlays(eye_left, eye_right, src)
+ if(length(emissive_overlays))
+ eye_left.overlays += emissive_overlays[1] //left first
+ eye_right.overlays += emissive_overlays[2] //right second
+ else if(blocks_emissive != EMISSIVE_BLOCK_NONE)
+ var/atom/location = loc || owner || src
+ eye_left.overlays += emissive_blocker(eye_left.icon, eye_left.icon_state, location, alpha = eye_left.alpha)
+ eye_right.overlays += emissive_blocker(eye_right.icon, eye_right.icon_state, location, alpha = eye_right.alpha)
+
+ if(worn_face_offset)
+ worn_face_offset.apply_offset(eye_left)
+ worn_face_offset.apply_offset(eye_right)
+ . += eye_left
+ . += eye_right
+ else if(!eyes && (head_flags & HEAD_EYEHOLES))
+ var/image/no_eyes = image('icons/mob/human/human_face.dmi', "eyes_missing", -EYES_LAYER, SOUTH)
+ worn_face_offset?.apply_offset(no_eyes)
+ . += no_eyes
/obj/item/bodypart/head/Initialize(mapload)
. = ..()
diff --git a/code/modules/surgery/ear_surgery.dm b/code/modules/surgery/ear_surgery.dm
index 9f41949f763..41afe23eb5f 100644
--- a/code/modules/surgery/ear_surgery.dm
+++ b/code/modules/surgery/ear_surgery.dm
@@ -45,8 +45,10 @@
span_notice("[user] completes the surgery on [target]'s ears."),
)
display_pain(target, "Your head swims, but it seems like you can feel your hearing coming back!")
- target_ears.deaf = (20) //deafness works off ticks, so this should work out to about 30-40s
target_ears.set_organ_damage(0)
+ ///makes you temporarily deaf for a duration post-surgery
+ var/deaf_change = 40 SECONDS - target_ears.temporary_deafness
+ target_ears.adjust_temporary_deafness(deaf_change)
return ..()
/datum/surgery_step/fix_ears/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm
index 7e969ee4843..3b2edfea15d 100644
--- a/code/modules/surgery/organs/_organ.dm
+++ b/code/modules/surgery/organs/_organ.dm
@@ -117,7 +117,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
/// Add a Trait to an organ that it will give its owner.
/obj/item/organ/proc/add_organ_trait(trait)
- LAZYADD(organ_traits, trait)
+ LAZYOR(organ_traits, trait)
if(isnull(owner))
return
ADD_TRAIT(owner, trait, REF(src))
@@ -251,14 +251,9 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
damage = clamp(damage + damage_amount, 0, maximum)
SEND_SIGNAL(src, COMSIG_ORGAN_ADJUST_DAMAGE, damage_amount, maximum, required_organ_flag)
. = (prev_damage - damage) // return net damage
- var/message = check_damage_thresholds(owner)
+ var/message = check_damage_thresholds()
prev_damage = damage
- if(damage >= maxHealth)
- organ_flags |= ORGAN_FAILING
- else
- organ_flags &= ~ORGAN_FAILING
-
if(message && owner && owner.stat <= SOFT_CRIT)
to_chat(owner, message)
@@ -272,24 +267,66 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
* description: By checking our current damage against our previous damage, we can decide whether we've passed an organ threshold.
* If we have, send the corresponding threshold message to the owner, if such a message exists.
*/
-/obj/item/organ/proc/check_damage_thresholds(mob/organ_owner)
+/obj/item/organ/proc/check_damage_thresholds()
+ SHOULD_CALL_PARENT(TRUE)
if(damage == prev_damage)
return
var/delta = damage - prev_damage
+ var/message = ""
if(delta > 0)
- if(damage >= maxHealth)
- return now_failing
- if(damage > high_threshold && prev_damage <= high_threshold)
- return high_threshold_passed
if(damage > low_threshold && prev_damage <= low_threshold)
- return low_threshold_passed
- else
- if(prev_damage > low_threshold && damage <= low_threshold)
- return low_threshold_cleared
- if(prev_damage > high_threshold && damage <= high_threshold)
- return high_threshold_cleared
- if(prev_damage == maxHealth)
- return now_fixed
+ on_low_damage_received()
+ message = low_threshold_passed
+ if(damage > high_threshold && prev_damage <= high_threshold)
+ on_high_damage_received()
+ message = high_threshold_passed
+ if(damage >= maxHealth)
+ organ_flags |= ORGAN_FAILING
+ on_begin_failure()
+ message = now_failing
+ return message
+
+ if(prev_damage == maxHealth)
+ organ_flags &= ~ORGAN_FAILING
+ on_failure_recovery()
+ message = now_fixed
+ if(prev_damage > high_threshold && damage <= high_threshold)
+ on_high_damage_healed()
+ message = high_threshold_cleared
+ if(prev_damage > low_threshold && damage <= low_threshold)
+ on_low_damage_healed()
+ message = low_threshold_cleared
+ return message
+
+/**
+ * Called when the damage surpasses the low damage threshold.
+ *
+ * This and other procs like this one merely exist to make it easier to keep a standard on
+ * damage thresholds for organs. This doesn't mean you cannot make custom thresholds for various stuff,
+ * and you're more than welcome to improve or refactor any portion of the code around these mechanics
+ */
+/obj/item/organ/proc/on_low_damage_received()
+ return
+
+///Called when the damage goes below the low damage threshold
+/obj/item/organ/proc/on_low_damage_healed()
+ return
+
+///Called when the damage surpasses the high damage threshold
+/obj/item/organ/proc/on_high_damage_received()
+ return
+
+///Called when the damage goes below the high damage threshold
+/obj/item/organ/proc/on_high_damage_healed()
+ return
+
+///Called when the organ enters failing stage
+/obj/item/organ/proc/on_begin_failure()
+ return
+
+///Called when the organ recovers from failing stage
+/obj/item/organ/proc/on_failure_recovery()
+ return
//Looking for brains?
//Try code/modules/mob/living/carbon/brain/brain_item.dm
@@ -313,9 +350,9 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
dna.species.regenerate_organs(src, replace_current = FALSE)
set_heartattack(FALSE)
- // Ears have aditional vаr "deaf", need to update it too
+ // Ears have aditional var "deaf", need to update it too
var/obj/item/organ/ears/ears = get_organ_slot(ORGAN_SLOT_EARS)
- ears?.adjustEarDamage(0, -INFINITY) // full heal ears deafness
+ ears.adjust_temporary_deafness(-INFINITY)
return
@@ -352,7 +389,8 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
if(!ears)
ears = new()
ears.Insert(src)
- ears.adjustEarDamage(-INFINITY, -INFINITY) // actually do: set_organ_damage(0) and deaf = 0
+ ears.set_organ_damage(0)
+ ears.adjust_temporary_deafness(-INFINITY)
///Organs don't die instantly, and neither should you when you get fucked up
/obj/item/organ/proc/handle_failing_organs(seconds_per_tick)
diff --git a/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm b/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm
index 9763b22e4b0..19ff1031d79 100644
--- a/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm
+++ b/code/modules/surgery/organs/internal/cyberimp/augments_eyes.dm
@@ -18,32 +18,36 @@
/// Eyecolor from the HUD
var/hud_color = "#3CB8A5"
+/obj/item/organ/cyberimp/eyes/hud/Initialize(mapload)
+ . = ..()
+ if(toggled_on)
+ for(var/hud_trait in HUD_traits)
+ add_organ_trait(hud_trait)
+
/obj/item/organ/cyberimp/eyes/hud/proc/toggle_hud(mob/living/carbon/human/eye_owner)
if(toggled_on)
toggled_on = FALSE
- eye_owner.remove_traits(HUD_traits, ORGAN_TRAIT)
+ for(var/hud_trait in HUD_traits)
+ remove_organ_trait(hud_trait)
balloon_alert(eye_owner, "hud disabled")
if(hud_color)
eye_owner.remove_eye_color(EYE_COLOR_HUD_PRIORITY)
return
toggled_on = TRUE
- eye_owner.add_traits(HUD_traits, ORGAN_TRAIT)
+ for(var/hud_trait in HUD_traits)
+ add_organ_trait(hud_trait)
balloon_alert(eye_owner, "hud enabled")
if(hud_color)
eye_owner.add_eye_color_right(hud_color, EYE_COLOR_HUD_PRIORITY)
/obj/item/organ/cyberimp/eyes/hud/on_mob_insert(mob/living/carbon/human/eye_owner, special = FALSE, movement_flags)
. = ..()
- eye_owner.add_traits(HUD_traits, ORGAN_TRAIT)
- toggled_on = TRUE
- if(hud_color)
+ if(toggled_on && hud_color)
eye_owner.add_eye_color_right(hud_color, EYE_COLOR_HUD_PRIORITY, !special)
/obj/item/organ/cyberimp/eyes/hud/on_mob_remove(mob/living/carbon/human/eye_owner, special, movement_flags)
. = ..()
- eye_owner.remove_traits(HUD_traits, ORGAN_TRAIT)
- toggled_on = FALSE
- if(hud_color)
+ if(toggled_on && hud_color)
eye_owner.remove_eye_color(EYE_COLOR_HUD_PRIORITY, !special)
/obj/item/organ/cyberimp/eyes/hud/medical
diff --git a/code/modules/surgery/organs/internal/ears/_ears.dm b/code/modules/surgery/organs/internal/ears/_ears.dm
index da1d7faff63..e50961a5d8b 100644
--- a/code/modules/surgery/organs/internal/ears/_ears.dm
+++ b/code/modules/surgery/organs/internal/ears/_ears.dm
@@ -14,8 +14,8 @@
now_fixed = span_info("Noise slowly begins filling your ears once more.")
low_threshold_cleared = span_info("The ringing in your ears has died down.")
- /// `deaf` measures "ticks" of deafness. While > 0, the person is unable to hear anything.
- var/deaf = 0
+ /// temporary deafness, measured in seconds. While > 0, the person is unable to hear anything.
+ var/temporary_deafness = 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
@@ -39,23 +39,20 @@
// no healing if failing
if(organ_flags & ORGAN_FAILING)
return
- adjustEarDamage(0, -0.5 * seconds_per_tick)
+ adjust_temporary_deafness(-seconds_per_tick SECONDS)
if((damage > low_threshold) && SPT_PROB(damage / 60, seconds_per_tick))
- adjustEarDamage(0, 4)
+ adjust_temporary_deafness(4 SECONDS)
SEND_SOUND(owner, sound('sound/items/weapons/flash_ring.ogg'))
-/obj/item/organ/ears/apply_organ_damage(damage_amount, maximum, required_organ_flag)
- . = ..()
- update_temp_deafness()
-
/obj/item/organ/ears/on_mob_insert(mob/living/carbon/organ_owner, special, movement_flags)
. = ..()
- update_temp_deafness()
+ if(temporary_deafness)
+ on_deafened()
/obj/item/organ/ears/on_mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
. = ..()
- UnregisterSignal(organ_owner, COMSIG_MOB_SAY)
- REMOVE_TRAIT(organ_owner, TRAIT_DEAF, EAR_DAMAGE)
+ if(temporary_deafness)
+ on_undeafened(organ_owner)
/obj/item/organ/ears/get_status_appendix(advanced, add_tooltips)
if(owner.stat == DEAD || !HAS_TRAIT(owner, TRAIT_DEAF))
@@ -65,7 +62,7 @@
return conditional_tooltip("Subject is permanently deaf.", "Irreparable under normal circumstances.", add_tooltips)
if(HAS_TRAIT_FROM(owner, TRAIT_DEAF, GENETIC_MUTATION))
return conditional_tooltip("Subject is genetically deaf.", "Use medication such as [/datum/reagent/medicine/mutadone::name].", add_tooltips)
- if(HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
+ if((organ_flags & ORGAN_FAILING) || HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
return conditional_tooltip("Subject is [(organ_flags & ORGAN_FAILING) ? "permanently": "temporarily"] deaf from ear damage.", "Repair surgically, use medication such as [/datum/reagent/medicine/inacusiate::name], or protect ears with earmuffs.", add_tooltips)
return "Subject is deaf."
@@ -73,52 +70,43 @@
// Always show if we have an appendix
return ..() || (owner.stat != DEAD && HAS_TRAIT(owner, TRAIT_DEAF))
-/**
- * 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/ears/proc/adjustEarDamage(ddmg = 0, ddeaf = 0)
- if(HAS_TRAIT(owner, TRAIT_GODMODE))
- update_temp_deafness()
+///Adjust the temporary deafness of the person, up or down
+/obj/item/organ/ears/proc/adjust_temporary_deafness(amount)
+ // organ failure makes us permanently deafened. Also, doesn't do anything if not in someone or during godmode
+ if(amount <= 0 || (owner && HAS_TRAIT(owner, TRAIT_GODMODE)))
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()
+ temporary_deafness += max(amount * damage_multiplier, 0)
-/// Updates status of deafness
-/obj/item/organ/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))
+ if(!owner)
return
- if(HAS_TRAIT(owner, TRAIT_GODMODE))
- deaf = 0
+ if(temporary_deafness && !HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
+ on_deafened()
+ else if(!temporary_deafness && HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE))
+ on_undeafened()
- 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)
+///Called when temporary deafness begins
+/obj/item/organ/ears/proc/on_deafened()
+ RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(adjust_speech))
+ ADD_TRAIT(owner, TRAIT_DEAF, EAR_DAMAGE)
+
+///Called when temporary deafness reaches zero. Has to have an 'organ_owner' arg, because by the time it's called on 'on_mob_remove', owner is already null
+/obj/item/organ/ears/proc/on_undeafened(mob/living/organ_owner = owner)
+ REMOVE_TRAIT(organ_owner, TRAIT_DEAF, EAR_DAMAGE)
+ UnregisterSignal(organ_owner, COMSIG_MOB_SAY)
+
+/obj/item/organ/ears/on_begin_failure()
+ add_organ_trait(TRAIT_DEAF)
+
+/obj/item/organ/ears/on_failure_recovery()
+ remove_organ_trait(TRAIT_DEAF)
/// Being deafened by loud noises makes you shout
/obj/item/organ/ears/proc/adjust_speech(datum/source, list/speech_args)
SIGNAL_HANDLER
- if(HAS_TRAIT_NOT_FROM(source, TRAIT_DEAF, EAR_DAMAGE))
- return
- if(HAS_TRAIT(source, TRAIT_SIGN_LANG))
+ if(HAS_TRAIT_NOT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE) || HAS_TRAIT(owner, TRAIT_SIGN_LANG))
return
var/message = speech_args[SPEECH_MESSAGE]
@@ -240,16 +228,9 @@
desc = "Allows the user to more easily hear whispers. The user becomes extra vulnerable to loud noises, however"
// Same sensitivity as felinid ears
damage_multiplier = 2
-
-// The original idea was to use signals to do this not traits. Unfortunately, the star effect used for whispers applies before any relevant signals
-// This seems like the least invasive solution
-/obj/item/organ/ears/cybernetic/whisper/on_mob_insert(mob/living/carbon/ear_owner)
- . = ..()
- ADD_TRAIT(ear_owner, TRAIT_GOOD_HEARING, ORGAN_TRAIT)
-
-/obj/item/organ/ears/cybernetic/whisper/on_mob_remove(mob/living/carbon/ear_owner)
- . = ..()
- REMOVE_TRAIT(ear_owner, TRAIT_GOOD_HEARING, ORGAN_TRAIT)
+ // The original idea was to use signals to do this not traits. Unfortunately, the star effect used for whispers applies before any relevant signals
+ // This seems like the least invasive solution
+ organ_traits = list(TRAIT_GOOD_HEARING)
/obj/item/organ/ears/cybernetic/volume
name = "volume-adjusting cybernetic ears"
@@ -265,14 +246,7 @@
desc = "Through the power of modern engineering, allows the user to hear speech through walls. The user becomes extra vulnerable to loud noises, however"
// Same sensitivity as felinid ears
damage_multiplier = 2
-
-/obj/item/organ/ears/cybernetic/xray/on_mob_insert(mob/living/carbon/ear_owner)
- . = ..()
- ADD_TRAIT(ear_owner, TRAIT_XRAY_HEARING, ORGAN_TRAIT)
-
-/obj/item/organ/ears/cybernetic/xray/on_mob_remove(mob/living/carbon/ear_owner)
- . = ..()
- REMOVE_TRAIT(ear_owner, TRAIT_XRAY_HEARING, ORGAN_TRAIT)
+ organ_traits = list(TRAIT_XRAY_HEARING)
/obj/item/organ/ears/cybernetic/emp_act(severity)
. = ..()
diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm
index 5d1d37ca9f9..9306abf8f63 100644
--- a/code/modules/surgery/organs/internal/eyes/_eyes.dm
+++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm
@@ -22,8 +22,6 @@
/// Sight flags this eye pair imparts on its user.
var/sight_flags = NONE
- /// changes how the eyes overlay is applied, makes it apply over the lighting layer
- var/overlay_ignore_lighting = FALSE
/// How much innate tint these eyes have
var/tint = 0
/// How much innare flash protection these eyes have, usually paired with tint
@@ -52,8 +50,6 @@
/// Glasses cannot be worn over these eyes. Currently unused
var/no_glasses = FALSE
- /// indication that the eyes are undergoing some negative effect
- var/damaged = FALSE
/// Native FOV that will be applied if a config is enabled
var/native_fov = FOV_90_DEGREES
/// Scarring on this organ
@@ -82,8 +78,13 @@
/obj/item/organ/eyes/on_mob_insert(mob/living/carbon/receiver, special, movement_flags)
. = ..()
+ if(organ_flags & ORGAN_FAILING)
+ receiver.become_blind(EYE_DAMAGE)
+ if(damage >= low_threshold)
+ receiver.assign_nearsightedness(EYE_DAMAGE, damage >= high_threshold ? 3 : 2, TRUE)
+
receiver.cure_blind(NO_EYES)
- apply_damaged_eye_effects()
+
// Ensures that non-player mobs get their eye colors assigned, as players get them from prefs
if (ishuman(receiver))
var/mob/living/carbon/human/as_human = receiver
@@ -91,9 +92,17 @@
eye_color_left = as_human.eye_color_left
if (!eye_color_right)
eye_color_right = as_human.eye_color_right
+ RegisterSignals(receiver, list(
+ SIGNAL_ADDTRAIT(TRAIT_LUMINESCENT_EYES),
+ SIGNAL_REMOVETRAIT(TRAIT_LUMINESCENT_EYES),
+ SIGNAL_ADDTRAIT(TRAIT_REFLECTIVE_EYES),
+ SIGNAL_REMOVETRAIT(TRAIT_REFLECTIVE_EYES),
+ ), PROC_REF(on_shiny_eyes_trait_update))
+
refresh(receiver, call_update = TRUE)
RegisterSignal(receiver, COMSIG_ATOM_BULLET_ACT, PROC_REF(on_bullet_act))
RegisterSignal(receiver, COMSIG_COMPONENT_CLEAN_FACE_ACT, PROC_REF(on_face_wash))
+
if (scarring)
apply_scarring_effects()
@@ -134,19 +143,37 @@
if(!special)
human_owner.update_body()
+ // become blind (if not special)
+ if(!special)
+ organ_owner.become_blind(NO_EYES)
+
// Cure blindness from eye damage
organ_owner.cure_blind(EYE_DAMAGE)
organ_owner.cure_nearsighted(EYE_DAMAGE)
// Eye blind and temp blind go to, even if this is a bit of cheesy way to clear blindness
organ_owner.remove_status_effect(/datum/status_effect/eye_blur)
organ_owner.remove_status_effect(/datum/status_effect/temporary_blindness)
- // Then become blind anyways (if not special)
- if(!special)
- organ_owner.become_blind(NO_EYES)
+
+ if (scarring)
+ owner.cure_nearsighted(TRAIT_RIGHT_EYE_SCAR)
+ owner.cure_nearsighted(TRAIT_LEFT_EYE_SCAR)
+ owner.cure_blind(EYE_SCARRING_TRAIT)
organ_owner.update_tint()
organ_owner.update_sight()
- UnregisterSignal(organ_owner, list(COMSIG_ATOM_BULLET_ACT, COMSIG_COMPONENT_CLEAN_FACE_ACT))
+ UnregisterSignal(organ_owner, list(
+ COMSIG_ATOM_BULLET_ACT,
+ COMSIG_COMPONENT_CLEAN_FACE_ACT,
+ SIGNAL_ADDTRAIT(TRAIT_LUMINESCENT_EYES),
+ SIGNAL_REMOVETRAIT(TRAIT_LUMINESCENT_EYES),
+ SIGNAL_ADDTRAIT(TRAIT_REFLECTIVE_EYES),
+ SIGNAL_REMOVETRAIT(TRAIT_REFLECTIVE_EYES),
+ ))
+
+///Called whenever the luminescent and/or reflective eyes traits are added or removed
+/obj/item/organ/eyes/proc/on_shiny_eyes_trait_update(mob/living/carbon/human/source)
+ SIGNAL_HANDLER
+ source.update_eyes()
/obj/item/organ/eyes/update_atom_colour()
. = ..()
@@ -267,9 +294,8 @@
var/mutable_appearance/eye_right = mutable_appearance('icons/mob/human/human_face.dmi', "[eye_icon_state]_r", -EYES_LAYER, parent)
var/list/overlays = list(eye_left, eye_right)
- if(overlay_ignore_lighting && !(parent.obscured_slots & HIDEEYES))
- overlays += emissive_appearance(eye_left.icon, eye_left.icon_state, parent, -EYES_LAYER, alpha = eye_left.alpha)
- overlays += emissive_appearance(eye_right.icon, eye_right.icon_state, parent, -EYES_LAYER, alpha = eye_right.alpha)
+ if(!(parent.obscured_slots & HIDEEYES))
+ overlays += get_emissive_overlays(eye_left, eye_right, parent)
var/obj/item/bodypart/head/my_head = parent.get_bodypart(BODY_ZONE_HEAD)
@@ -299,6 +325,19 @@
return overlays
+///Returns the two emissive overlays built for the left and right eyes, in order.
+/obj/item/organ/eyes/proc/get_emissive_overlays(mutable_appearance/eye_left, mutable_appearance/eye_right, atom/spokesman)
+ var/list/return_list = list()
+ var/emissive_effect
+ if((owner && HAS_TRAIT(owner, TRAIT_LUMINESCENT_EYES)) || (TRAIT_LUMINESCENT_EYES in organ_traits))
+ emissive_effect = EMISSIVE_BLOOM
+ else if((owner && HAS_TRAIT(owner, TRAIT_REFLECTIVE_EYES)) || (TRAIT_REFLECTIVE_EYES in organ_traits))
+ emissive_effect = EMISSIVE_SPECULAR
+ if(emissive_effect)
+ return_list += emissive_appearance(eye_left.icon, eye_left.icon_state, spokesman, -EYES_LAYER, alpha = eye_left.alpha, effect_type = emissive_effect)
+ return_list += emissive_appearance(eye_right.icon, eye_right.icon_state, spokesman, -EYES_LAYER, alpha = eye_right.alpha, effect_type = emissive_effect)
+ return return_list
+
/obj/item/organ/eyes/update_overlays()
. = ..()
if (scarring & RIGHT_EYE_SCAR)
@@ -358,13 +397,6 @@
owner.cure_blind(EYE_SCARRING_TRAIT)
owner.update_body()
-/obj/item/organ/eyes/on_mob_remove(mob/living/carbon/eye_owner)
- . = ..()
- if (scarring)
- eye_owner.cure_nearsighted(TRAIT_RIGHT_EYE_SCAR)
- eye_owner.cure_nearsighted(TRAIT_LEFT_EYE_SCAR)
- eye_owner.cure_blind(EYE_SCARRING_TRAIT)
-
#undef OFFSET_X
#undef OFFSET_Y
@@ -374,38 +406,28 @@
eye_color_left = initial(eye_color_left)
eye_color_right = initial(eye_color_right)
-/obj/item/organ/eyes/apply_organ_damage(damage_amount, maximum = maxHealth, required_organ_flag)
- . = ..()
- if(!owner)
- return FALSE
- apply_damaged_eye_effects()
-
-/// Applies effects to our owner based on how damaged our eyes are
-/obj/item/organ/eyes/proc/apply_damaged_eye_effects()
- // we're in healthy threshold, either try to heal (if damaged) or do nothing
- if(damage <= low_threshold)
- if(damaged)
- damaged = FALSE
- // clear nearsightedness from damage
- owner.cure_nearsighted(EYE_DAMAGE)
- // and cure blindness from damage
- owner.cure_blind(EYE_DAMAGE)
+/obj/item/organ/eyes/on_low_damage_received()
+ if(damage >= high_threshold)
return
+ owner?.assign_nearsightedness(EYE_DAMAGE, 2, TRUE)
- //various degrees of "oh fuck my eyes", from "point a laser at your eye" to "staring at the Sun" intensities
- // 50 - blind
- // 49-31 - nearsighted (2 severity)
- // 30-20 - nearsighted (1 severity)
- if(organ_flags & ORGAN_FAILING)
- // become blind from damage
- owner.become_blind(EYE_DAMAGE)
+/obj/item/organ/eyes/on_high_damage_received()
+ owner?.assign_nearsightedness(EYE_DAMAGE, 3, TRUE)
- else
- // become nearsighted from damage
- var/severity = damage > high_threshold ? 3 : 2
- owner.assign_nearsightedness(EYE_DAMAGE, severity, TRUE)
+/obj/item/organ/eyes/on_begin_failure()
+ owner?.become_blind(EYE_DAMAGE)
- damaged = TRUE
+/obj/item/organ/eyes/on_failure_recovery()
+ owner?.cure_blind(EYE_DAMAGE)
+
+/obj/item/organ/eyes/on_high_damage_healed()
+ if(damage <= low_threshold)
+ return
+ owner?.assign_nearsightedness(EYE_DAMAGE, 2, TRUE)
+
+/obj/item/organ/eyes/on_low_damage_healed()
+ // clear nearsightedness from damage
+ owner?.cure_nearsighted(EYE_DAMAGE)
/obj/item/organ/eyes/feel_for_damage(self_aware)
// Eye damage has visual effects, so we don't really need to "feel" it when self-examining
@@ -681,16 +703,9 @@
eye_color_left = "#3cb8a5"
eye_color_right = "#3cb8a5"
sight_flags = SEE_MOBS | SEE_OBJS | SEE_TURFS
+ organ_traits = list(TRAIT_XRAY_VISION)
penlight_message = "replaced by small radiation emitters and detectors"
-/obj/item/organ/eyes/robotic/xray/on_mob_insert(mob/living/carbon/eye_owner)
- . = ..()
- ADD_TRAIT(eye_owner, TRAIT_XRAY_VISION, ORGAN_TRAIT)
-
-/obj/item/organ/eyes/robotic/xray/on_mob_remove(mob/living/carbon/eye_owner)
- . = ..()
- REMOVE_TRAIT(eye_owner, TRAIT_XRAY_VISION, ORGAN_TRAIT)
-
/obj/item/organ/eyes/robotic/thermals
name = "thermal eyes"
desc = "These cybernetic eye implants will give you thermal vision. Vertical slit pupil included."
@@ -1004,17 +1019,25 @@
if(QDELETED(eye_owner) || !ishuman(eye_owner)) //Other carbon mobs don't have eye color.
return
- if(!eye.light_on)
- eye_icon_state = initial(eye_icon_state)
- overlay_ignore_lighting = FALSE
- else
- overlay_ignore_lighting = TRUE
- eye_icon_state = base_eye_state
-
var/obj/item/bodypart/head/head = eye_owner.get_bodypart(BODY_ZONE_HEAD) //if we have eyes we definently have a head anyway
var/previous_flags = head.head_flags
- head.head_flags = previous_flags | HEAD_EYECOLOR
- eye_owner.dna.species.handle_body(eye_owner)
+ head.head_flags |= HEAD_EYECOLOR
+
+ ///enabling and disabling the TRAIT_LUMINESCENT_EYES trait already calls handle_eyes(), in that case, let's skip that call
+ var/skip_call = FALSE
+ if(!eye.light_on)
+ eye_icon_state = initial(eye_icon_state)
+ skip_call = HAS_TRAIT_FROM_ONLY(eye_owner, TRAIT_LUMINESCENT_EYES, REF(src))
+ remove_organ_trait(TRAIT_LUMINESCENT_EYES)
+ else
+ skip_call = !HAS_TRAIT(eye_owner, TRAIT_LUMINESCENT_EYES)
+ add_organ_trait(TRAIT_LUMINESCENT_EYES)
+ eye_icon_state = base_eye_state
+
+ if(!skip_call && ishuman(eye_owner))
+ var/mob/living/carbon/human/humie = eye_owner
+ humie.update_eyes()
+
head.head_flags = previous_flags
#undef MATCH_LIGHT_COLOR
@@ -1140,7 +1163,7 @@
eye_color_right = "#f74a4d"
eye_icon_state = "eyes_glow"
iris_overlay = null
- overlay_ignore_lighting = TRUE
+ organ_traits = list(TRAIT_UNNATURAL_RED_GLOWY_EYES, TRAIT_LUMINESCENT_EYES)
flash_protect = FLASH_PROTECTION_HYPER_SENSITIVE
low_light_cutoff = list(5, 12, 20)
medium_light_cutoff = list(15, 20, 30)
@@ -1153,10 +1176,6 @@
apply_organ_damage(20 * examtool.light_power) //that's 0.5 lightpower for a penlight, so one penlight shining is equivalent to two seconds in a lit area
return span_danger("[owner.p_Their()] eyes [penlight_message].")
-/obj/item/organ/eyes/night_vision/maintenance_adapted/on_mob_insert(mob/living/carbon/eye_owner)
- . = ..()
- ADD_TRAIT(eye_owner, TRAIT_UNNATURAL_RED_GLOWY_EYES, ORGAN_TRAIT)
-
/obj/item/organ/eyes/night_vision/maintenance_adapted/on_life(seconds_per_tick, times_fired)
if(!owner.is_blind() && isturf(owner.loc) && owner.has_light_nearby(light_amount=0.5)) //we allow a little more than usual so we can produce light from the adapted eyes
to_chat(owner, span_danger("Your eyes! They burn in the light!"))
@@ -1166,10 +1185,6 @@
apply_organ_damage(-10) //heal quickly
. = ..()
-/obj/item/organ/eyes/night_vision/maintenance_adapted/on_mob_remove(mob/living/carbon/unadapted, special = FALSE, movement_flags)
- REMOVE_TRAIT(unadapted, TRAIT_UNNATURAL_RED_GLOWY_EYES, ORGAN_TRAIT)
- return ..()
-
/obj/item/organ/eyes/pod
name = "pod eyes"
desc = "Strangest salad you've ever seen."
@@ -1179,3 +1194,9 @@
iris_overlay = null
foodtype_flags = PODPERSON_ORGAN_FOODTYPES
penlight_message = "are green and plant-like"
+
+/obj/item/organ/eyes/felinid
+ name = "felinid eyes"
+ desc = "A pair of highly reflective eyes with slit pupils, like those of a cat."
+ pupils_name = "slit pupils"
+ penlight_message = "shine under the pearly light"
diff --git a/code/modules/surgery/organs/internal/tongue/_tongue.dm b/code/modules/surgery/organs/internal/tongue/_tongue.dm
index 9a540532388..34c2b7df085 100644
--- a/code/modules/surgery/organs/internal/tongue/_tongue.dm
+++ b/code/modules/surgery/organs/internal/tongue/_tongue.dm
@@ -8,6 +8,7 @@
attack_verb_continuous = list("licks", "slobbers", "slaps", "frenches", "tongues")
attack_verb_simple = list("lick", "slobber", "slap", "french", "tongue")
voice_filter = ""
+ organ_traits = list(TRAIT_SPEAKS_CLEARLY)
/**
* A cached list of paths of all the languages this tongue is capable of speaking
*
@@ -51,6 +52,8 @@
// - then we cache it via string list
// this results in tongues with identical possible languages sharing a cached list instance
languages_possible = string_list(get_possible_languages())
+ if(!sense_of_taste)
+ add_organ_trait(TRAIT_AGEUSIA)
/obj/item/organ/tongue/examine(mob/user)
. = ..()
@@ -137,40 +140,24 @@
* ageusia from having a non-tasting tongue.
*/
REMOVE_TRAIT(receiver, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
- apply_tongue_effects()
/obj/item/organ/tongue/on_mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
. = ..()
temp_say_mod = ""
UnregisterSignal(organ_owner, COMSIG_MOB_SAY)
- REMOVE_TRAIT(organ_owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE)
- REMOVE_TRAIT(organ_owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
// Carbons by default start with NO_TONGUE_TRAIT caused TRAIT_AGEUSIA
ADD_TRAIT(organ_owner, TRAIT_AGEUSIA, NO_TONGUE_TRAIT)
organ_owner.voice_filter = initial(organ_owner.voice_filter)
-/obj/item/organ/tongue/apply_organ_damage(damage_amount, maximum = maxHealth, required_organ_flag)
- . = ..()
- if(!owner)
- return FALSE
- apply_tongue_effects()
+/obj/item/organ/tongue/on_begin_failure()
+ remove_organ_trait(TRAIT_SPEAKS_CLEARLY)
+ add_organ_trait(TRAIT_AGEUSIA)
-/// Applies effects to our owner based on how damaged our tongue is
-/obj/item/organ/tongue/proc/apply_tongue_effects()
+/obj/item/organ/tongue/on_failure_recovery()
+ add_organ_trait(TRAIT_SPEAKS_CLEARLY)
if(sense_of_taste)
- //tongues can't taste food when they are failing
- if(organ_flags & ORGAN_FAILING)
- ADD_TRAIT(owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
- else
- REMOVE_TRAIT(owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
- else
- //tongues can't taste food when they lack a sense of taste
- ADD_TRAIT(owner, TRAIT_AGEUSIA, ORGAN_TRAIT)
- if(organ_flags & ORGAN_FAILING)
- REMOVE_TRAIT(owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE)
- else
- ADD_TRAIT(owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE)
+ remove_organ_trait(TRAIT_AGEUSIA)
/obj/item/organ/tongue/could_speak_language(datum/language/language_path)
return (language_path in languages_possible)
diff --git a/code/modules/unit_tests/screenshots/screenshot_high_luminosity_eyes_light_emissive.png b/code/modules/unit_tests/screenshots/screenshot_high_luminosity_eyes_light_emissive.png
index 912f16e6839..7445f2cfffa 100644
Binary files a/code/modules/unit_tests/screenshots/screenshot_high_luminosity_eyes_light_emissive.png and b/code/modules/unit_tests/screenshots/screenshot_high_luminosity_eyes_light_emissive.png differ
diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
index 0cfc0712b59..7e68aaf91cb 100644
--- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
+++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm
@@ -273,9 +273,7 @@
to_chat(M, "HONK")
M.SetSleeping(0)
M.adjust_stutter(40 SECONDS)
- var/obj/item/organ/ears/ears = M.get_organ_slot(ORGAN_SLOT_EARS)
- if(ears)
- ears.adjustEarDamage(0, 30)
+ M.sound_damage(deafen = 30 SECONDS)
M.Paralyze(60)
if(prob(30))
M.Stun(200)