diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index e6155c1edb..dcad7f531e 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -437,3 +437,10 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define GANGSTER_SOLDIER_STARTING_INFLUENCE 5
#define GANGSTER_BOSS_STARTING_INFLUENCE 20
+
+//for determining which type of heartbeat sound is playing
+#define BEAT_FAST 1
+#define BEAT_SLOW 2
+#define BEAT_NONE 0
+
+#define BEAT_CHANNEL 150
diff --git a/code/__DEFINES/misc.dm.rej b/code/__DEFINES/misc.dm.rej
new file mode 100644
index 0000000000..8aeab16ceb
--- /dev/null
+++ b/code/__DEFINES/misc.dm.rej
@@ -0,0 +1,7 @@
+diff a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm (rejected hunks)
+@@ -440,4 +440,4 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
+ #define BEAT_SLOW 2
+ #define BEAT_NONE 0
+
+-#define BEAT_CHANNEL 150 //sound channel for heartbeats
++
diff --git a/code/__DEFINES/server_tools.dm b/code/__DEFINES/server_tools.dm
index 1e57d8cb80..4624c5914f 100644
--- a/code/__DEFINES/server_tools.dm
+++ b/code/__DEFINES/server_tools.dm
@@ -2,7 +2,7 @@
#define REBOOT_MODE_HARD 1
#define REBOOT_MODE_SHUTDOWN 2
-#define IRC_STATUS_THROTTLE 50
+#define IRC_STATUS_THROTTLE 5
//keep these in sync with TGS3
#define SERVICE_WORLD_PARAM "server_service"
diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm
index 5e0ae93d1b..6fea9601b6 100644
--- a/code/__DEFINES/sound.dm
+++ b/code/__DEFINES/sound.dm
@@ -3,6 +3,7 @@
#define CHANNEL_ADMIN 1023
#define CHANNEL_VOX 1022
#define CHANNEL_JUKEBOX 1021
+#define CHANNEL_HEARTBEAT 1019 //sound channel for heartbeats
//Citadel code
#define CHANNEL_PRED 1020
diff --git a/code/__DEFINES/sound.dm.rej b/code/__DEFINES/sound.dm.rej
new file mode 100644
index 0000000000..e47ebb9375
--- /dev/null
+++ b/code/__DEFINES/sound.dm.rej
@@ -0,0 +1,8 @@
+diff a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm (rejected hunks)
+@@ -9,5 +9,5 @@
+ //THIS SHOULD ALWAYS BE THE LOWEST ONE!
+ //KEEP IT UPDATED
+
+-#define CHANNEL_HIGHEST_AVAILABLE 1019
++#define CHANNEL_HIGHEST_AVAILABLE 1018
+
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 0cd21170b9..ad1ee3143b 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -45,6 +45,6 @@
//Gets filled up in create_bodyparts()
var/list/hand_bodyparts = list() //a collection of arms (or actually whatever the fug /bodyparts you monsters use to wreck my systems)
-
+
var/icon_render_key = ""
var/static/list/limb_icon_cache = list()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 0e0f5f7328..8c84024401 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -1,400 +1,407 @@
-/mob/living/carbon/Life()
- set invisibility = 0
- set background = BACKGROUND_ENABLED
-
- if (notransform)
- return
-
- if(damageoverlaytemp)
- damageoverlaytemp = 0
- update_damage_hud()
-
- if(..()) //not dead
- handle_blood()
-
- if(stat != DEAD)
- for(var/V in internal_organs)
- var/obj/item/organ/O = V
- O.on_life()
+/mob/living/carbon/Life()
+ set invisibility = 0
+ set background = BACKGROUND_ENABLED
+
+ if (notransform)
+ return
+
+ if(damageoverlaytemp)
+ damageoverlaytemp = 0
+ update_damage_hud()
+
+ if(..()) //not dead
+ handle_blood()
+
+ if(stat != DEAD)
+ for(var/V in internal_organs)
+ var/obj/item/organ/O = V
+ O.on_life()
if(stat == DEAD)
stop_sound_channel(CHANNEL_HEARTBEAT)
-
- //Updates the number of stored chemicals for powers
- handle_changeling()
-
- if(stat != DEAD)
- return 1
-
-///////////////
-// BREATHING //
-///////////////
-
-//Start of a breath chain, calls breathe()
+
+ //Updates the number of stored chemicals for powers
+ handle_changeling()
+
+ if(stat != DEAD)
+ return 1
+
+///////////////
+// BREATHING //
+///////////////
+
+//Start of a breath chain, calls breathe()
+
/mob/living/carbon/handle_breathing(times_fired)
if((times_fired % 4) == 2 || failed_last_breath)
- breathe() //Breathe per 4 ticks, unless suffocating
- else
- if(istype(loc, /obj/))
- var/obj/location_as_object = loc
- location_as_object.handle_internal_lifeform(src,0)
-
-//Second link in a breath chain, calls check_breath()
-/mob/living/carbon/proc/breathe()
- if(reagents.has_reagent("lexorin"))
- return
- if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
- return
- if(ismob(loc))
- return
-
-
- var/datum/gas_mixture/environment
- if(loc)
- environment = loc.return_air()
-
- var/datum/gas_mixture/breath
-
- if(health <= HEALTH_THRESHOLD_CRIT || (pulledby && pulledby.grab_state >= GRAB_KILL && !getorganslot("breathing_tube")))
- losebreath++
-
- //Suffocate
- if(losebreath > 0)
- losebreath--
- if(prob(10))
- emote("gasp")
- if(istype(loc, /obj/))
- var/obj/loc_as_obj = loc
- loc_as_obj.handle_internal_lifeform(src,0)
- else
- //Breathe from internal
- breath = get_breath_from_internal(BREATH_VOLUME)
-
- if(!breath)
-
- if(isobj(loc)) //Breathe from loc as object
- var/obj/loc_as_obj = loc
- breath = loc_as_obj.handle_internal_lifeform(src, BREATH_VOLUME)
-
- else if(isturf(loc)) //Breathe from loc as turf
- var/breath_moles = 0
- if(environment)
- breath_moles = environment.total_moles()*BREATH_PERCENTAGE
-
- breath = loc.remove_air(breath_moles)
- else //Breathe from loc as obj again
- if(istype(loc, /obj/))
- var/obj/loc_as_obj = loc
- loc_as_obj.handle_internal_lifeform(src,0)
-
- check_breath(breath)
-
- if(breath)
- loc.assume_air(breath)
- air_update_turf()
-
-/mob/living/carbon/proc/has_smoke_protection()
- return 0
-
-
-//Third link in a breath chain, calls handle_breath_temperature()
-/mob/living/carbon/proc/check_breath(datum/gas_mixture/breath)
- if((status_flags & GODMODE))
- return
-
- var/lungs = getorganslot("lungs")
- if(!lungs)
- adjustOxyLoss(2)
-
- //CRIT
- if(!breath || (breath.total_moles() == 0) || !lungs)
- if(reagents.has_reagent("epinephrine") && lungs)
- return
- adjustOxyLoss(1)
- failed_last_breath = 1
- throw_alert("oxy", /obj/screen/alert/oxy)
- return 0
-
- var/safe_oxy_min = 16
- var/safe_co2_max = 10
- var/safe_tox_max = 0.05
- var/SA_para_min = 1
- var/SA_sleep_min = 5
- var/oxygen_used = 0
- var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
-
- var/list/breath_gases = breath.gases
- breath.assert_gases("o2","plasma","co2","n2o", "bz")
-
- var/O2_partialpressure = (breath_gases["o2"][MOLES]/breath.total_moles())*breath_pressure
- var/Toxins_partialpressure = (breath_gases["plasma"][MOLES]/breath.total_moles())*breath_pressure
- var/CO2_partialpressure = (breath_gases["co2"][MOLES]/breath.total_moles())*breath_pressure
-
-
- //OXYGEN
- if(O2_partialpressure < safe_oxy_min) //Not enough oxygen
- if(prob(20))
- emote("gasp")
- if(O2_partialpressure > 0)
- var/ratio = 1 - O2_partialpressure/safe_oxy_min
- adjustOxyLoss(min(5*ratio, 3))
- failed_last_breath = 1
- oxygen_used = breath_gases["o2"][MOLES]*ratio
- else
- adjustOxyLoss(3)
- failed_last_breath = 1
- throw_alert("oxy", /obj/screen/alert/oxy)
-
- else //Enough oxygen
- failed_last_breath = 0
- if(oxyloss)
- adjustOxyLoss(-5)
- oxygen_used = breath_gases["o2"][MOLES]
- clear_alert("oxy")
-
- breath_gases["o2"][MOLES] -= oxygen_used
- breath_gases["co2"][MOLES] += oxygen_used
-
- //CARBON DIOXIDE
- if(CO2_partialpressure > safe_co2_max)
- if(!co2overloadtime)
- co2overloadtime = world.time
- else if(world.time - co2overloadtime > 120)
- Paralyse(3)
- adjustOxyLoss(3)
- if(world.time - co2overloadtime > 300)
- adjustOxyLoss(8)
- if(prob(20))
- emote("cough")
-
- else
- co2overloadtime = 0
-
- //TOXINS/PLASMA
- if(Toxins_partialpressure > safe_tox_max)
- var/ratio = (breath_gases["plasma"][MOLES]/safe_tox_max) * 10
- if(reagents)
- reagents.add_reagent("plasma", Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE))
- throw_alert("tox_in_air", /obj/screen/alert/tox_in_air)
- else
- clear_alert("tox_in_air")
-
- //NITROUS OXIDE
- if(breath_gases["n2o"])
- var/SA_partialpressure = (breath_gases["n2o"][MOLES]/breath.total_moles())*breath_pressure
- if(SA_partialpressure > SA_para_min)
- Paralyse(3)
- if(SA_partialpressure > SA_sleep_min)
- Sleeping(max(sleeping+2, 10))
- else if(SA_partialpressure > 0.01)
- if(prob(20))
- emote(pick("giggle","laugh"))
-
- //BZ (Facepunch port of their Agent B)
- if(breath_gases["bz"])
- var/bz_partialpressure = (breath_gases["bz"][MOLES]/breath.total_moles())*breath_pressure
- if(bz_partialpressure > 1)
- hallucination += 20
- else if(bz_partialpressure > 0.01)
- hallucination += 5//Removed at 2 per tick so this will slowly build up
-
- breath.garbage_collect()
-
- //BREATH TEMPERATURE
- handle_breath_temperature(breath)
-
- return 1
-
-//Fourth and final link in a breath chain
-/mob/living/carbon/proc/handle_breath_temperature(datum/gas_mixture/breath)
- return
-
-/mob/living/carbon/proc/get_breath_from_internal(volume_needed)
- if(internal)
- if(internal.loc != src)
- internal = null
- update_internals_hud_icon(0)
- else if ((!wear_mask || !(wear_mask.flags & MASKINTERNALS)) && !getorganslot("breathing_tube"))
- internal = null
- update_internals_hud_icon(0)
- else
- update_internals_hud_icon(1)
- return internal.remove_air_volume(volume_needed)
-
-/mob/living/carbon/proc/handle_blood()
- return
-
-/mob/living/carbon/proc/handle_changeling()
- if(mind && hud_used && hud_used.lingchemdisplay)
- if(mind.changeling)
- mind.changeling.regenerate(src)
- hud_used.lingchemdisplay.invisibility = 0
- hud_used.lingchemdisplay.maptext = "
[round(mind.changeling.chem_charges)]
"
- else
- hud_used.lingchemdisplay.invisibility = INVISIBILITY_ABSTRACT
-
-
-/mob/living/carbon/handle_mutations_and_radiation()
- if(dna && dna.temporary_mutations.len)
- var/datum/mutation/human/HM
- for(var/mut in dna.temporary_mutations)
- if(dna.temporary_mutations[mut] < world.time)
- if(mut == UI_CHANGED)
- if(dna.previous["UI"])
- dna.uni_identity = merge_text(dna.uni_identity,dna.previous["UI"])
- updateappearance(mutations_overlay_update=1)
- dna.previous.Remove("UI")
- dna.temporary_mutations.Remove(mut)
- continue
- if(mut == UE_CHANGED)
- if(dna.previous["name"])
- real_name = dna.previous["name"]
- name = real_name
- dna.previous.Remove("name")
- if(dna.previous["UE"])
- dna.unique_enzymes = dna.previous["UE"]
- dna.previous.Remove("UE")
- if(dna.previous["blood_type"])
- dna.blood_type = dna.previous["blood_type"]
- dna.previous.Remove("blood_type")
- dna.temporary_mutations.Remove(mut)
- continue
- HM = GLOB.mutations_list[mut]
- HM.force_lose(src)
- dna.temporary_mutations.Remove(mut)
-
- if(radiation)
- radiation = Clamp(radiation, 0, 100)
- switch(radiation)
- if(0 to 50)
- radiation = max(radiation-1,0)
- if(prob(25))
- adjustToxLoss(1)
-
- if(50 to 75)
- radiation = max(radiation-2,0)
- adjustToxLoss(1)
- if(prob(5))
- radiation = max(radiation-5,0)
-
- if(75 to 100)
- radiation = max(radiation-3,0)
- adjustToxLoss(3)
-
-/mob/living/carbon/handle_chemicals_in_body()
- if(reagents)
- reagents.metabolize(src)
-
-
-/mob/living/carbon/handle_stomach()
- set waitfor = 0
- for(var/mob/living/M in stomach_contents)
- if(M.loc != src)
- stomach_contents.Remove(M)
- continue
- if(istype(M, /mob/living/carbon) && stat != DEAD)
- if(M.stat == DEAD)
- M.death(1)
- stomach_contents.Remove(M)
- qdel(M)
- continue
- if(SSmobs.times_fired%3==1)
- if(!(M.status_flags & GODMODE))
- M.adjustBruteLoss(5)
- nutrition += 10
-
-//this updates all special effects: stunned, sleeping, weakened, druggy, stuttering, etc..
-/mob/living/carbon/handle_status_effects()
- ..()
-
- if(staminaloss)
- if(sleeping)
- adjustStaminaLoss(-10)
- else
- adjustStaminaLoss(-3)
-
- if(sleeping)
- handle_dreams()
- AdjustSleeping(-1)
- if(prob(10) && health>HEALTH_THRESHOLD_CRIT)
- emote("snore")
-
- var/restingpwr = 1 + 4 * resting
-
- //Dizziness
- if(dizziness)
- var/client/C = client
- var/pixel_x_diff = 0
- var/pixel_y_diff = 0
- var/temp
- var/saved_dizz = dizziness
- if(C)
- var/oldsrc = src
- var/amplitude = dizziness*(sin(dizziness * 0.044 * world.time) + 1) / 70 // This shit is annoying at high strength
- src = null
- spawn(0)
- if(C)
- temp = amplitude * sin(0.008 * saved_dizz * world.time)
- pixel_x_diff += temp
- C.pixel_x += temp
- temp = amplitude * cos(0.008 * saved_dizz * world.time)
- pixel_y_diff += temp
- C.pixel_y += temp
- sleep(3)
- if(C)
- temp = amplitude * sin(0.008 * saved_dizz * world.time)
- pixel_x_diff += temp
- C.pixel_x += temp
- temp = amplitude * cos(0.008 * saved_dizz * world.time)
- pixel_y_diff += temp
- C.pixel_y += temp
- sleep(3)
- if(C)
- C.pixel_x -= pixel_x_diff
- C.pixel_y -= pixel_y_diff
- src = oldsrc
- dizziness = max(dizziness - restingpwr, 0)
-
- if(drowsyness)
- drowsyness = max(drowsyness - restingpwr, 0)
- blur_eyes(2)
- if(prob(5))
- AdjustSleeping(1)
- Paralyse(5)
-
- //Jitteryness
- if(jitteriness)
- do_jitter_animation(jitteriness)
- jitteriness = max(jitteriness - restingpwr, 0)
-
- if(stuttering)
- stuttering = max(stuttering-1, 0)
-
- if(slurring)
- slurring = max(slurring-1,0)
-
- if(cultslurring)
- cultslurring = max(cultslurring-1, 0)
-
- if(silent)
- silent = max(silent-1, 0)
-
- if(druggy)
- adjust_drugginess(-1)
-
- if(hallucination)
- spawn handle_hallucinations()
- hallucination = max(hallucination-2,0)
-
-//used in human and monkey handle_environment()
-/mob/living/carbon/proc/natural_bodytemperature_stabilization()
- var/body_temperature_difference = 310.15 - bodytemperature
- switch(bodytemperature)
- if(-INFINITY to 260.15) //260.15 is 310.15 - 50, the temperature where you start to feel effects.
- bodytemperature += max((body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM)
- if(260.15 to 310.15)
- bodytemperature += max(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, min(body_temperature_difference, BODYTEMP_AUTORECOVERY_MINIMUM/4))
- if(310.15 to 360.15)
- bodytemperature += min(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, max(body_temperature_difference, -BODYTEMP_AUTORECOVERY_MINIMUM/4))
- if(360.15 to INFINITY) //360.15 is 310.15 + 50, the temperature where you start to feel effects.
- //We totally need a sweat system cause it totally makes sense...~
- bodytemperature += min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers
+ breathe() //Breathe per 4 ticks, unless suffocating
+ else
+ if(istype(loc, /obj/))
+ var/obj/location_as_object = loc
+ location_as_object.handle_internal_lifeform(src,0)
+
+//Second link in a breath chain, calls check_breath()
+/mob/living/carbon/proc/breathe()
+ if(reagents.has_reagent("lexorin"))
+ return
+ if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
+ return
+ if(ismob(loc))
+ return
+
+
+ var/datum/gas_mixture/environment
+ if(loc)
+ environment = loc.return_air()
+
+ var/datum/gas_mixture/breath
+
+ if(health <= HEALTH_THRESHOLD_CRIT || (pulledby && pulledby.grab_state >= GRAB_KILL && !getorganslot("breathing_tube")))
+ losebreath++
+
+ //Suffocate
+ if(losebreath > 0)
+ losebreath--
+ if(prob(10))
+ emote("gasp")
+ if(istype(loc, /obj/))
+ var/obj/loc_as_obj = loc
+ loc_as_obj.handle_internal_lifeform(src,0)
+ else
+ //Breathe from internal
+ breath = get_breath_from_internal(BREATH_VOLUME)
+
+ if(!breath)
+
+ if(isobj(loc)) //Breathe from loc as object
+ var/obj/loc_as_obj = loc
+ breath = loc_as_obj.handle_internal_lifeform(src, BREATH_VOLUME)
+
+ else if(isturf(loc)) //Breathe from loc as turf
+ var/breath_moles = 0
+ if(environment)
+ breath_moles = environment.total_moles()*BREATH_PERCENTAGE
+
+ breath = loc.remove_air(breath_moles)
+ else //Breathe from loc as obj again
+ if(istype(loc, /obj/))
+ var/obj/loc_as_obj = loc
+ loc_as_obj.handle_internal_lifeform(src,0)
+
+ check_breath(breath)
+
+ if(breath)
+ loc.assume_air(breath)
+ air_update_turf()
+
+/mob/living/carbon/proc/has_smoke_protection()
+ return 0
+
+
+//Third link in a breath chain, calls handle_breath_temperature()
+/mob/living/carbon/proc/check_breath(datum/gas_mixture/breath)
+ if((status_flags & GODMODE))
+ return
+
+ var/lungs = getorganslot("lungs")
+ if(!lungs)
+ adjustOxyLoss(2)
+
+ //CRIT
+ if(!breath || (breath.total_moles() == 0) || !lungs)
+ if(reagents.has_reagent("epinephrine") && lungs)
+ return
+ adjustOxyLoss(1)
+ failed_last_breath = 1
+ throw_alert("oxy", /obj/screen/alert/oxy)
+ return 0
+
+ var/safe_oxy_min = 16
+ var/safe_co2_max = 10
+ var/safe_tox_max = 0.05
+ var/SA_para_min = 1
+ var/SA_sleep_min = 5
+ var/oxygen_used = 0
+ var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
+
+ var/list/breath_gases = breath.gases
+ breath.assert_gases("o2","plasma","co2","n2o", "bz")
+
+ var/O2_partialpressure = (breath_gases["o2"][MOLES]/breath.total_moles())*breath_pressure
+ var/Toxins_partialpressure = (breath_gases["plasma"][MOLES]/breath.total_moles())*breath_pressure
+ var/CO2_partialpressure = (breath_gases["co2"][MOLES]/breath.total_moles())*breath_pressure
+
+
+ //OXYGEN
+ if(O2_partialpressure < safe_oxy_min) //Not enough oxygen
+ if(prob(20))
+ emote("gasp")
+ if(O2_partialpressure > 0)
+ var/ratio = 1 - O2_partialpressure/safe_oxy_min
+ adjustOxyLoss(min(5*ratio, 3))
+ failed_last_breath = 1
+ oxygen_used = breath_gases["o2"][MOLES]*ratio
+ else
+ adjustOxyLoss(3)
+ failed_last_breath = 1
+ throw_alert("oxy", /obj/screen/alert/oxy)
+
+ else //Enough oxygen
+ failed_last_breath = 0
+ if(oxyloss)
+ adjustOxyLoss(-5)
+ oxygen_used = breath_gases["o2"][MOLES]
+ clear_alert("oxy")
+
+ breath_gases["o2"][MOLES] -= oxygen_used
+ breath_gases["co2"][MOLES] += oxygen_used
+
+ //CARBON DIOXIDE
+ if(CO2_partialpressure > safe_co2_max)
+ if(!co2overloadtime)
+ co2overloadtime = world.time
+ else if(world.time - co2overloadtime > 120)
+ Paralyse(3)
+ adjustOxyLoss(3)
+ if(world.time - co2overloadtime > 300)
+ adjustOxyLoss(8)
+ if(prob(20))
+ emote("cough")
+
+ else
+ co2overloadtime = 0
+
+ //TOXINS/PLASMA
+ if(Toxins_partialpressure > safe_tox_max)
+ var/ratio = (breath_gases["plasma"][MOLES]/safe_tox_max) * 10
+ if(reagents)
+ reagents.add_reagent("plasma", Clamp(ratio, MIN_PLASMA_DAMAGE, MAX_PLASMA_DAMAGE))
+ throw_alert("tox_in_air", /obj/screen/alert/tox_in_air)
+ else
+ clear_alert("tox_in_air")
+
+ //NITROUS OXIDE
+ if(breath_gases["n2o"])
+ var/SA_partialpressure = (breath_gases["n2o"][MOLES]/breath.total_moles())*breath_pressure
+ if(SA_partialpressure > SA_para_min)
+ Paralyse(3)
+ if(SA_partialpressure > SA_sleep_min)
+ Sleeping(max(sleeping+2, 10))
+ else if(SA_partialpressure > 0.01)
+ if(prob(20))
+ emote(pick("giggle","laugh"))
+
+ //BZ (Facepunch port of their Agent B)
+ if(breath_gases["bz"])
+ var/bz_partialpressure = (breath_gases["bz"][MOLES]/breath.total_moles())*breath_pressure
+ if(bz_partialpressure > 1)
+ hallucination += 20
+ else if(bz_partialpressure > 0.01)
+ hallucination += 5//Removed at 2 per tick so this will slowly build up
+
+ breath.garbage_collect()
+
+ //BREATH TEMPERATURE
+ handle_breath_temperature(breath)
+
+ return 1
+
+//Fourth and final link in a breath chain
+/mob/living/carbon/proc/handle_breath_temperature(datum/gas_mixture/breath)
+ return
+
+/mob/living/carbon/proc/get_breath_from_internal(volume_needed)
+ if(internal)
+ if(internal.loc != src)
+ internal = null
+ update_internals_hud_icon(0)
+ else if ((!wear_mask || !(wear_mask.flags & MASKINTERNALS)) && !getorganslot("breathing_tube"))
+ internal = null
+ update_internals_hud_icon(0)
+ else
+ update_internals_hud_icon(1)
+ return internal.remove_air_volume(volume_needed)
+
+/mob/living/carbon/proc/handle_blood()
+ return
+
+/mob/living/carbon/proc/handle_changeling()
+ if(mind && hud_used && hud_used.lingchemdisplay)
+ if(mind.changeling)
+ mind.changeling.regenerate(src)
+ hud_used.lingchemdisplay.invisibility = 0
+ hud_used.lingchemdisplay.maptext = "[round(mind.changeling.chem_charges)]
"
+ else
+ hud_used.lingchemdisplay.invisibility = INVISIBILITY_ABSTRACT
+
+
+/mob/living/carbon/handle_mutations_and_radiation()
+ if(dna && dna.temporary_mutations.len)
+ var/datum/mutation/human/HM
+ for(var/mut in dna.temporary_mutations)
+ if(dna.temporary_mutations[mut] < world.time)
+ if(mut == UI_CHANGED)
+ if(dna.previous["UI"])
+ dna.uni_identity = merge_text(dna.uni_identity,dna.previous["UI"])
+ updateappearance(mutations_overlay_update=1)
+ dna.previous.Remove("UI")
+ dna.temporary_mutations.Remove(mut)
+ continue
+ if(mut == UE_CHANGED)
+ if(dna.previous["name"])
+ real_name = dna.previous["name"]
+ name = real_name
+ dna.previous.Remove("name")
+ if(dna.previous["UE"])
+ dna.unique_enzymes = dna.previous["UE"]
+ dna.previous.Remove("UE")
+ if(dna.previous["blood_type"])
+ dna.blood_type = dna.previous["blood_type"]
+ dna.previous.Remove("blood_type")
+ dna.temporary_mutations.Remove(mut)
+ continue
+ HM = GLOB.mutations_list[mut]
+ HM.force_lose(src)
+ dna.temporary_mutations.Remove(mut)
+
+ if(radiation)
+ radiation = Clamp(radiation, 0, 100)
+ switch(radiation)
+ if(0 to 50)
+ radiation = max(radiation-1,0)
+ if(prob(25))
+ adjustToxLoss(1)
+
+ if(50 to 75)
+ radiation = max(radiation-2,0)
+ adjustToxLoss(1)
+ if(prob(5))
+ radiation = max(radiation-5,0)
+
+ if(75 to 100)
+ radiation = max(radiation-3,0)
+ adjustToxLoss(3)
+
+/mob/living/carbon/handle_chemicals_in_body()
+ if(reagents)
+ reagents.metabolize(src)
+
+
+/mob/living/carbon/handle_stomach()
+ set waitfor = 0
+ for(var/mob/living/M in stomach_contents)
+ if(M.loc != src)
+ stomach_contents.Remove(M)
+ continue
+ if(istype(M, /mob/living/carbon) && stat != DEAD)
+ if(M.stat == DEAD)
+ M.death(1)
+ stomach_contents.Remove(M)
+ qdel(M)
+ continue
+ if(SSmobs.times_fired%3==1)
+ if(!(M.status_flags & GODMODE))
+ M.adjustBruteLoss(5)
+ nutrition += 10
+
+//this updates all special effects: stunned, sleeping, weakened, druggy, stuttering, etc..
+/mob/living/carbon/handle_status_effects()
+ ..()
+
+ if(staminaloss)
+ if(sleeping)
+ adjustStaminaLoss(-10)
+ else
+ adjustStaminaLoss(-3)
+
+ if(sleeping)
+ handle_dreams()
+ AdjustSleeping(-1)
+ if(prob(10) && health>HEALTH_THRESHOLD_CRIT)
+ emote("snore")
+
+ var/restingpwr = 1 + 4 * resting
+
+ //Dizziness
+ if(dizziness)
+ var/client/C = client
+ var/pixel_x_diff = 0
+ var/pixel_y_diff = 0
+ var/temp
+ var/saved_dizz = dizziness
+ if(C)
+ var/oldsrc = src
+ var/amplitude = dizziness*(sin(dizziness * 0.044 * world.time) + 1) / 70 // This shit is annoying at high strength
+ src = null
+ spawn(0)
+ if(C)
+ temp = amplitude * sin(0.008 * saved_dizz * world.time)
+ pixel_x_diff += temp
+ C.pixel_x += temp
+ temp = amplitude * cos(0.008 * saved_dizz * world.time)
+ pixel_y_diff += temp
+ C.pixel_y += temp
+ sleep(3)
+ if(C)
+ temp = amplitude * sin(0.008 * saved_dizz * world.time)
+ pixel_x_diff += temp
+ C.pixel_x += temp
+ temp = amplitude * cos(0.008 * saved_dizz * world.time)
+ pixel_y_diff += temp
+ C.pixel_y += temp
+ sleep(3)
+ if(C)
+ C.pixel_x -= pixel_x_diff
+ C.pixel_y -= pixel_y_diff
+ src = oldsrc
+ dizziness = max(dizziness - restingpwr, 0)
+
+ if(drowsyness)
+ drowsyness = max(drowsyness - restingpwr, 0)
+ blur_eyes(2)
+ if(prob(5))
+ AdjustSleeping(1)
+ Paralyse(5)
+
+ //Jitteriness
+ if(jitteriness)
+ do_jitter_animation(jitteriness)
+ jitteriness = max(jitteriness - restingpwr, 0)
+ var/obj/item/organ/heart/heart = getorgan(/obj/item/organ/heart)
+ if(heart)
+ if(!heart.beat || heart.beat == BEAT_SLOW)
+ stop_sound_channel(BEAT_CHANNEL)
+ playsound_local(src,'sound/health/fastbeat.ogg',40,0, channel = BEAT_CHANNEL)
+ heart.beat = BEAT_FAST
+
+ if(stuttering)
+ stuttering = max(stuttering-1, 0)
+
+ if(slurring)
+ slurring = max(slurring-1,0)
+
+ if(cultslurring)
+ cultslurring = max(cultslurring-1, 0)
+
+ if(silent)
+ silent = max(silent-1, 0)
+
+ if(druggy)
+ adjust_drugginess(-1)
+
+ if(hallucination)
+ spawn handle_hallucinations()
+ hallucination = max(hallucination-2,0)
+
+//used in human and monkey handle_environment()
+/mob/living/carbon/proc/natural_bodytemperature_stabilization()
+ var/body_temperature_difference = 310.15 - bodytemperature
+ switch(bodytemperature)
+ if(-INFINITY to 260.15) //260.15 is 310.15 - 50, the temperature where you start to feel effects.
+ bodytemperature += max((body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM)
+ if(260.15 to 310.15)
+ bodytemperature += max(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, min(body_temperature_difference, BODYTEMP_AUTORECOVERY_MINIMUM/4))
+ if(310.15 to 360.15)
+ bodytemperature += min(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, max(body_temperature_difference, -BODYTEMP_AUTORECOVERY_MINIMUM/4))
+ if(360.15 to INFINITY) //360.15 is 310.15 + 50, the temperature where you start to feel effects.
+ //We totally need a sweat system cause it totally makes sense...~
+ bodytemperature += min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers
diff --git a/code/modules/mob/living/carbon/life.dm.rej b/code/modules/mob/living/carbon/life.dm.rej
new file mode 100644
index 0000000000..8cc1950622
--- /dev/null
+++ b/code/modules/mob/living/carbon/life.dm.rej
@@ -0,0 +1,19 @@
+diff a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm (rejected hunks)
+@@ -347,16 +347,10 @@
+ AdjustSleeping(20)
+ Unconscious(100)
+
+- //Jitteryness
++ //Jitteriness
+ if(jitteriness)
+ do_jitter_animation(jitteriness)
+ jitteriness = max(jitteriness - restingpwr, 0)
+- var/obj/item/organ/heart/heart = getorgan(/obj/item/organ/heart)
+- if(heart)
+- if(!heart.beat || heart.beat == BEAT_SLOW)
+- stop_sound_channel(BEAT_CHANNEL)
+- playsound_local(src,'sound/health/fastbeat.ogg',40,0, channel = BEAT_CHANNEL)
+- heart.beat = BEAT_FAST
+
+ if(stuttering)
+ stuttering = max(stuttering-1, 0)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
index 8f158c6b05..6f97737616 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
@@ -185,14 +185,15 @@ Difficulty: Medium
negative = !negative //invert it for the swoop down later
var/oldtransform = transform
- animate(src, transform = matrix()*0.9, time = 3, easing = BOUNCE_EASING)
+ alpha = 255
+ animate(src, alpha = 204, transform = matrix()*0.9, time = 3, easing = BOUNCE_EASING)
for(var/i in 1 to 3)
sleep(1)
if(QDELETED(src) || stat == DEAD) //we got hit and died, rip us
qdel(F)
swooping &= ~SWOOP_DAMAGEABLE
return
- animate(src, transform = matrix()*0.7, time = 7)
+ animate(src, alpha = 100, transform = matrix()*0.7, time = 7)
swooping |= SWOOP_INVULNERABLE
mouse_opacity = 0
sleep(7)
@@ -232,7 +233,7 @@ Difficulty: Medium
negative = TRUE
new /obj/effect/temp_visual/dragon_flight/end(loc, negative)
new /obj/effect/temp_visual/dragon_swoop(loc)
- animate(src, transform = oldtransform, time = 5)
+ animate(src, alpha = 255, transform = oldtransform, time = 5)
sleep(5)
swooping &= ~SWOOP_INVULNERABLE
mouse_opacity = initial(mouse_opacity)
diff --git a/code/modules/server_tools/server_tools.dm b/code/modules/server_tools/server_tools.dm
index b3678cc525..38a172372b 100644
--- a/code/modules/server_tools/server_tools.dm
+++ b/code/modules/server_tools/server_tools.dm
@@ -73,7 +73,7 @@ GLOBAL_PROTECT(reboot_mode)
if(rtod - last_irc_status < IRC_STATUS_THROTTLE)
return
last_irc_status = rtod
- return "[GLOB.clients.len] players on [SSmapping.config.map_name], Mode: [GLOB.master_mode]; Round [SSticker.HasRoundStarted() ? (SSticker.IsRoundInProgress() ? "Active" : "Finishing") : "Starting"] -- [config.server ? config.server : "byond://[address]:[port]"]"
+ return "[GLOB.clients.len] players on [SSmapping.config.map_name], Mode: [GLOB.master_mode]; Round [SSticker.HasRoundStarted() ? (SSticker.IsRoundInProgress() ? "Active" : "Finishing") : "Starting"] -- [config.server ? config.server : world.internet_address]"
if(SERVICE_CMD_ADMIN_MSG)
return IrcPm(params[SERVICE_CMD_PARAM_TARGET], params[SERVICE_CMD_PARAM_MESSAGE], params[SERVICE_CMD_PARAM_SENDER])
diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm
index 1e81c1c609..223345cd81 100644
--- a/code/modules/surgery/organs/heart.dm
+++ b/code/modules/surgery/organs/heart.dm
@@ -8,6 +8,7 @@
var/beating = 1
var/icon_base = "heart"
attack_verb = list("beat", "thumped")
+ var/beat = BEAT_NONE//is this mob having a heatbeat sound played? if so, which?
/obj/item/organ/heart/update_icon()
if(beating)
@@ -67,6 +68,21 @@
H.playsound_local(get_turf(H),fastbeat,40,0, channel = CHANNEL_HEARTBEAT)
beat = BEAT_FAST
+/obj/item/organ/heart/on_life()
+ if(owner.client)
+ var/mob/living/carbon/H = owner
+ if(H.health <= HEALTH_THRESHOLD_CRIT && beat != BEAT_SLOW)
+ beat = BEAT_SLOW
+ H.playsound_local(get_turf(H),'sound/health/slowbeat.ogg',40,0, channel = CHANNEL_HEARTBEAT)
+ to_chat(owner, "You feel your heart slow down...")
+ if(beat == BEAT_SLOW && H.health > HEALTH_THRESHOLD_CRIT)
+ H.stop_sound_channel(CHANNEL_HEARTBEAT)
+ beat = BEAT_NONE
+
+ if(H.jitteriness)
+ if(!beat || beat == BEAT_SLOW)
+ H.playsound_local(get_turf(H),'sound/health/fastbeat.ogg',40,0, channel = CHANNEL_HEARTBEAT)
+ beat = BEAT_FAST
/obj/item/organ/heart/cursed
name = "cursed heart"
diff --git a/html/changelogs/AutoChangeLog-pr-1812.yml b/html/changelogs/AutoChangeLog-pr-1812.yml
new file mode 100644
index 0000000000..762c98787f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-1812.yml
@@ -0,0 +1,4 @@
+author: "Tacolizard"
+delete-after: True
+changes:
+ - rscadd: "NanoTrasen has now outfitted their employees with Extra-Loud(TM) Genetically Modified Hearts! Now you can hear your heart about to explode when the clown shoots you full of meth, or hear it slowly coming to a stop as you bleed out in critical condition after being toolboxed by an unknown gas-mask wearing assistant."
diff --git a/icons/mob/lavaland/dragon.dmi b/icons/mob/lavaland/dragon.dmi
index 2a5e20a671..7cc2b92a17 100644
Binary files a/icons/mob/lavaland/dragon.dmi and b/icons/mob/lavaland/dragon.dmi differ
diff --git a/sound/health/fastbeat.ogg b/sound/health/fastbeat.ogg
new file mode 100644
index 0000000000..29df92812b
Binary files /dev/null and b/sound/health/fastbeat.ogg differ
diff --git a/sound/health/slowbeat.ogg b/sound/health/slowbeat.ogg
new file mode 100644
index 0000000000..a44b609eeb
Binary files /dev/null and b/sound/health/slowbeat.ogg differ