mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-21 04:57:57 +01:00
Refactors ear damage into ear organs (#26044)
* Refactors ear damage into ear organs 🆑 coiax add: Centcom would like to inform all employees that they have ears. add: Adds "ear" organs to all carbons. These organs store ear damage and deafness. A carbon without any ears is deaf. Genetic deafness functions as before. /🆑 - `ear_damage` and `ear_deaf` vars removed from /mob. - All mobs have a `can_hear` proc, which returns TRUE always except for carbons. - Carbons need to have an ear organ that has 0 `deaf` var. - Explanation of how ear damage works is in the code, it hasn't been changed from previously. Deafness is applied in number of Life ticks until you regain hearing, while damage is long team, heals slower, and when high enough, can cause flashbangs to make you go permamently deaf, as before. - Wearing earmuffs halves the healing time of deafness, and promotes healing long term ear damage, as before. Earmuffs now have a secondary flag HEALS_EARS, which currently only they own. * Changes how soundbang deafness works slightly * Ear organ icon * Code review I * Makes fully healing carbons not dependent on having a dna and species * Gives monkeys and aliens ears * Whoops * Split organs into seperate files * Tweaks. * Un-removes brain damage lines * Moved procs onto /mob for ear stuff * Massages things into compiling * Replacement of spam_flag with world.time tracker
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -47,6 +47,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
|
||||
@@ -146,6 +147,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
|
||||
|
||||
@@ -720,6 +720,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()
|
||||
. = ..()
|
||||
|
||||
@@ -275,20 +275,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
|
||||
@@ -308,3 +312,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
|
||||
|
||||
@@ -58,6 +58,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
|
||||
..()
|
||||
|
||||
|
||||
@@ -66,18 +66,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
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
var/default_color = "#FFF" // if alien colors are disabled, this is the color that will be used by that race
|
||||
|
||||
var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows
|
||||
|
||||
|
||||
var/face_y_offset = 0
|
||||
var/hair_y_offset = 0
|
||||
|
||||
|
||||
var/hair_color = null // this allows races to have specific hair colors... if null, it uses the H's hair/facial hair colors. if "mutcolor", it uses the H's mutant_color
|
||||
var/hair_alpha = 255 // the alpha used by the hair. 255 is completely solid, 0 is transparent.
|
||||
|
||||
@@ -69,9 +69,13 @@
|
||||
|
||||
//Eyes
|
||||
var/obj/item/organ/eyes/mutanteyes = /obj/item/organ/eyes
|
||||
///////////
|
||||
// PROCS //
|
||||
///////////
|
||||
|
||||
//Ears
|
||||
var/obj/item/organ/ears/mutantears = /obj/item/organ/ears
|
||||
|
||||
///////////
|
||||
// PROCS //
|
||||
///////////
|
||||
|
||||
|
||||
/datum/species/New()
|
||||
@@ -122,6 +126,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)
|
||||
@@ -139,6 +144,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()
|
||||
|
||||
@@ -44,6 +44,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()
|
||||
@@ -133,15 +134,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
|
||||
|
||||
@@ -123,14 +123,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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -69,7 +69,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
|
||||
@@ -958,10 +958,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")
|
||||
@@ -999,4 +995,4 @@
|
||||
switch(var_name)
|
||||
if("logging")
|
||||
return debug_variable(var_name, logging, 0, src, FALSE)
|
||||
. = ..()
|
||||
. = ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -489,3 +489,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -100,658 +100,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/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)
|
||||
@@ -768,135 +144,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)
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
/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/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
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user