diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index 32543822b9..7d10bd9a6f 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -288,6 +288,7 @@
M.client.eye = src
M.stop_pulling()
M.loc = src
+ M.ExtinguishMob()
if(M.health > -100 && (M.health < 0 || M.sleeping))
M << "\blue You feel a cold liquid surround you. Your skin starts to freeze up."
occupant = M
diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm
index fb51d83c14..337c111799 100644
--- a/code/game/objects/items/weapons/cigs_lighters.dm
+++ b/code/game/objects/items/weapons/cigs_lighters.dm
@@ -31,6 +31,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM
attack_verb = list("burnt", "singed")
/obj/item/weapon/flame/match/process()
+ if(isliving(loc))
+ var/mob/living/M = loc
+ M.IgniteMob()
var/turf/location = get_turf(src)
smoketime--
if(smoketime < 1)
@@ -162,6 +165,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/cigarette/process()
+ if(isliving(loc))
+ var/mob/living/M = loc
+ M.IgniteMob()
var/turf/location = get_turf(src)
smoketime--
if(smoketime < 1)
@@ -444,6 +450,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/weapon/flame/lighter/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
if(!istype(M, /mob))
return
+ M.IgniteMob()
if(istype(M.wear_mask, /obj/item/clothing/mask/cigarette) && user.zone_sel.selecting == "mouth" && lit)
var/obj/item/clothing/mask/cigarette/cig = M.wear_mask
diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm
index 7264b11fe1..800f47773c 100644
--- a/code/game/objects/items/weapons/extinguisher.dm
+++ b/code/game/objects/items/weapons/extinguisher.dm
@@ -13,7 +13,7 @@
force = 10.0
matter = list("metal" = 90)
attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed")
-
+
var/spray_particles = 6
var/spray_amount = 2 //units of liquid per particle
var/max_water = 120
@@ -123,7 +123,7 @@
R.my_atom = W
if(!W || !src) return
src.reagents.trans_to(W, spray_amount)
-
+
for(var/b=0, b<5, b++)
step_towards(W,my_target)
if(!W || !W.reagents) return
@@ -134,6 +134,9 @@
if(!W.reagents)
break
W.reagents.reaction(atm)
+ if(isliving(atm)) //For extinguishing mobs on fire
+ var/mob/living/M = atm
+ M.ExtinguishMob()
if(W.loc == my_target) break
sleep(2)
W.delete()
diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm
index d3f797e2f0..ee56415be7 100644
--- a/code/game/objects/items/weapons/tools.dm
+++ b/code/game/objects/items/weapons/tools.dm
@@ -261,6 +261,9 @@
if (src.welding)
remove_fuel(1)
var/turf/location = get_turf(user)
+ if(isliving(O))
+ var/mob/living/L = O
+ L.IgniteMob()
if (istype(location, /turf))
location.hotspot_expose(700, 50, 1)
return
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 33235ae124..e77f1e602c 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -211,6 +211,11 @@
/obj/machinery/shower/proc/wash(atom/movable/O as obj|mob)
if(!on) return
+ if(isliving(O))
+ var/mob/living/L = O
+ L.ExtinguishMob()
+ L.fire_stacks = -20 //Douse ourselves with water to avoid fire more easily
+
if(iscarbon(O))
var/mob/living/carbon/M = O
if(M.r_hand)
diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm
index 22f9295b82..5eb7e0c65b 100644
--- a/code/modules/clothing/head/misc_special.dm
+++ b/code/modules/clothing/head/misc_special.dm
@@ -159,4 +159,4 @@
desc = "You can hear the distant sounds of rhythmic electronica."
icon_state = "richard"
body_parts_covered = HEAD|FACE
- flags = FPRINT|TABLEPASS|HEADCOVERSEYES|HEADCOVERSMOUTH|BLOCKHAIR
\ No newline at end of file
+ flags = HEADCOVERSEYES|HEADCOVERSMOUTH|BLOCKHAIR
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 7147b85765..0f06e979ad 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -223,7 +223,10 @@
usr << "[t_He] has no pulse[src.client ? "" : " and [t_his] soul has departed"]..."
else
usr << "[t_He] has a pulse!"
-
+ if(fire_stacks)
+ msg += "[t_He] [t_is] covered in some liquid.\n"
+ if(on_fire)
+ msg += "[t_He] [t_is] on fire!.\n"
msg += ""
if(nutrition < 100)
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 6638689887..ce3a5401ae 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -112,6 +112,9 @@
//Handle temperature/pressure differences between body and environment
handle_environment(environment) //Optimized a good bit.
+ //Check if we're on fire
+ handle_fire()
+
//Status updates, death etc.
handle_regular_status_updates() //Optimized a bit
update_canmove()
@@ -788,6 +791,8 @@
if (abs(body_temperature_difference) < 0.5)
return //fuck this precision
+ if (on_fire)
+ return //too busy for pesky convection
if(bodytemperature < species.cold_level_1) //260.15 is 310.15 - 50, the temperature where you start to feel effects.
if(nutrition >= 2) //If we are very, very cold we'll use up quite a bit of nutriment to heat us up.
@@ -1775,5 +1780,15 @@
speech_problem_flag = 1
return stuttering
+/mob/living/carbon/human/handle_fire()
+ if(..())
+ return
+
+ var/burn_temperature = fire_burn_temperature()
+ var/thermal_protection = get_heat_protection(burn_temperature)
+
+ if (thermal_protection < 1 && bodytemperature < burn_temperature)
+ bodytemperature += round(BODYTEMP_HEATING_MAX*(1-thermal_protection), 1)
+
#undef HUMAN_MAX_OXYLOSS
#undef HUMAN_CRIT_MAX_OXYLOSS
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index cc053f219d..19736bad3f 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -126,8 +126,9 @@ Please contact me on #coderbus IRC. ~Carn x
#define LEGCUFF_LAYER 19
#define L_HAND_LAYER 20
#define R_HAND_LAYER 21
-#define TARGETED_LAYER 22 //BS12: Layer for the target overlay from weapon targeting system
-#define TOTAL_LAYERS 22
+#define FIRE_LAYER 22 //If you're on fire
+#define TARGETED_LAYER 23 //BS12: Layer for the target overlay from weapon targeting system
+#define TOTAL_LAYERS 23
//////////////////////////////////
/mob/living/carbon/human
@@ -508,6 +509,7 @@ proc/get_damage_icon_part(damage_state, body_part)
update_inv_handcuffed(0)
update_inv_legcuffed(0)
update_inv_pockets(0)
+ update_fire(0)
UpdateDamageIcon()
update_icons()
//Hud Stuff
@@ -911,6 +913,13 @@ proc/get_damage_icon_part(damage_state, body_part)
if(update_icons) update_icons()
+/mob/living/carbon/human/update_fire(var/update_icons=1)
+ overlays_standing[FIRE_LAYER] = null
+ if(on_fire)
+ overlays_standing[FIRE_LAYER] = image("icon"='icons/mob/OnFire.dmi', "icon_state"="Standing", "layer"=-FIRE_LAYER)
+
+ if(update_icons) update_icons()
+
// Used mostly for creating head items
/mob/living/carbon/human/proc/generate_head_icon()
//gender no longer matters for the mouth, although there should probably be seperate base head icons.
@@ -969,4 +978,5 @@ proc/get_damage_icon_part(damage_state, body_part)
#undef L_HAND_LAYER
#undef R_HAND_LAYER
#undef TARGETED_LAYER
+#undef FIRE_LAYER
#undef TOTAL_LAYERS
diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm
index 20b80c9c89..016f57f18f 100644
--- a/code/modules/mob/living/carbon/monkey/life.dm
+++ b/code/modules/mob/living/carbon/monkey/life.dm
@@ -57,6 +57,9 @@
if(environment) // More error checking -- TLE
handle_environment(environment)
+ //Check if we're on fire
+ handle_fire()
+
//Status updates, death etc.
handle_regular_status_updates()
update_canmove()
@@ -629,3 +632,9 @@
proc/handle_changeling()
if(mind && mind.changeling)
mind.changeling.regenerate()
+
+/mob/living/carbon/monkey/handle_fire()
+ if(..())
+ return
+ adjustFireLoss(6)
+ return
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/monkey/update_icons.dm b/code/modules/mob/living/carbon/monkey/update_icons.dm
index 284f9e288f..ec69d454f6 100644
--- a/code/modules/mob/living/carbon/monkey/update_icons.dm
+++ b/code/modules/mob/living/carbon/monkey/update_icons.dm
@@ -5,7 +5,8 @@
#define M_L_HAND_LAYER 4
#define M_R_HAND_LAYER 5
#define TARGETED_LAYER 6
-#define M_TOTAL_LAYERS 6
+#define M_FIRE_LAYER 6
+#define M_TOTAL_LAYERS 7
/////////////////////////////////
/mob/living/carbon/monkey
@@ -19,6 +20,7 @@
update_inv_r_hand(0)
update_inv_l_hand(0)
update_inv_handcuffed(0)
+ update_fire(0)
update_icons()
//Hud Stuff
update_hud()
@@ -109,6 +111,12 @@
overlays_standing[TARGETED_LAYER] = null
if(update_icons) update_icons()
+/mob/living/carbon/monkey/update_fire(var/update_icons=1)
+ if(on_fire)
+ overlays_standing[M_FIRE_LAYER] = image("icon"='icons/mob/OnFire.dmi', "icon_state"="Standing", "layer"= -M_FIRE_LAYER)
+ else
+ overlays_standing[M_FIRE_LAYER] = null
+ if(update_icons) update_icons()
//Monkey Overlays Indexes////////
#undef M_MASK_LAYER
#undef M_BACK_LAYER
@@ -116,5 +124,6 @@
#undef M_L_HAND_LAYER
#undef M_R_HAND_LAYER
#undef TARGETED_LAYER
+#undef M_FIRE_LAYER
#undef M_TOTAL_LAYERS
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 79537ae833..6eb23964aa 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -281,6 +281,8 @@
C.legcuffed = initial(C.legcuffed)
hud_updateflag |= 1 << HEALTH_HUD
hud_updateflag |= 1 << STATUS_HUD
+ ExtinguishMob()
+ fire_stacks = 0
/mob/living/proc/rejuvenate()
@@ -628,9 +630,21 @@
BD.attack_hand(usr)
C.open()
- //breaking out of handcuffs
+ //drop && roll or breaking out of handcuffs
else if(iscarbon(L))
var/mob/living/carbon/CM = L
+ if(CM.on_fire && CM.canmove)
+ CM.fire_stacks -= 5
+ CM.Weaken(3)
+ CM.spin(32,2)
+ CM.visible_message("[CM] rolls on the floor, trying to put themselves out!", \
+ "You stop, drop, and roll!")
+ sleep(30)
+ if(fire_stacks <= 0)
+ CM.visible_message("[CM] has successfully extinguished themselves!", \
+ "You extinguish yourself.")
+ ExtinguishMob()
+ return
if(CM.handcuffed && CM.canmove && (CM.last_special <= world.time))
CM.next_move = world.time + 100
CM.last_special = world.time + 100
@@ -843,4 +857,22 @@
return 1
/mob/living/proc/slip(var/slipped_on,stun_duration=8)
- return 0
\ No newline at end of file
+ return 0
+
+/mob/living/carbon/proc/spin(spintime, speed)
+ spawn()
+ var/D = dir
+ while(spintime >= speed)
+ sleep(speed)
+ switch(D)
+ if(NORTH)
+ D = EAST
+ if(SOUTH)
+ D = WEST
+ if(EAST)
+ D = SOUTH
+ if(WEST)
+ D = NORTH
+ set_dir(D)
+ spintime -= speed
+ return
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 1afd5b5325..1be8ea4ac9 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -191,3 +191,52 @@
src.visible_message("[user] has [attack_message] [src]!")
spawn(1) updatehealth()
return 1
+
+/mob/living/proc/IgniteMob()
+ if(fire_stacks > 0 && !on_fire)
+ on_fire = 1
+ src.AddLuminosity(3)
+ update_fire()
+
+/mob/living/proc/ExtinguishMob()
+ if(on_fire)
+ on_fire = 0
+ fire_stacks = 0
+ src.AddLuminosity(-3)
+ update_fire()
+
+/mob/living/proc/update_fire()
+ return
+
+/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
+ fire_stacks = Clamp(fire_stacks + add_fire_stacks, min = FIRE_MIN_STACKS, max = FIRE_MAX_STACKS)
+
+/mob/living/proc/handle_fire()
+ if(fire_stacks < 0)
+ fire_stacks = max(0, fire_stacks++) //If we've doused ourselves in water to avoid fire, dry off slowly
+
+ if(!on_fire)
+ return 1
+ else if(fire_stacks <= 0)
+ ExtinguishMob() //Fire's been put out.
+ return 1
+
+ var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
+ if(G.gas["oxygen"] < 1)
+ ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire
+ return 1
+
+ var/turf/location = get_turf(src)
+ location.hotspot_expose(fire_burn_temperature(), 50, 1)
+
+/mob/living/fire_act()
+ adjust_fire_stacks(0.5)
+ IgniteMob()
+
+//Finds the effective temperature that the mob is burning at.
+/mob/living/proc/fire_burn_temperature()
+ if (fire_stacks <= 0)
+ return 0
+
+ //Scale quadratically so that single digit numbers of fire stacks don't burn ridiculously hot.
+ return round(FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE*(fire_stacks/FIRE_MAX_FIRESUIT_STACKS)**2)
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index ecbc51db37..a9cbcbe0dd 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -38,4 +38,6 @@
var/tod = null // Time of death
var/update_slimes = 1
var/silent = null // Can't talk. Value goes down every life proc.
- var/mob_size // Used by lockers.
\ No newline at end of file
+ var/mob_size // Used by lockers.
+ var/on_fire = 0 //The "Are we on fire?" var
+ var/fire_stacks
diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm
index 6e2103e842..e523fab26c 100644
--- a/code/modules/reagents/Chemistry-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents.dm
@@ -258,10 +258,15 @@ datum
if(!cube.wrapped)
cube.Expand()
- reaction_mob(var/mob/M, var/method=TOUCH, var/volume)
+ reaction_mob(var/mob/living/M, var/method=TOUCH, var/volume)
if (istype(M, /mob/living/carbon/slime))
var/mob/living/carbon/slime/S = M
S.apply_water()
+ if(method == TOUCH && isliving(M))
+ M.adjust_fire_stacks(-(volume / 10))
+ if(M.fire_stacks <= 0)
+ M.ExtinguishMob()
+ return
water/holywater
name = "Holy Water"
@@ -911,6 +916,12 @@ datum
M.adjustToxLoss(1)
..()
return
+ reaction_mob(var/mob/living/M, var/method=TOUCH, var/volume)//Splashing people with welding fuel to make them easy to ignite!
+ if(!istype(M, /mob/living))
+ return
+ if(method == TOUCH)
+ M.adjust_fire_stacks(volume / 10)
+ return
space_cleaner
name = "Space cleaner"
@@ -1665,6 +1676,12 @@ datum
src = null
T.assume_gas("volatile_fuel", volume, T20C)
return
+ reaction_mob(var/mob/living/M, var/method=TOUCH, var/volume)//Splashing people with plasma is stronger than fuel!
+ if(!istype(M, /mob/living))
+ return
+ if(method == TOUCH)
+ M.adjust_fire_stacks(volume / 5)
+ return
toxin/lexorin
name = "Lexorin"
@@ -3335,6 +3352,12 @@ datum
usr << "It wasn't enough..."
return
+ reaction_mob(var/mob/living/M, var/method=TOUCH, var/volume)//Splashing people with ethanol isn't quite as good as fuel.
+ if(!istype(M, /mob/living))
+ return
+ if(method == TOUCH)
+ M.adjust_fire_stacks(volume / 15)
+ return
ethanol/beer
name = "Beer"
id = "beer"
diff --git a/code/setup.dm b/code/setup.dm
index 41c2f710d7..4b91223b21 100644
--- a/code/setup.dm
+++ b/code/setup.dm
@@ -77,6 +77,12 @@
#define SHOE_MIN_COLD_PROTECTION_TEMPERATURE 2.0 //For gloves
#define SHOE_MAX_HEAT_PROTECTION_TEMPERATURE 1500 //For gloves
+//Fire
+#define FIRE_MIN_STACKS -20
+#define FIRE_MAX_STACKS 25
+//If the number of stacks goes above this firesuits won't protect you anymore. If not you can walk around while on fire like a badass.
+#define FIRE_MAX_FIRESUIT_STACKS 20
+
#define THROWFORCE_SPEED_DIVISOR 5 //The throwing speed value at which the throwforce multiplier is exactly 1.
#define THROWNOBJ_KNOCKBACK_SPEED 15 //The minumum speed of a thrown object that will cause living mobs it hits to be knocked back.
#define THROWNOBJ_KNOCKBACK_DIVISOR 2 //Affects how much speed the mob is knocked back with
diff --git a/icons/mob/OnFire.dmi b/icons/mob/OnFire.dmi
new file mode 100644
index 0000000000..8bf6e2c774
Binary files /dev/null and b/icons/mob/OnFire.dmi differ