Refactors ears into organs (#513)

* Refactors ear damage into ear organs

* Update human.dm

* Update species.dm

* Delete species.dm.rej

* Update tgstation.dme

* Delete tgstation.dme.rej

* Delete human.dm.rej

* Update tongue.dm

* Delete surgery.dmi

* upload fixed surgery.dmi
This commit is contained in:
CitadelStationBot
2017-04-26 09:52:35 -05:00
committed by Poojawa
parent a905c15dad
commit 84321916a5
40 changed files with 925 additions and 908 deletions
+1
View File
@@ -201,6 +201,7 @@
/obj/item/clothing/ears/earmuffs/Initialize(mapload)
..()
SET_SECONDARY_FLAG(src, BANG_PROTECT)
SET_SECONDARY_FLAG(src, HEALS_EARS)
//Glasses
/obj/item/clothing/glasses
@@ -1,15 +1,7 @@
//Here are the procs used to modify status effects of a mob.
//The effects include: stunned, weakened, paralysis, sleeping, resting, jitteriness, dizziness, ear damage,
//The effects include: stunned, weakened, paralysis, sleeping, resting, jitteriness, dizziness
// eye damage, eye_blind, eye_blurry, druggy, BLIND disability, and NEARSIGHT disability.
/////////////////////////////////// EAR DAMAGE ////////////////////////////////////
/mob/living/brain/adjustEarDamage()
return
/mob/living/brain/setEarDamage() // no ears to damage or heal
return
/////////////////////////////////// EYE_BLIND ////////////////////////////////////
/mob/living/brain/blind_eyes() // no eyes to damage or heal
@@ -48,6 +48,7 @@
internal_organs += new /obj/item/organ/alien/hivenode
internal_organs += new /obj/item/organ/tongue/alien
internal_organs += new /obj/item/organ/eyes/night_vision/alien
internal_organs += new /obj/item/organ/ears
..()
/mob/living/carbon/alien/assess_threat() // beepsky won't hunt aliums
@@ -147,6 +148,8 @@ Des: Removes all infected images from the alien.
mind.transfer_to(new_xeno)
qdel(src)
// TODO make orbiters orbit the new xeno, or make xenos species rather than types
#undef HEAT_DAMAGE_LEVEL_1
#undef HEAT_DAMAGE_LEVEL_2
#undef HEAT_DAMAGE_LEVEL_3
+3
View File
@@ -722,6 +722,9 @@
if(reagents)
reagents.addiction_list = list()
..()
// heal ears after healing disabilities, since ears check DEAF disability
// when healing.
restoreEars()
/mob/living/carbon/can_be_revived()
. = ..()
@@ -277,20 +277,24 @@
/mob/living/carbon/soundbang_act(intensity = 1, stun_pwr = 1, damage_pwr = 5, deafen_pwr = 15)
var/ear_safety = get_ear_protection()
var/obj/item/organ/ears/ears = getorganslot("ears")
if(ear_safety < 2) //has ears
var/effect_amount = intensity - ear_safety
if(effect_amount > 0)
if(stun_pwr)
Stun(stun_pwr*effect_amount)
Weaken(stun_pwr*effect_amount)
if(deafen_pwr || damage_pwr)
setEarDamage(ear_damage + damage_pwr*effect_amount, max(ear_deaf, deafen_pwr*effect_amount))
if (ear_damage >= 15)
if(istype(ears) && (deafen_pwr || damage_pwr))
ears.ear_damage += damage_pwr * effect_amount
ears.deaf = max(ears.deaf, deafen_pwr * effect_amount)
if(ears.ear_damage >= 15)
to_chat(src, "<span class='warning'>Your ears start to ring badly!</span>")
if(prob(ear_damage - 5))
to_chat(src, "<span class='warning'>You can't hear anything!</span>")
disabilities |= DEAF
else if(ear_damage >= 5)
if(prob(ears.ear_damage - 5))
to_chat(src, "<span class='userdanger'>You can't hear anything!</span>")
ears.ear_damage = min(ears.ear_damage, UNHEALING_EAR_DAMAGE)
// you need earmuffs, inacusiate, or replacement
else if(ears.ear_damage >= 5)
to_chat(src, "<span class='warning'>Your ears start to ring!</span>")
src << sound('sound/weapons/flash_ring.ogg',0,1,0,250)
return effect_amount //how soundbanged we are
@@ -310,3 +314,9 @@
hit_clothes = head
if(hit_clothes)
hit_clothes.take_damage(damage_amount, damage_type, damage_flag, 0)
/mob/living/carbon/can_hear()
. = FALSE
var/obj/item/organ/ears/ears = getorganslot("ears")
if(istype(ears) && !ears.deaf)
. = TRUE
@@ -59,6 +59,7 @@
internal_organs += new /obj/item/organ/heart
internal_organs += new dna.species.mutanteyes()
internal_organs += new dna.species.mutantears
internal_organs += new /obj/item/organ/brain
give_genitals()
..()
+1 -11
View File
@@ -70,18 +70,8 @@
else if(eye_blurry) //blurry eyes heal slowly
adjust_blurriness(-1)
//Ears
if(disabilities & DEAF) //disabled-deaf, doesn't get better on its own
setEarDamage(-1, max(ear_deaf, 1))
else
if(istype(ears, /obj/item/clothing/ears/earmuffs)) // earmuffs rest your ears, healing ear_deaf faster and ear_damage, but keeping you deaf.
setEarDamage(max(ear_damage-0.10, 0), max(ear_deaf - 1, 1))
// deafness heals slowly over time, unless ear_damage is over 100
if(ear_damage < 100)
adjustEarDamage(-0.05,-1)
if (getBrainLoss() >= 60 && stat != DEAD)
if (prob(3))
if(prob(3))
if(prob(25))
emote("drool")
else
@@ -67,6 +67,9 @@
//Eyes
var/obj/item/organ/eyes/mutanteyes = /obj/item/organ/eyes
//Ears
var/obj/item/organ/ears/mutantears = /obj/item/organ/ears
//Citadel snowflake
var/fixed_mut_color2 = ""
@@ -127,6 +130,7 @@
var/obj/item/organ/lungs/lungs = C.getorganslot("lungs")
var/obj/item/organ/appendix/appendix = C.getorganslot("appendix")
var/obj/item/organ/eyes/eyes = C.getorganslot("eye_sight")
var/obj/item/organ/ears/ears = C.getorganslot("ears")
if((NOBLOOD in species_traits) && heart)
heart.Remove(C)
@@ -144,6 +148,11 @@
eyes = new mutanteyes
eyes.Insert(C)
if(ears)
qdel(ears)
ears = new mutantears
ears.Insert(C)
if((!(NOBREATH in species_traits)) && !lungs)
if(mutantlungs)
lungs = new mutantlungs()
@@ -45,6 +45,7 @@
internal_organs += new /obj/item/organ/brain
internal_organs += new /obj/item/organ/tongue
internal_organs += new /obj/item/organ/eyes
internal_organs += new /obj/item/organ/ears
..()
/mob/living/carbon/monkey/movement_delay()
@@ -134,15 +135,6 @@
protection = protection/7 //the rest of the body isn't covered.
return protection
/mob/living/carbon/monkey/fully_heal(admin_revive = 0)
if(!getorganslot("lungs"))
var/obj/item/organ/lungs/L = new()
L.Insert(src)
if(!getorganslot("tongue"))
var/obj/item/organ/tongue/T = new()
T.Insert(src)
..()
/mob/living/carbon/monkey/IsVocal()
if(!getorganslot("lungs"))
return 0
-8
View File
@@ -126,14 +126,6 @@
if(client && !eye_blurry)
clear_fullscreen("blurry")
//Ears
if(disabilities & DEAF) //disabled-deaf, doesn't get better on its own
setEarDamage(-1, max(ear_deaf, 1))
else
// deafness heals slowly over time, unless ear_damage is over 100
if(ear_damage < 100)
adjustEarDamage(-0.05,-1)
/mob/living/proc/update_damage_hud()
return
-2
View File
@@ -379,8 +379,6 @@
cure_blind()
cure_husk()
disabilities = 0
ear_deaf = 0
ear_damage = 0
hallucination = 0
heal_overall_damage(100000, 100000, 0, 0, 1) //heal brute and burn dmg on both organic and robotic limbs, and update health right away.
ExtinguishMob()
+1 -1
View File
@@ -153,7 +153,7 @@
if(!only_listener)
// Play voice for all mobs in the z level
for(var/mob/M in GLOB.player_list)
if(M.client && !M.ear_deaf && (M.client.prefs.toggles & SOUND_ANNOUNCEMENTS))
if(M.client && M.can_hear() && (M.client.prefs.toggles & SOUND_ANNOUNCEMENTS))
var/turf/T = get_turf(M)
if(T.z == z_level)
M << voice
@@ -36,11 +36,3 @@
. = ..()
if(. && updating)
update_stat()
/////////////////////////////////// EAR DAMAGE ////////////////////////////////////
/mob/living/silicon/adjustEarDamage()
return
/mob/living/silicon/setEarDamage()
return
@@ -23,12 +23,3 @@
/mob/living/simple_animal/become_blind()
return
/mob/living/simple_animal/adjustEarDamage()
return
/mob/living/simple_animal/setEarDamage()
return
+2 -16
View File
@@ -1,21 +1,7 @@
//Here are the procs used to modify status effects of a mob.
//The effects include: stunned, weakened, paralysis, sleeping, resting, jitteriness, dizziness, ear damage,
//The effects include: stunned, weakened, paralysis, sleeping, resting, jitteriness, dizziness,
// eye damage, eye_blind, eye_blurry, druggy, BLIND disability, and NEARSIGHT disability.
/////////////////////////////////// EAR DAMAGE ////////////////////////////////////
//damage/heal the mob ears and adjust the deaf amount
/mob/living/adjustEarDamage(damage, deaf)
ear_damage = max(0, ear_damage + damage)
ear_deaf = max(0, ear_deaf + deaf)
//pass a negative argument to skip one of the variable
/mob/living/setEarDamage(damage, deaf)
if(damage >= 0)
ear_damage = damage
if(deaf >= 0)
ear_deaf = deaf
//////////////////////////////STUN ////////////////////////////////////
@@ -71,4 +57,4 @@
to_chat(src, "<span class='boldwarning'>[priority_absorb_key["self_message"]]</span>")
priority_absorb_key["stuns_absorbed"] += amount
return 0
return ..()
return ..()
+2 -6
View File
@@ -73,7 +73,7 @@
msg = alt_msg
type = alt_type
if(type & 2 && ear_deaf)//Hearing related
if(type & 2 && !can_hear())//Hearing related
if(!alt_msg)
return
else
@@ -972,10 +972,6 @@
set_eye_damage(var_value)
if("eye_blurry")
set_blurriness(var_value)
if("ear_deaf")
setEarDamage(-1, var_value)
if("ear_damage")
setEarDamage(var_value, -1)
if("maxHealth")
updatehealth()
if("resize")
@@ -1013,4 +1009,4 @@
switch(var_name)
if("logging")
return debug_variable(var_name, logging, 0, src, FALSE)
. = ..()
. = ..()
-2
View File
@@ -42,8 +42,6 @@
var/notransform = null //Carbon
var/eye_blind = 0 //Carbon
var/eye_blurry = 0 //Carbon
var/ear_deaf = 0 //Carbon
var/ear_damage = 0 //Carbon
var/stuttering = 0 //Carbon
var/slurring = 0 //Carbon
var/cultslurring = 0 //Carbon
+3
View File
@@ -482,3 +482,6 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
var/list/timestamped_message = list("[LAZYLEN(logging[message_type]) + 1]\[[time_stamp()]\] [key_name(src)]" = message)
logging[message_type] += timestamped_message
/mob/proc/can_hear()
. = TRUE
-8
View File
@@ -143,14 +143,6 @@
/mob/proc/Dizzy(amount)
dizziness = max(dizziness,amount,0)
/////////////////////////////////// EAR DAMAGE ////////////////////////////////////
/mob/proc/adjustEarDamage()
return
/mob/proc/setEarDamage()
return
/////////////////////////////////// EYE DAMAGE ////////////////////////////////////
/mob/proc/damage_eyes(amount)
@@ -118,7 +118,7 @@
color = "#6600FF" // rgb: 100, 165, 255
/datum/reagent/medicine/inacusiate/on_mob_life(mob/living/M)
M.setEarDamage(0,0)
M.restoreEars()
..()
/datum/reagent/medicine/cryoxadone
+32
View File
@@ -0,0 +1,32 @@
/obj/item/organ/appendix
name = "appendix"
icon_state = "appendix"
zone = "groin"
slot = "appendix"
var/inflamed = 0
/obj/item/organ/appendix/update_icon()
if(inflamed)
icon_state = "appendixinflamed"
name = "inflamed appendix"
else
icon_state = "appendix"
name = "appendix"
/obj/item/organ/appendix/Remove(mob/living/carbon/M, special = 0)
for(var/datum/disease/appendicitis/A in M.viruses)
A.cure()
inflamed = 1
update_icon()
..()
/obj/item/organ/appendix/Insert(mob/living/carbon/M, special = 0)
..()
if(inflamed)
M.AddDisease(new /datum/disease/appendicitis)
/obj/item/organ/appendix/prepare_eat()
var/obj/S = ..()
if(inflamed)
S.reagents.add_reagent("bad_food", 5)
return S
+69
View File
@@ -0,0 +1,69 @@
/obj/item/organ/ears
name = "ears"
icon_state = "ears"
desc = "There are three parts to the ear. Inner, middle and outer. Only one of these parts should be normally visible."
zone = "head"
slot = "ears"
// `deaf` measures "ticks" of deafness. While > 0, the person is unable
// to hear anything.
var/deaf = 0
// `ear_damage` 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)
var/ear_damage = 0
/obj/item/organ/ears/on_life()
if(!iscarbon(owner))
return
var/mob/living/carbon/C = owner
// genetic deafness prevents the body from using the ears, even if healthy
if(C.disabilities & DEAF)
deaf = max(deaf, 1)
else
if(HAS_SECONDARY_FLAG(C.ears, HEALS_EARS))
deaf = max(deaf - 1, 1)
ear_damage = max(ear_damage - 0.10, 0)
// if higher than UNHEALING_EAR_DAMAGE, no natural healing occurs.
if(ear_damage < UNHEALING_EAR_DAMAGE)
ear_damage = max(ear_damage - 0.05, 0)
deaf = max(deaf - 1, 0)
/obj/item/organ/ears/proc/restoreEars()
deaf = 0
ear_damage = 0
var/mob/living/carbon/C = owner
if(iscarbon(owner) && C.disabilities & DEAF)
deaf = 1
/obj/item/organ/ears/proc/adjustEarDamage(ddmg, ddeaf)
ear_damage = max(ear_damage + ddmg, 0)
deaf = max(deaf + ddeaf, 0)
/obj/item/organ/ears/proc/minimumDeafTicks(value)
deaf = max(deaf, value)
/mob/proc/restoreEars()
/mob/living/carbon/restoreEars()
var/obj/item/organ/ears/ears = getorgan(/obj/item/organ/ears)
if(ears)
ears.restoreEars()
/mob/proc/adjustEarDamage()
/mob/living/carbon/adjustEarDamage(ddmg, ddeaf)
var/obj/item/organ/ears/ears = getorgan(/obj/item/organ/ears)
if(ears)
ears.adjustEarDamage(ddmg, ddeaf)
/mob/proc/minimumDeafTicks()
/mob/living/carbon/minimumDeafTicks(value)
var/obj/item/organ/ears/ears = getorgan(/obj/item/organ/ears)
if(ears)
ears.minimumDeafTicks(value)
+130
View File
@@ -0,0 +1,130 @@
/obj/item/organ/eyes
name = "eyes"
icon_state = "eyeballs"
desc = "I see you!"
zone = "eyes"
slot = "eye_sight"
var/sight_flags = 0
var/see_in_dark = 2
var/tint = 0
var/eye_color = "" //set to a hex code to override a mob's eye color
var/old_eye_color = "fff"
var/flash_protect = 0
var/see_invisible = SEE_INVISIBLE_LIVING
var/lighting_alpha
/obj/item/organ/eyes/Insert(mob/living/carbon/M, special = 0)
..()
if(ishuman(owner))
var/mob/living/carbon/human/HMN = owner
old_eye_color = HMN.eye_color
if(eye_color)
HMN.eye_color = eye_color
HMN.regenerate_icons()
else
eye_color = HMN.eye_color
M.update_tint()
owner.update_sight()
/obj/item/organ/eyes/Remove(mob/living/carbon/M, special = 0)
..()
if(ishuman(M) && eye_color)
var/mob/living/carbon/human/HMN = M
HMN.eye_color = old_eye_color
HMN.regenerate_icons()
M.update_tint()
M.update_sight()
/obj/item/organ/eyes/night_vision
name = "shadow eyes"
desc = "A spooky set of eyes that can see in the dark."
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
actions_types = list(/datum/action/item_action/organ_action/use)
var/night_vision = TRUE
/obj/item/organ/eyes/night_vision/ui_action_click()
switch(lighting_alpha)
if (LIGHTING_PLANE_ALPHA_VISIBLE)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
if (LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
if (LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE)
lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
else
lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
owner.update_sight()
/obj/item/organ/eyes/night_vision/alien
name = "alien eyes"
desc = "It turned out they had them after all!"
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
sight_flags = SEE_MOBS
///Robotic
/obj/item/organ/eyes/robotic
name = "robotic eyes"
icon_state = "cybernetic_eyeballs"
desc = "Your vision is augmented."
status = ORGAN_ROBOTIC
/obj/item/organ/eyes/robotic/emp_act(severity)
if(!owner)
return
if(severity > 1)
if(prob(10 * severity))
return
to_chat(owner, "<span class='warning'>Static obfuscates your vision!</span>")
owner.flash_act(visual = 1)
/obj/item/organ/eyes/robotic/xray
name = "X-ray eyes"
desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile."
eye_color = "000"
see_in_dark = 8
sight_flags = SEE_MOBS | SEE_OBJS | SEE_TURFS
/obj/item/organ/eyes/robotic/thermals
name = "Thermals eyes"
desc = "These cybernetic eye implants will give you Thermal vision. Vertical slit pupil included."
eye_color = "FC0"
origin_tech = "materials=5;programming=4;biotech=4;magnets=4;syndicate=1"
sight_flags = SEE_MOBS
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
flash_protect = -1
see_in_dark = 8
/obj/item/organ/eyes/robotic/flashlight
name = "flashlight eyes"
desc = "It's two flashlights rigged together with some wire. Why would you put these in someones head?"
eye_color ="fee5a3"
icon = 'icons/obj/lighting.dmi'
icon_state = "flashlight_eyes"
flash_protect = 2
tint = INFINITY
/obj/item/organ/eyes/robotic/flashlight/emp_act(severity)
return
/obj/item/organ/eyes/robotic/flashlight/Insert(var/mob/living/carbon/M, var/special = 0)
..()
M.set_light(M.light_range + 15, M.light_power + 1)
/obj/item/organ/eyes/robotic/flashlight/Remove(var/mob/living/carbon/M, var/special = 0)
M.set_light(M.light_range -15, M.light_power - 1)
..()
// Welding shield implant
/obj/item/organ/eyes/robotic/shield
name = "shielded robotic eyes"
desc = "These reactive micro-shields will protect you from welders and flashes without obscuring your vision."
origin_tech = "materials=4;biotech=3;engineering=4;plasmatech=3"
flash_protect = 2
/obj/item/organ/eyes/robotic/shield/emp_act(severity)
return
+126
View File
@@ -0,0 +1,126 @@
/obj/item/organ/heart
name = "heart"
icon_state = "heart-on"
zone = "chest"
slot = "heart"
origin_tech = "biotech=5"
// Heart attack code is in code/modules/mob/living/carbon/human/life.dm
var/beating = 1
var/icon_base = "heart"
attack_verb = list("beat", "thumped")
/obj/item/organ/heart/update_icon()
if(beating)
icon_state = "[icon_base]-on"
else
icon_state = "[icon_base]-off"
/obj/item/organ/heart/Remove(mob/living/carbon/M, special = 0)
..()
if(!special)
addtimer(CALLBACK(src, .proc/stop_if_unowned), 120)
/obj/item/organ/heart/proc/stop_if_unowned()
if(!owner)
Stop()
/obj/item/organ/heart/attack_self(mob/user)
..()
if(!beating)
visible_message("<span class='notice'>[user] squeezes [src] to \
make it beat again!</span>", "<span class='notice'>You squeeze \
[src] to make it beat again!</span>")
Restart()
addtimer(CALLBACK(src, .proc/stop_if_unowned), 80)
/obj/item/organ/heart/proc/Stop()
beating = 0
update_icon()
return 1
/obj/item/organ/heart/proc/Restart()
beating = 1
update_icon()
return 1
/obj/item/organ/heart/prepare_eat()
var/obj/S = ..()
S.icon_state = "heart-off"
return S
/obj/item/organ/heart/cursed
name = "cursed heart"
desc = "A heart that, when inserted, will force you to pump it manually."
icon_state = "cursedheart-off"
icon_base = "cursedheart"
origin_tech = "biotech=6"
actions_types = list(/datum/action/item_action/organ_action/cursed_heart)
var/last_pump = 0
var/add_colour = TRUE //So we're not constantly recreating colour datums
var/pump_delay = 30 //you can pump 1 second early, for lag, but no more (otherwise you could spam heal)
var/blood_loss = 100 //600 blood is human default, so 5 failures (below 122 blood is where humans die because reasons?)
//How much to heal per pump, negative numbers would HURT the player
var/heal_brute = 0
var/heal_burn = 0
var/heal_oxy = 0
/obj/item/organ/heart/cursed/attack(mob/living/carbon/human/H, mob/living/carbon/human/user, obj/target)
if(H == user && istype(H))
playsound(user,'sound/effects/singlebeat.ogg',40,1)
user.drop_item()
Insert(user)
else
return ..()
/obj/item/organ/heart/cursed/on_life()
if(world.time > (last_pump + pump_delay))
if(ishuman(owner) && owner.client) //While this entire item exists to make people suffer, they can't control disconnects.
var/mob/living/carbon/human/H = owner
if(H.dna && !(NOBLOOD in H.dna.species.species_traits))
H.blood_volume = max(H.blood_volume - blood_loss, 0)
to_chat(H, "<span class = 'userdanger'>You have to keep pumping your blood!</span>")
if(add_colour)
H.add_client_colour(/datum/client_colour/cursed_heart_blood) //bloody screen so real
add_colour = FALSE
else
last_pump = world.time //lets be extra fair *sigh*
/obj/item/organ/heart/cursed/Insert(mob/living/carbon/M, special = 0)
..()
if(owner)
to_chat(owner, "<span class ='userdanger'>Your heart has been replaced with a cursed one, you have to pump this one manually otherwise you'll die!</span>")
/datum/action/item_action/organ_action/cursed_heart
name = "Pump your blood"
//You are now brea- pumping blood manually
/datum/action/item_action/organ_action/cursed_heart/Trigger()
. = ..()
if(. && istype(target,/obj/item/organ/heart/cursed))
var/obj/item/organ/heart/cursed/cursed_heart = target
if(world.time < (cursed_heart.last_pump + (cursed_heart.pump_delay-10))) //no spam
to_chat(owner, "<span class='userdanger'>Too soon!</span>")
return
cursed_heart.last_pump = world.time
playsound(owner,'sound/effects/singlebeat.ogg',40,1)
to_chat(owner, "<span class = 'notice'>Your heart beats.</span>")
var/mob/living/carbon/human/H = owner
if(istype(H))
if(H.dna && !(NOBLOOD in H.dna.species.species_traits))
H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss*0.5, BLOOD_VOLUME_MAXIMUM)
H.remove_client_colour(/datum/client_colour/cursed_heart_blood)
cursed_heart.add_colour = TRUE
H.adjustBruteLoss(-cursed_heart.heal_brute)
H.adjustFireLoss(-cursed_heart.heal_burn)
H.adjustOxyLoss(-cursed_heart.heal_oxy)
/datum/client_colour/cursed_heart_blood
priority = 100 //it's an indicator you're dieing, so it's very high priority
colour = "red"
+267
View File
@@ -0,0 +1,267 @@
#define HUMAN_MAX_OXYLOSS 3
#define HUMAN_CRIT_MAX_OXYLOSS (SSmobs.wait/30)
#define HEAT_GAS_DAMAGE_LEVEL_1 2
#define HEAT_GAS_DAMAGE_LEVEL_2 4
#define HEAT_GAS_DAMAGE_LEVEL_3 8
#define COLD_GAS_DAMAGE_LEVEL_1 0.5
#define COLD_GAS_DAMAGE_LEVEL_2 1.5
#define COLD_GAS_DAMAGE_LEVEL_3 3
/obj/item/organ/lungs
name = "lungs"
icon_state = "lungs"
zone = "chest"
slot = "lungs"
gender = PLURAL
w_class = WEIGHT_CLASS_NORMAL
var/list/breathlevels = list("safe_oxygen_min" = 16,"safe_oxygen_max" = 0,"safe_co2_min" = 0,"safe_co2_max" = 10,
"safe_toxins_min" = 0,"safe_toxins_max" = 0.05,"SA_para_min" = 1,"SA_sleep_min" = 5,"BZ_trip_balls_min" = 1)
//Breath damage
var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa
var/safe_oxygen_max = 0
var/safe_co2_min = 0
var/safe_co2_max = 10 // Yes it's an arbitrary value who cares?
var/safe_toxins_min = 0
var/safe_toxins_max = 0.05
var/SA_para_min = 1 //Sleeping agent
var/SA_sleep_min = 5 //Sleeping agent
var/BZ_trip_balls_min = 1 //BZ gas.
var/oxy_breath_dam_min = 1
var/oxy_breath_dam_max = 10
var/co2_breath_dam_min = 1
var/co2_breath_dam_max = 10
var/tox_breath_dam_min = MIN_PLASMA_DAMAGE
var/tox_breath_dam_max = MAX_PLASMA_DAMAGE
/obj/item/organ/lungs/proc/check_breath(datum/gas_mixture/breath, var/mob/living/carbon/human/H)
if((H.status_flags & GODMODE))
return
var/species_traits = list()
if(H && H.dna && H.dna.species && H.dna.species.species_traits)
species_traits = H.dna.species.species_traits
if(!breath || (breath.total_moles() == 0))
if(H.reagents.has_reagent("epinephrine"))
return
if(H.health >= HEALTH_THRESHOLD_CRIT)
H.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
else if(!(NOCRITDAMAGE in species_traits))
H.adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS)
H.failed_last_breath = 1
if(safe_oxygen_min)
H.throw_alert("oxy", /obj/screen/alert/oxy)
else if(safe_toxins_min)
H.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox)
else if(safe_co2_min)
H.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2)
return 0
var/gas_breathed = 0
var/list/breath_gases = breath.gases
breath.assert_gases("o2", "plasma", "co2", "n2o", "bz")
//Partial pressures in our breath
var/O2_pp = breath.get_breath_partial_pressure(breath_gases["o2"][MOLES])
var/Toxins_pp = breath.get_breath_partial_pressure(breath_gases["plasma"][MOLES])
var/CO2_pp = breath.get_breath_partial_pressure(breath_gases["co2"][MOLES])
//-- OXY --//
//Too much oxygen! //Yes, some species may not like it.
if(safe_oxygen_max)
if(O2_pp > safe_oxygen_max)
var/ratio = (breath_gases["o2"][MOLES]/safe_oxygen_max) * 10
H.adjustOxyLoss(Clamp(ratio,oxy_breath_dam_min,oxy_breath_dam_max))
H.throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy)
else
H.clear_alert("too_much_oxy")
//Too little oxygen!
if(safe_oxygen_min)
if(O2_pp < safe_oxygen_min)
gas_breathed = handle_too_little_breath(H,O2_pp,safe_oxygen_min,breath_gases["o2"][MOLES])
H.throw_alert("oxy", /obj/screen/alert/oxy)
else
H.failed_last_breath = 0
if(H.getOxyLoss())
H.adjustOxyLoss(-5)
gas_breathed = breath_gases["o2"][MOLES]
H.clear_alert("oxy")
//Exhale
breath_gases["o2"][MOLES] -= gas_breathed
breath_gases["co2"][MOLES] += gas_breathed
gas_breathed = 0
//-- CO2 --//
//CO2 does not affect failed_last_breath. So if there was enough oxygen in the air but too much co2, this will hurt you, but only once per 4 ticks, instead of once per tick.
if(safe_co2_max)
if(CO2_pp > safe_co2_max)
if(!H.co2overloadtime) // If it's the first breath with too much CO2 in it, lets start a counter, then have them pass out after 12s or so.
H.co2overloadtime = world.time
else if(world.time - H.co2overloadtime > 120)
H.Paralyse(3)
H.adjustOxyLoss(3) // Lets hurt em a little, let them know we mean business
if(world.time - H.co2overloadtime > 300) // They've been in here 30s now, lets start to kill them for their own good!
H.adjustOxyLoss(8)
H.throw_alert("too_much_co2", /obj/screen/alert/too_much_co2)
if(prob(20)) // Lets give them some chance to know somethings not right though I guess.
H.emote("cough")
else
H.co2overloadtime = 0
H.clear_alert("too_much_co2")
//Too little CO2!
if(breathlevels["safe_co2_min"])
if(CO2_pp < safe_co2_min)
gas_breathed = handle_too_little_breath(H,CO2_pp, safe_co2_min,breath_gases["co2"][MOLES])
H.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2)
else
H.failed_last_breath = 0
H.adjustOxyLoss(-5)
gas_breathed = breath_gases["co2"][MOLES]
H.clear_alert("not_enough_co2")
//Exhale
breath_gases["co2"][MOLES] -= gas_breathed
breath_gases["o2"][MOLES] += gas_breathed
gas_breathed = 0
//-- TOX --//
//Too much toxins!
if(safe_toxins_max)
if(Toxins_pp > safe_toxins_max)
var/ratio = (breath_gases["plasma"][MOLES]/safe_toxins_max) * 10
if(H.reagents)
H.reagents.add_reagent("plasma", Clamp(ratio, tox_breath_dam_min, tox_breath_dam_max))
H.throw_alert("tox_in_air", /obj/screen/alert/tox_in_air)
else
H.clear_alert("tox_in_air")
//Too little toxins!
if(safe_toxins_min)
if(Toxins_pp < safe_toxins_min)
gas_breathed = handle_too_little_breath(H,Toxins_pp, safe_toxins_min, breath_gases["plasma"][MOLES])
H.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox)
else
H.failed_last_breath = 0
H.adjustOxyLoss(-5)
gas_breathed = breath_gases["plasma"][MOLES]
H.clear_alert("not_enough_tox")
//Exhale
breath_gases["plasma"][MOLES] -= gas_breathed
breath_gases["co2"][MOLES] += gas_breathed
gas_breathed = 0
//-- TRACES --//
if(breath) // If there's some other shit in the air lets deal with it here.
// N2O
var/SA_pp = breath.get_breath_partial_pressure(breath_gases["n2o"][MOLES])
if(SA_pp > SA_para_min) // Enough to make us paralysed for a bit
H.Paralyse(3) // 3 gives them one second to wake up and run away a bit!
if(SA_pp > SA_sleep_min) // Enough to make us sleep as well
H.Sleeping(max(H.sleeping+2, 10))
else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning
if(prob(20))
H.emote(pick("giggle", "laugh"))
// BZ
var/bz_pp = breath.get_breath_partial_pressure(breath_gases["bz"][MOLES])
if(bz_pp > BZ_trip_balls_min)
H.hallucination += 20
if(prob(33))
H.adjustBrainLoss(3)
else if(bz_pp > 0.01)
H.hallucination += 5//Removed at 2 per tick so this will slowly build up
handle_breath_temperature(breath, H)
breath.garbage_collect()
return 1
/obj/item/organ/lungs/proc/handle_too_little_breath(mob/living/carbon/human/H = null,breath_pp = 0, safe_breath_min = 0, true_pp = 0)
. = 0
if(!H || !safe_breath_min) //the other args are either: Ok being 0 or Specifically handled.
return 0
if(prob(20))
H.emote("gasp")
if(breath_pp > 0)
var/ratio = safe_breath_min/breath_pp
H.adjustOxyLoss(min(5*ratio, HUMAN_MAX_OXYLOSS)) // Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS after all!
H.failed_last_breath = 1
. = true_pp*ratio/6
else
H.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
H.failed_last_breath = 1
/obj/item/organ/lungs/proc/handle_breath_temperature(datum/gas_mixture/breath, mob/living/carbon/human/H) // called by human/life, handles temperatures
if(abs(310.15 - breath.temperature) > 50)
var/species_traits = list()
if(H && H.dna && H.dna.species && H.dna.species.species_traits)
species_traits = H.dna.species.species_traits
if(!(GLOB.mutations_list[COLDRES] in H.dna.mutations) && !(RESISTCOLD in species_traits)) // COLD DAMAGE
switch(breath.temperature)
if(-INFINITY to 120)
H.apply_damage(COLD_GAS_DAMAGE_LEVEL_3, BURN, "head")
if(120 to 200)
H.apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, "head")
if(200 to 260)
H.apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, "head")
if(!(RESISTHOT in species_traits)) // HEAT DAMAGE
switch(breath.temperature)
if(360 to 400)
H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, "head")
if(400 to 1000)
H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head")
if(1000 to INFINITY)
H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head")
/obj/item/organ/lungs/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent("salbutamol", 5)
return S
/obj/item/organ/lungs/plasmaman
name = "plasma filter"
safe_oxygen_min = 0 //We don't breath this
safe_toxins_min = 16 //We breath THIS!
safe_toxins_max = 0
#undef HUMAN_MAX_OXYLOSS
#undef HUMAN_CRIT_MAX_OXYLOSS
#undef HEAT_GAS_DAMAGE_LEVEL_1
#undef HEAT_GAS_DAMAGE_LEVEL_2
#undef HEAT_GAS_DAMAGE_LEVEL_3
#undef COLD_GAS_DAMAGE_LEVEL_1
#undef COLD_GAS_DAMAGE_LEVEL_2
#undef COLD_GAS_DAMAGE_LEVEL_3
+20 -776
View File
@@ -102,666 +102,34 @@
//Looking for brains?
//Try code/modules/mob/living/carbon/brain/brain_item.dm
/obj/item/organ/heart
name = "heart"
icon_state = "heart-on"
zone = "chest"
slot = "heart"
origin_tech = "biotech=5"
// Heart attack code is in code/modules/mob/living/carbon/human/life.dm
var/beating = 1
var/icon_base = "heart"
attack_verb = list("beat", "thumped")
/obj/item/organ/heart/update_icon()
if(beating)
icon_state = "[icon_base]-on"
else
icon_state = "[icon_base]-off"
/obj/item/organ/heart/Remove(mob/living/carbon/M, special = 0)
..()
if(!special)
addtimer(CALLBACK(src, .proc/stop_if_unowned), 120)
/obj/item/organ/heart/proc/stop_if_unowned()
if(!owner)
Stop()
/obj/item/organ/heart/attack_self(mob/user)
..()
if(!beating)
visible_message("<span class='notice'>[user] squeezes [src] to \
make it beat again!</span>", "<span class='notice'>You squeeze \
[src] to make it beat again!</span>")
Restart()
addtimer(CALLBACK(src, .proc/stop_if_unowned), 80)
/obj/item/organ/heart/proc/Stop()
beating = 0
update_icon()
return 1
/obj/item/organ/heart/proc/Restart()
beating = 1
update_icon()
return 1
/obj/item/organ/heart/prepare_eat()
var/obj/S = ..()
S.icon_state = "heart-off"
return S
/obj/item/organ/heart/cursed
name = "cursed heart"
desc = "A heart that, when inserted, will force you to pump it manually."
icon_state = "cursedheart-off"
icon_base = "cursedheart"
origin_tech = "biotech=6"
actions_types = list(/datum/action/item_action/organ_action/cursed_heart)
var/last_pump = 0
var/add_colour = TRUE //So we're not constantly recreating colour datums
var/pump_delay = 30 //you can pump 1 second early, for lag, but no more (otherwise you could spam heal)
var/blood_loss = 100 //600 blood is human default, so 5 failures (below 122 blood is where humans die because reasons?)
//How much to heal per pump, negative numbers would HURT the player
var/heal_brute = 0
var/heal_burn = 0
var/heal_oxy = 0
/obj/item/organ/heart/cursed/attack(mob/living/carbon/human/H, mob/living/carbon/human/user, obj/target)
if(H == user && istype(H))
playsound(user,'sound/effects/singlebeat.ogg',40,1)
user.drop_item()
Insert(user)
else
return ..()
/obj/item/organ/heart/cursed/on_life()
if(world.time > (last_pump + pump_delay))
if(ishuman(owner) && owner.client) //While this entire item exists to make people suffer, they can't control disconnects.
var/mob/living/carbon/human/H = owner
if(H.dna && !(NOBLOOD in H.dna.species.species_traits))
H.blood_volume = max(H.blood_volume - blood_loss, 0)
to_chat(H, "<span class = 'userdanger'>You have to keep pumping your blood!</span>")
if(add_colour)
H.add_client_colour(/datum/client_colour/cursed_heart_blood) //bloody screen so real
add_colour = FALSE
else
last_pump = world.time //lets be extra fair *sigh*
/obj/item/organ/heart/cursed/Insert(mob/living/carbon/M, special = 0)
..()
if(owner)
to_chat(owner, "<span class ='userdanger'>Your heart has been replaced with a cursed one, you have to pump this one manually otherwise you'll die!</span>")
/datum/action/item_action/organ_action/cursed_heart
name = "Pump your blood"
//You are now brea- pumping blood manually
/datum/action/item_action/organ_action/cursed_heart/Trigger()
. = ..()
if(. && istype(target,/obj/item/organ/heart/cursed))
var/obj/item/organ/heart/cursed/cursed_heart = target
if(world.time < (cursed_heart.last_pump + (cursed_heart.pump_delay-10))) //no spam
to_chat(owner, "<span class='userdanger'>Too soon!</span>")
return
cursed_heart.last_pump = world.time
playsound(owner,'sound/effects/singlebeat.ogg',40,1)
to_chat(owner, "<span class = 'notice'>Your heart beats.</span>")
var/mob/living/carbon/human/H = owner
if(istype(H))
if(H.dna && !(NOBLOOD in H.dna.species.species_traits))
H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss*0.5, BLOOD_VOLUME_MAXIMUM)
H.remove_client_colour(/datum/client_colour/cursed_heart_blood)
cursed_heart.add_colour = TRUE
H.adjustBruteLoss(-cursed_heart.heal_brute)
H.adjustFireLoss(-cursed_heart.heal_burn)
H.adjustOxyLoss(-cursed_heart.heal_oxy)
/datum/client_colour/cursed_heart_blood
priority = 100 //it's an indicator you're dieing, so it's very high priority
colour = "red"
#define HUMAN_MAX_OXYLOSS 3
#define HUMAN_CRIT_MAX_OXYLOSS (SSmobs.wait/30)
#define HEAT_GAS_DAMAGE_LEVEL_1 2
#define HEAT_GAS_DAMAGE_LEVEL_2 4
#define HEAT_GAS_DAMAGE_LEVEL_3 8
#define COLD_GAS_DAMAGE_LEVEL_1 0.5
#define COLD_GAS_DAMAGE_LEVEL_2 1.5
#define COLD_GAS_DAMAGE_LEVEL_3 3
/obj/item/organ/lungs
name = "lungs"
icon_state = "lungs"
zone = "chest"
slot = "lungs"
gender = PLURAL
w_class = WEIGHT_CLASS_NORMAL
var/list/breathlevels = list("safe_oxygen_min" = 16,"safe_oxygen_max" = 0,"safe_co2_min" = 0,"safe_co2_max" = 10,
"safe_toxins_min" = 0,"safe_toxins_max" = 0.05,"SA_para_min" = 1,"SA_sleep_min" = 5,"BZ_trip_balls_min" = 1)
//Breath damage
var/safe_oxygen_min = 16 // Minimum safe partial pressure of O2, in kPa
var/safe_oxygen_max = 0
var/safe_co2_min = 0
var/safe_co2_max = 10 // Yes it's an arbitrary value who cares?
var/safe_toxins_min = 0
var/safe_toxins_max = 0.05
var/SA_para_min = 1 //Sleeping agent
var/SA_sleep_min = 5 //Sleeping agent
var/BZ_trip_balls_min = 1 //BZ gas.
var/oxy_breath_dam_min = 1
var/oxy_breath_dam_max = 10
var/co2_breath_dam_min = 1
var/co2_breath_dam_max = 10
var/tox_breath_dam_min = MIN_PLASMA_DAMAGE
var/tox_breath_dam_max = MAX_PLASMA_DAMAGE
/obj/item/organ/lungs/proc/check_breath(datum/gas_mixture/breath, var/mob/living/carbon/human/H)
if((H.status_flags & GODMODE))
return
var/species_traits = list()
if(H && H.dna && H.dna.species && H.dna.species.species_traits)
species_traits = H.dna.species.species_traits
if(!breath || (breath.total_moles() == 0))
if(H.reagents.has_reagent("epinephrine"))
return
if(H.health >= HEALTH_THRESHOLD_CRIT)
H.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
else if(!(NOCRITDAMAGE in species_traits))
H.adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS)
H.failed_last_breath = 1
if(safe_oxygen_min)
H.throw_alert("oxy", /obj/screen/alert/oxy)
else if(safe_toxins_min)
H.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox)
else if(safe_co2_min)
H.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2)
return 0
var/gas_breathed = 0
var/list/breath_gases = breath.gases
breath.assert_gases("o2", "plasma", "co2", "n2o", "bz")
//Partial pressures in our breath
var/O2_pp = breath.get_breath_partial_pressure(breath_gases["o2"][MOLES])
var/Toxins_pp = breath.get_breath_partial_pressure(breath_gases["plasma"][MOLES])
var/CO2_pp = breath.get_breath_partial_pressure(breath_gases["co2"][MOLES])
//-- OXY --//
//Too much oxygen! //Yes, some species may not like it.
if(safe_oxygen_max)
if(O2_pp > safe_oxygen_max)
var/ratio = (breath_gases["o2"][MOLES]/safe_oxygen_max) * 10
H.adjustOxyLoss(Clamp(ratio,oxy_breath_dam_min,oxy_breath_dam_max))
H.throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy)
else
H.clear_alert("too_much_oxy")
//Too little oxygen!
if(safe_oxygen_min)
if(O2_pp < safe_oxygen_min)
gas_breathed = handle_too_little_breath(H,O2_pp,safe_oxygen_min,breath_gases["o2"][MOLES])
H.throw_alert("oxy", /obj/screen/alert/oxy)
else
H.failed_last_breath = 0
if(H.getOxyLoss())
H.adjustOxyLoss(-5)
gas_breathed = breath_gases["o2"][MOLES]
H.clear_alert("oxy")
//Exhale
breath_gases["o2"][MOLES] -= gas_breathed
breath_gases["co2"][MOLES] += gas_breathed
gas_breathed = 0
//-- CO2 --//
//CO2 does not affect failed_last_breath. So if there was enough oxygen in the air but too much co2, this will hurt you, but only once per 4 ticks, instead of once per tick.
if(safe_co2_max)
if(CO2_pp > safe_co2_max)
if(!H.co2overloadtime) // If it's the first breath with too much CO2 in it, lets start a counter, then have them pass out after 12s or so.
H.co2overloadtime = world.time
else if(world.time - H.co2overloadtime > 120)
H.Paralyse(3)
H.adjustOxyLoss(3) // Lets hurt em a little, let them know we mean business
if(world.time - H.co2overloadtime > 300) // They've been in here 30s now, lets start to kill them for their own good!
H.adjustOxyLoss(8)
H.throw_alert("too_much_co2", /obj/screen/alert/too_much_co2)
if(prob(20)) // Lets give them some chance to know somethings not right though I guess.
H.emote("cough")
else
H.co2overloadtime = 0
H.clear_alert("too_much_co2")
//Too little CO2!
if(breathlevels["safe_co2_min"])
if(CO2_pp < safe_co2_min)
gas_breathed = handle_too_little_breath(H,CO2_pp, safe_co2_min,breath_gases["co2"][MOLES])
H.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2)
else
H.failed_last_breath = 0
H.adjustOxyLoss(-5)
gas_breathed = breath_gases["co2"][MOLES]
H.clear_alert("not_enough_co2")
//Exhale
breath_gases["co2"][MOLES] -= gas_breathed
breath_gases["o2"][MOLES] += gas_breathed
gas_breathed = 0
//-- TOX --//
//Too much toxins!
if(safe_toxins_max)
if(Toxins_pp > safe_toxins_max)
var/ratio = (breath_gases["plasma"][MOLES]/safe_toxins_max) * 10
if(H.reagents)
H.reagents.add_reagent("plasma", Clamp(ratio, tox_breath_dam_min, tox_breath_dam_max))
H.throw_alert("tox_in_air", /obj/screen/alert/tox_in_air)
else
H.clear_alert("tox_in_air")
//Too little toxins!
if(safe_toxins_min)
if(Toxins_pp < safe_toxins_min)
gas_breathed = handle_too_little_breath(H,Toxins_pp, safe_toxins_min, breath_gases["plasma"][MOLES])
H.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox)
else
H.failed_last_breath = 0
H.adjustOxyLoss(-5)
gas_breathed = breath_gases["plasma"][MOLES]
H.clear_alert("not_enough_tox")
//Exhale
breath_gases["plasma"][MOLES] -= gas_breathed
breath_gases["co2"][MOLES] += gas_breathed
gas_breathed = 0
//-- TRACES --//
if(breath) // If there's some other shit in the air lets deal with it here.
// N2O
var/SA_pp = breath.get_breath_partial_pressure(breath_gases["n2o"][MOLES])
if(SA_pp > SA_para_min) // Enough to make us paralysed for a bit
H.Paralyse(3) // 3 gives them one second to wake up and run away a bit!
if(SA_pp > SA_sleep_min) // Enough to make us sleep as well
H.Sleeping(max(H.sleeping+2, 10))
else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning
if(prob(20))
H.emote(pick("giggle", "laugh"))
// BZ
var/bz_pp = breath.get_breath_partial_pressure(breath_gases["bz"][MOLES])
if(bz_pp > BZ_trip_balls_min)
H.hallucination += 20
if(prob(33))
H.adjustBrainLoss(3)
else if(bz_pp > 0.01)
H.hallucination += 5//Removed at 2 per tick so this will slowly build up
handle_breath_temperature(breath, H)
breath.garbage_collect()
return 1
/obj/item/organ/lungs/proc/handle_too_little_breath(mob/living/carbon/human/H = null,breath_pp = 0, safe_breath_min = 0, true_pp = 0)
. = 0
if(!H || !safe_breath_min) //the other args are either: Ok being 0 or Specifically handled.
return 0
if(prob(20))
H.emote("gasp")
if(breath_pp > 0)
var/ratio = safe_breath_min/breath_pp
H.adjustOxyLoss(min(5*ratio, HUMAN_MAX_OXYLOSS)) // Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS after all!
H.failed_last_breath = 1
. = true_pp*ratio/6
else
H.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
H.failed_last_breath = 1
/obj/item/organ/lungs/proc/handle_breath_temperature(datum/gas_mixture/breath, mob/living/carbon/human/H) // called by human/life, handles temperatures
if(abs(310.15 - breath.temperature) > 50)
var/species_traits = list()
if(H && H.dna && H.dna.species && H.dna.species.species_traits)
species_traits = H.dna.species.species_traits
if(!(GLOB.mutations_list[COLDRES] in H.dna.mutations) && !(RESISTCOLD in species_traits)) // COLD DAMAGE
switch(breath.temperature)
if(-INFINITY to 120)
H.apply_damage(COLD_GAS_DAMAGE_LEVEL_3, BURN, "head")
if(120 to 200)
H.apply_damage(COLD_GAS_DAMAGE_LEVEL_2, BURN, "head")
if(200 to 260)
H.apply_damage(COLD_GAS_DAMAGE_LEVEL_1, BURN, "head")
if(!(RESISTHOT in species_traits)) // HEAT DAMAGE
switch(breath.temperature)
if(360 to 400)
H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_1, BURN, "head")
if(400 to 1000)
H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head")
if(1000 to INFINITY)
H.apply_damage(HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head")
/obj/item/organ/lungs/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent("salbutamol", 5)
return S
/obj/item/organ/lungs/plasmaman
name = "plasma filter"
safe_oxygen_min = 0 //We don't breath this
safe_toxins_min = 16 //We breath THIS!
safe_toxins_max = 0
#undef HUMAN_MAX_OXYLOSS
#undef HUMAN_CRIT_MAX_OXYLOSS
#undef HEAT_GAS_DAMAGE_LEVEL_1
#undef HEAT_GAS_DAMAGE_LEVEL_2
#undef HEAT_GAS_DAMAGE_LEVEL_3
#undef COLD_GAS_DAMAGE_LEVEL_1
#undef COLD_GAS_DAMAGE_LEVEL_2
#undef COLD_GAS_DAMAGE_LEVEL_3
/obj/item/organ/tongue
name = "tongue"
desc = "A fleshy muscle mostly used for lying."
icon_state = "tonguenormal"
zone = "mouth"
slot = "tongue"
attack_verb = list("licked", "slobbered", "slapped", "frenched", "tongued")
var/list/languages_possible
var/say_mod = null
var/taste_sensitivity = 15 // lower is more sensitive.
/obj/item/organ/tongue/Initialize(mapload)
..()
languages_possible = typecacheof(list(
/datum/language/common,
/datum/language/monkey,
/datum/language/ratvar
))
/obj/item/organ/tongue/get_spans()
return list()
/obj/item/organ/tongue/proc/TongueSpeech(var/message)
return message
/obj/item/organ/tongue/Insert(mob/living/carbon/M, special = 0)
..()
if(say_mod && M.dna && M.dna.species)
M.dna.species.say_mod = say_mod
/obj/item/organ/tongue/Remove(mob/living/carbon/M, special = 0)
..()
if(say_mod && M.dna && M.dna.species)
M.dna.species.say_mod = initial(M.dna.species.say_mod)
/obj/item/organ/tongue/can_speak_in_language(datum/language/dt)
. = is_type_in_typecache(dt, languages_possible)
/obj/item/organ/tongue/lizard
name = "forked tongue"
desc = "A thin and long muscle typically found in reptilian races, apparently moonlights as a nose."
icon_state = "tonguelizard"
say_mod = "hisses"
taste_sensitivity = 10 // combined nose + tongue, extra sensitive
/obj/item/organ/tongue/lizard/TongueSpeech(var/message)
var/regex/lizard_hiss = new("s+", "g")
var/regex/lizard_hiSS = new("S+", "g")
if(copytext(message, 1, 2) != "*")
message = lizard_hiss.Replace(message, "sss")
message = lizard_hiSS.Replace(message, "SSS")
return message
/obj/item/organ/tongue/fly
name = "proboscis"
desc = "A freakish looking meat tube that apparently can take in liquids."
icon_state = "tonguefly"
say_mod = "buzzes"
taste_sensitivity = 25 // you eat vomit, this is a mercy
/obj/item/organ/tongue/fly/TongueSpeech(var/message)
var/regex/fly_buzz = new("z+", "g")
var/regex/fly_buZZ = new("Z+", "g")
if(copytext(message, 1, 2) != "*")
message = fly_buzz.Replace(message, "zzz")
message = fly_buZZ.Replace(message, "ZZZ")
return message
/obj/item/organ/tongue/abductor
name = "superlingual matrix"
desc = "A mysterious structure that allows for instant communication between users. Pretty impressive until you need to eat something."
icon_state = "tongueayylmao"
say_mod = "gibbers"
taste_sensitivity = 101 // ayys cannot taste anything.
/obj/item/organ/tongue/abductor/TongueSpeech(var/message)
//Hacks
var/mob/living/carbon/human/user = usr
var/rendered = "<span class='abductor'><b>[user.name]:</b> [message]</span>"
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
var/obj/item/organ/tongue/T = H.getorganslot("tongue")
if(!T || T.type != type)
continue
else if(H.dna && H.dna.species.id == "abductor" && user.dna && user.dna.species.id == "abductor")
var/datum/species/abductor/Ayy = user.dna.species
var/datum/species/abductor/Byy = H.dna.species
if(Ayy.team != Byy.team)
continue
to_chat(H, rendered)
for(var/mob/M in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(M, user)
to_chat(M, "[link] [rendered]")
return ""
/obj/item/organ/tongue/zombie
name = "rotting tongue"
desc = "Between the decay and the fact that it's just lying there you doubt a tongue has ever seemed less sexy."
icon_state = "tonguezombie"
say_mod = "moans"
taste_sensitivity = 32
/obj/item/organ/tongue/zombie/TongueSpeech(var/message)
var/list/message_list = splittext(message, " ")
var/maxchanges = max(round(message_list.len / 1.5), 2)
for(var/i = rand(maxchanges / 2, maxchanges), i > 0, i--)
var/insertpos = rand(1, message_list.len - 1)
var/inserttext = message_list[insertpos]
if(!(copytext(inserttext, length(inserttext) - 2) == "..."))
message_list[insertpos] = inserttext + "..."
if(prob(20) && message_list.len > 3)
message_list.Insert(insertpos, "[pick("BRAINS", "Brains", "Braaaiinnnsss", "BRAAAIIINNSSS")]...")
return jointext(message_list, " ")
/obj/item/organ/tongue/alien
name = "alien tongue"
desc = "According to leading xenobiologists the evolutionary benefit of having a second mouth in your mouth is \"that it looks badass\"."
icon_state = "tonguexeno"
say_mod = "hisses"
taste_sensitivity = 10 // LIZARDS ARE ALIENS CONFIRMED
/obj/item/organ/tongue/alien/Initialize(mapload)
..()
languages_possible = typecacheof(list(
/datum/language/xenocommon,
/datum/language/common,
/datum/language/ratvar,
/datum/language/monkey))
/obj/item/organ/tongue/alien/TongueSpeech(var/message)
playsound(owner, "hiss", 25, 1, 1)
return message
/obj/item/organ/tongue/bone
name = "bone \"tongue\""
desc = "Apparently skeletons alter the sounds they produce \
through oscillation of their teeth, hence their characteristic \
rattling."
icon_state = "tonguebone"
say_mod = "rattles"
attack_verb = list("bitten", "chattered", "chomped", "enamelled", "boned")
taste_sensitivity = 101 // skeletons cannot taste anything
var/chattering = FALSE
var/phomeme_type = "sans"
var/list/phomeme_types = list("sans", "papyrus")
/obj/item/organ/tongue/bone/New()
. = ..()
phomeme_type = pick(phomeme_types)
/obj/item/organ/tongue/bone/TongueSpeech(var/message)
. = message
if(chattering)
//Annoy everyone nearby with your chattering.
chatter(message, phomeme_type, usr)
/obj/item/organ/tongue/bone/get_spans()
. = ..()
// Feature, if the tongue talks directly, it will speak with its span
switch(phomeme_type)
if("sans")
. |= SPAN_SANS
if("papyrus")
. |= SPAN_PAPYRUS
/obj/item/organ/tongue/bone/plasmaman
name = "plasma bone \"tongue\""
desc = "Like animated skeletons, Plasmamen vibrate their teeth in order to produce speech."
icon_state = "tongueplasma"
/obj/item/organ/tongue/bone/plasmaman/get_spans()
return
/obj/item/organ/tongue/robot
name = "robotic voicebox"
desc = "A voice synthesizer that can interface with organic lifeforms."
status = ORGAN_ROBOTIC
icon_state = "tonguerobot"
say_mod = "states"
attack_verb = list("beeped", "booped")
taste_sensitivity = 25 // not as good as an organic tongue
/obj/item/organ/tongue/robot/Initialize(mapload)
..()
languages_possible = typecacheof(list(
/datum/language/xenocommon,
/datum/language/common,
/datum/language/ratvar,
/datum/language/monkey,
/datum/language/drone,
/datum/language/machine,
/datum/language/swarmer))
/obj/item/organ/tongue/robot/get_spans()
return ..() | SPAN_ROBOT
/obj/item/organ/appendix
name = "appendix"
icon_state = "appendix"
zone = "groin"
slot = "appendix"
var/inflamed = 0
/obj/item/organ/appendix/update_icon()
if(inflamed)
icon_state = "appendixinflamed"
name = "inflamed appendix"
else
icon_state = "appendix"
name = "appendix"
/obj/item/organ/appendix/Remove(mob/living/carbon/M, special = 0)
for(var/datum/disease/appendicitis/A in M.viruses)
A.cure()
inflamed = 1
update_icon()
..()
/obj/item/organ/appendix/Insert(mob/living/carbon/M, special = 0)
..()
if(inflamed)
M.AddDisease(new /datum/disease/appendicitis)
/obj/item/organ/appendix/prepare_eat()
var/obj/S = ..()
if(inflamed)
S.reagents.add_reagent("bad_food", 5)
return S
/mob/living/proc/regenerate_organs()
return 0
/mob/living/carbon/regenerate_organs()
CHECK_DNA_AND_SPECIES(src)
var/breathes = TRUE
var/blooded = TRUE
if(dna && dna.species)
if(NOBREATH in dna.species.species_traits)
breathes = FALSE
if(NOBLOOD in dna.species.species_traits)
blooded = FALSE
if(!(NOBREATH in dna.species.species_traits) && !getorganslot("lungs"))
if(breathes && !getorganslot("lungs"))
var/obj/item/organ/lungs/L = new()
L.Insert(src)
if(!(NOBLOOD in dna.species.species_traits) && !getorganslot("heart"))
if(blooded && !getorganslot("heart"))
var/obj/item/organ/heart/H = new()
H.Insert(src)
if(!getorganslot("tongue"))
var/obj/item/organ/tongue/T
for(var/tongue_type in dna.species.mutant_organs)
if(ispath(tongue_type, /obj/item/organ/tongue))
T = new tongue_type()
T.Insert(src)
if(dna && dna.species)
for(var/tongue_type in dna.species.mutant_organs)
if(ispath(tongue_type, /obj/item/organ/tongue))
T = new tongue_type()
T.Insert(src)
// if they have no mutant tongues, give them a regular one
if(!T)
@@ -778,135 +146,11 @@
E = new()
E.Insert(src)
//Eyes
/obj/item/organ/eyes
name = "eyes"
icon_state = "eyeballs"
desc = "I see you!"
zone = "eyes"
slot = "eye_sight"
var/sight_flags = 0
var/see_in_dark = 2
var/tint = 0
var/eye_color = "" //set to a hex code to override a mob's eye color
var/old_eye_color = "fff"
var/flash_protect = 0
var/see_invisible = SEE_INVISIBLE_LIVING
var/lighting_alpha
/obj/item/organ/eyes/Insert(mob/living/carbon/M, special = 0)
..()
if(ishuman(owner))
var/mob/living/carbon/human/HMN = owner
old_eye_color = HMN.eye_color
if(eye_color)
HMN.eye_color = eye_color
HMN.regenerate_icons()
if(!getorganslot("ears"))
var/obj/item/organ/ears/ears
if(dna && dna.species && dna.species.mutantears)
ears = new dna.species.mutantears
else
eye_color = HMN.eye_color
M.update_tint()
owner.update_sight()
ears = new
/obj/item/organ/eyes/Remove(mob/living/carbon/M, special = 0)
..()
if(ishuman(M) && eye_color)
var/mob/living/carbon/human/HMN = M
HMN.eye_color = old_eye_color
HMN.regenerate_icons()
M.update_tint()
M.update_sight()
/obj/item/organ/eyes/night_vision
name = "shadow eyes"
desc = "A spooky set of eyes that can see in the dark."
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
actions_types = list(/datum/action/item_action/organ_action/use)
var/night_vision = TRUE
/obj/item/organ/eyes/night_vision/ui_action_click()
switch(lighting_alpha)
if (LIGHTING_PLANE_ALPHA_VISIBLE)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
if (LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
if (LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE)
lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
else
lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
owner.update_sight()
/obj/item/organ/eyes/night_vision/alien
name = "alien eyes"
desc = "It turned out they had them after all!"
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
sight_flags = SEE_MOBS
///Robotic
/obj/item/organ/eyes/robotic
name = "robotic eyes"
icon_state = "cybernetic_eyeballs"
desc = "Your vision is augmented."
status = ORGAN_ROBOTIC
/obj/item/organ/eyes/robotic/emp_act(severity)
if(!owner)
return
if(severity > 1)
if(prob(10 * severity))
return
to_chat(owner, "<span class='warning'>Static obfuscates your vision!</span>")
owner.flash_act(visual = 1)
/obj/item/organ/eyes/robotic/xray
name = "X-ray eyes"
desc = "These cybernetic eyes will give you X-ray vision. Blinking is futile."
eye_color = "000"
see_in_dark = 8
sight_flags = SEE_MOBS | SEE_OBJS | SEE_TURFS
/obj/item/organ/eyes/robotic/thermals
name = "Thermals eyes"
desc = "These cybernetic eye implants will give you Thermal vision. Vertical slit pupil included."
eye_color = "FC0"
origin_tech = "materials=5;programming=4;biotech=4;magnets=4;syndicate=1"
sight_flags = SEE_MOBS
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
flash_protect = -1
see_in_dark = 8
/obj/item/organ/eyes/robotic/flashlight
name = "flashlight eyes"
desc = "It's two flashlights rigged together with some wire. Why would you put these in someones head?"
eye_color ="fee5a3"
icon = 'icons/obj/lighting.dmi'
icon_state = "flashlight_eyes"
flash_protect = 2
tint = INFINITY
/obj/item/organ/eyes/robotic/flashlight/emp_act(severity)
return
/obj/item/organ/eyes/robotic/flashlight/Insert(var/mob/living/carbon/M, var/special = 0)
..()
M.set_light(M.light_range + 15, M.light_power + 1)
/obj/item/organ/eyes/robotic/flashlight/Remove(var/mob/living/carbon/M, var/special = 0)
M.set_light(M.light_range -15, M.light_power - 1)
..()
// Welding shield implant
/obj/item/organ/eyes/robotic/shield
name = "shielded robotic eyes"
desc = "These reactive micro-shields will protect you from welders and flashes without obscuring your vision."
origin_tech = "materials=4;biotech=3;engineering=4;plasmatech=3"
flash_protect = 2
/obj/item/organ/eyes/robotic/shield/emp_act(severity)
return
ears.Insert(src)
+200
View File
@@ -0,0 +1,200 @@
/obj/item/organ/tongue
name = "tongue"
desc = "A fleshy muscle mostly used for lying."
icon_state = "tonguenormal"
zone = "mouth"
slot = "tongue"
attack_verb = list("licked", "slobbered", "slapped", "frenched", "tongued")
var/list/languages_possible
var/say_mod = null
var/taste_sensitivity = 15 // lower is more sensitive.
/obj/item/organ/tongue/Initialize(mapload)
..()
languages_possible = typecacheof(list(
/datum/language/common,
/datum/language/monkey,
/datum/language/ratvar
))
/obj/item/organ/tongue/get_spans()
return list()
/obj/item/organ/tongue/proc/TongueSpeech(var/message)
return message
/obj/item/organ/tongue/Insert(mob/living/carbon/M, special = 0)
..()
if(say_mod && M.dna && M.dna.species)
M.dna.species.say_mod = say_mod
/obj/item/organ/tongue/Remove(mob/living/carbon/M, special = 0)
..()
if(say_mod && M.dna && M.dna.species)
M.dna.species.say_mod = initial(M.dna.species.say_mod)
/obj/item/organ/tongue/can_speak_in_language(datum/language/dt)
. = is_type_in_typecache(dt, languages_possible)
/obj/item/organ/tongue/lizard
name = "forked tongue"
desc = "A thin and long muscle typically found in reptilian races, apparently moonlights as a nose."
icon_state = "tonguelizard"
say_mod = "hisses"
taste_sensitivity = 10 // combined nose + tongue, extra sensitive
/obj/item/organ/tongue/lizard/TongueSpeech(var/message)
var/regex/lizard_hiss = new("s+", "g")
var/regex/lizard_hiSS = new("S+", "g")
if(copytext(message, 1, 2) != "*")
message = lizard_hiss.Replace(message, "sss")
message = lizard_hiSS.Replace(message, "SSS")
return message
/obj/item/organ/tongue/fly
name = "proboscis"
desc = "A freakish looking meat tube that apparently can take in liquids."
icon_state = "tonguefly"
say_mod = "buzzes"
taste_sensitivity = 25 // you eat vomit, this is a mercy
/obj/item/organ/tongue/fly/TongueSpeech(var/message)
var/regex/fly_buzz = new("z+", "g")
var/regex/fly_buZZ = new("Z+", "g")
if(copytext(message, 1, 2) != "*")
message = fly_buzz.Replace(message, "zzz")
message = fly_buZZ.Replace(message, "ZZZ")
return message
/obj/item/organ/tongue/abductor
name = "superlingual matrix"
desc = "A mysterious structure that allows for instant communication between users. Pretty impressive until you need to eat something."
icon_state = "tongueayylmao"
say_mod = "gibbers"
taste_sensitivity = 101 // ayys cannot taste anything.
/obj/item/organ/tongue/abductor/TongueSpeech(var/message)
//Hacks
var/mob/living/carbon/human/user = usr
var/rendered = "<span class='abductor'><b>[user.name]:</b> [message]</span>"
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
var/obj/item/organ/tongue/T = H.getorganslot("tongue")
if(!T || T.type != type)
continue
else if(H.dna && H.dna.species.id == "abductor" && user.dna && user.dna.species.id == "abductor")
var/datum/species/abductor/Ayy = user.dna.species
var/datum/species/abductor/Byy = H.dna.species
if(Ayy.team != Byy.team)
continue
to_chat(H, rendered)
for(var/mob/M in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(M, user)
to_chat(M, "[link] [rendered]")
return ""
/obj/item/organ/tongue/zombie
name = "rotting tongue"
desc = "Between the decay and the fact that it's just lying there you doubt a tongue has ever seemed less sexy."
icon_state = "tonguezombie"
say_mod = "moans"
taste_sensitivity = 32
/obj/item/organ/tongue/zombie/TongueSpeech(var/message)
var/list/message_list = splittext(message, " ")
var/maxchanges = max(round(message_list.len / 1.5), 2)
for(var/i = rand(maxchanges / 2, maxchanges), i > 0, i--)
var/insertpos = rand(1, message_list.len - 1)
var/inserttext = message_list[insertpos]
if(!(copytext(inserttext, length(inserttext) - 2) == "..."))
message_list[insertpos] = inserttext + "..."
if(prob(20) && message_list.len > 3)
message_list.Insert(insertpos, "[pick("BRAINS", "Brains", "Braaaiinnnsss", "BRAAAIIINNSSS")]...")
return jointext(message_list, " ")
/obj/item/organ/tongue/alien
name = "alien tongue"
desc = "According to leading xenobiologists the evolutionary benefit of having a second mouth in your mouth is \"that it looks badass\"."
icon_state = "tonguexeno"
say_mod = "hisses"
taste_sensitivity = 10 // LIZARDS ARE ALIENS CONFIRMED
/obj/item/organ/tongue/alien/Initialize(mapload)
..()
languages_possible = typecacheof(list(
/datum/language/xenocommon,
/datum/language/common,
/datum/language/ratvar,
/datum/language/monkey))
/obj/item/organ/tongue/alien/TongueSpeech(var/message)
playsound(owner, "hiss", 25, 1, 1)
return message
/obj/item/organ/tongue/bone
name = "bone \"tongue\""
desc = "Apparently skeletons alter the sounds they produce \
through oscillation of their teeth, hence their characteristic \
rattling."
icon_state = "tonguebone"
say_mod = "rattles"
attack_verb = list("bitten", "chattered", "chomped", "enamelled", "boned")
taste_sensitivity = 101 // skeletons cannot taste anything
var/chattering = FALSE
var/phomeme_type = "sans"
var/list/phomeme_types = list("sans", "papyrus")
/obj/item/organ/tongue/bone/New()
. = ..()
phomeme_type = pick(phomeme_types)
/obj/item/organ/tongue/bone/TongueSpeech(var/message)
. = message
if(chattering)
//Annoy everyone nearby with your chattering.
chatter(message, phomeme_type, usr)
/obj/item/organ/tongue/bone/get_spans()
. = ..()
// Feature, if the tongue talks directly, it will speak with its span
switch(phomeme_type)
if("sans")
. |= SPAN_SANS
if("papyrus")
. |= SPAN_PAPYRUS
/obj/item/organ/tongue/bone/plasmaman
name = "plasma bone \"tongue\""
desc = "Like animated skeletons, Plasmamen vibrate their teeth in order to produce speech."
icon_state = "tongueplasma"
/obj/item/organ/tongue/bone/plasmaman/get_spans()
return
/obj/item/organ/tongue/robot
name = "robotic voicebox"
desc = "A voice synthesizer that can interface with organic lifeforms."
status = ORGAN_ROBOTIC
icon_state = "tonguerobot"
say_mod = "states"
attack_verb = list("beeped", "booped")
taste_sensitivity = 25 // not as good as an organic tongue
/obj/item/organ/tongue/robot/Initialize(mapload)
..()
languages_possible = typecacheof(list(
/datum/language/xenocommon,
/datum/language/common,
/datum/language/ratvar,
/datum/language/monkey,
/datum/language/drone,
/datum/language/machine,
/datum/language/swarmer))
/obj/item/organ/tongue/robot/get_spans()
return ..() | SPAN_ROBOT
+1 -1
View File
@@ -107,7 +107,7 @@
message = lowertext(message)
var/mob/living/list/listeners = list()
for(var/mob/living/L in get_hearers_in_view(8, user))
if(!L.ear_deaf && !L.null_rod_check() && L != user && L.stat != DEAD)
if(L.can_hear() && !L.null_rod_check() && L != user && L.stat != DEAD)
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(istype(H.ears, /obj/item/clothing/ears/earmuffs))