Reviving Fire Fixes and Tweaks PR. (#6129)

This PR revives Burger's PR #5797

Fire extinguishing foam now works properly. It is 3 times stronger than water.

Walking through a foam will extenguish your fire stacks.

Atmos suit max temperature threshold was increased from 30k to 40k. Atmos firefighter suit max temperature was increased from 30k to 45k. Heavy firesuit max temperature was increased from 30k to 55k. Same goes for their helmets.

Firesuits and red/white/atmos hardhats no longer protect wearer from pressure. So people cannot use it in space. For areas with 2000+ KPa fire people need to use atmos voidsuit.

Fixes #867

Cyborg stations now refill cyborg's fire extinguishers. Fixes #6171

Fire now produces CO2 while burning, with amount varying by fire severity
This commit is contained in:
Mykhailo Bykhovtsev
2019-03-22 15:10:42 -07:00
committed by Erki
parent c9a1b968f6
commit 7f0c085b1a
23 changed files with 807 additions and 735 deletions

View File

@@ -155,6 +155,8 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
else
icon_state = "1"
set_light(3, FIRE_LIGHT_1, no_update = TRUE)
air_contents.adjust_gas("carbon_dioxide", air_contents.gas["carbon_dioxide"] + firelevel * 0.07)
for(var/mob/living/L in loc)
L.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure()) //Burn the mobs!

View File

@@ -180,13 +180,13 @@
#define GLOVES_MIN_COLD_PROTECTION_TEMPERATURE 2.0 // For some gloves.
#define SHOE_MIN_COLD_PROTECTION_TEMPERATURE 2.0 // For shoes.
#define SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE 5000 // These need better heat protect, but not as good heat protect as firesuits.
#define FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE 30000 // What max_heat_protection_temperature is set to for firesuit quality headwear. MUST NOT BE 0.
#define FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE 30000 // For fire-helmet quality items. (Red and white hardhats)
#define HELMET_MAX_HEAT_PROTECTION_TEMPERATURE 600 // For normal helmets.
#define ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE 600 // For armor.
#define GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE 1500 // For some gloves.
#define SHOE_MAX_HEAT_PROTECTION_TEMPERATURE 1500 // For shoes.
#define SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE 5000 // These need better heat protect, but not as good heat protect as firesuits.
#define FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE 30000 // What max_heat_protection_temperature is set to for firesuit quality headwear. MUST NOT BE 0.
#define FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE 30000 // For fire-helmet quality items. (Red and white hardhats)
#define HELMET_MAX_HEAT_PROTECTION_TEMPERATURE 600 // For normal helmets.
#define ARMOR_MAX_HEAT_PROTECTION_TEMPERATURE 600 // For armor.
#define GLOVES_MAX_HEAT_PROTECTION_TEMPERATURE 1500 // For some gloves.
#define SHOE_MAX_HEAT_PROTECTION_TEMPERATURE 1500 // For shoes.
// Fire.
#define FIRE_MIN_STACKS -20

File diff suppressed because it is too large Load Diff

View File

@@ -10,12 +10,24 @@
hitsound = 'sound/weapons/towelwhip.ogg'
/obj/item/weapon/towel/attack_self(mob/living/user as mob)
user.visible_message("<span class='notice'>\The [user] uses \the [src] to towel themselves off.</span>")
playsound(user, 'sound/weapons/towelwipe.ogg', 25, 1)
if(user.fire_stacks > 0)
user.fire_stacks = (max(0, user.fire_stacks - 1.5))
else if(user.fire_stacks < 0)
user.fire_stacks = (min(0, user.fire_stacks + 1.5))
attack(user,user)
/obj/item/weapon/towel/attack(mob/living/carbon/human/M as mob, mob/living/carbon/user as mob)
if(istype(M) && user.a_intent == I_HELP)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(user.on_fire)
user.visible_message("<span class='warning'>\The [user] uses \the [src] to pat out \the [M]'s flames with \the [src]!</span>")
playsound(M, 'sound/weapons/towelwhip.ogg', 25, 1)
M.ExtinguishMob(-1)
else
user.visible_message("<span class='notice'>\The [user] starts drying \the [M] off with \the [src]...</span>")
if(do_mob(user, M, 3 SECONDS))
user.visible_message("<span class='notice'>\The [user] dries \the [M] off with \the [src].</span>")
playsound(M, 'sound/weapons/towelwipe.ogg', 25, 1)
M.adjust_fire_stacks(-Clamp(M.fire_stacks,-1.5,1.5))
return
. = ..()
/obj/item/weapon/towel/random/Initialize()
. = ..()

View File

@@ -16,13 +16,11 @@
/obj/item/clothing/head/hardhat/red
icon_state = "hardhat0_red"
name = "firefighter helmet"
item_flags = STOPPRESSUREDAMAGE
heat_protection = HEAD
max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE
/obj/item/clothing/head/hardhat/white
icon_state = "hardhat0_white"
item_flags = STOPPRESSUREDAMAGE
heat_protection = HEAD
max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE
@@ -33,5 +31,6 @@
/obj/item/clothing/head/hardhat/red/atmos
name = "atmospheric firefighter helmet"
desc = "An atmospheric firefighter's helmet, able to keep the user protected from heat and fire."
max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE + 15000
icon_state = "atmos_fire"
item_state = "atmos_fire"

View File

@@ -106,7 +106,7 @@
slot_r_hand_str = "atmos_helm"
)
armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 35, bio = 100, rad = 50)
max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE
max_heat_protection_temperature = FIRE_HELMET_MAX_HEAT_PROTECTION_TEMPERATURE + 10000 // It is a suit designed for fire, enclosed
light_overlay = "helmet_light_dual"
/obj/item/clothing/suit/space/void/atmos
@@ -119,7 +119,7 @@
slot_r_hand_str = "atmos_hardsuit"
)
armor = list(melee = 40, bullet = 5, laser = 20,energy = 5, bomb = 35, bio = 100, rad = 50)
max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE
max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE + 10000 // It is a suit designed for fire, enclosed
//Head of Security
/obj/item/clothing/head/helmet/space/void/hos

View File

@@ -21,7 +21,6 @@
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency_oxygen,/obj/item/weapon/extinguisher)
slowdown = 1.0
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL
item_flags = STOPPRESSUREDAMAGE
heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE
cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
@@ -38,11 +37,13 @@
//icon_state = "thermal"
item_state = "ro_suit"
w_class = 4//bulky item
max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE + 25000
slowdown = 1.5
/obj/item/clothing/suit/fire/atmos
name = "atmospheric technician firesuit"
desc = "A suit that protects against fire and heat, this one is designed for atmospheric technicians."
max_heat_protection_temperature = FIRESUIT_MAX_HEAT_PROTECTION_TEMPERATURE + 15000
icon_state = "atmos_firesuit"
item_state = "atmos_firesuit"

View File

@@ -37,8 +37,7 @@
else
L.bodytemperature = min(L.bodytemperature + 150, 1000)
else
L.adjust_fire_stacks(15)
L.IgniteMob()
L.IgniteMob(15)
return 1
..()
@@ -106,4 +105,4 @@
base_icon_state = "rockyash"
base_icon = 'icons/turf/smooth/rocky_ash.dmi'
desc = "A fine grey ash. Seems to contain medium-sized rocks."
footstep_sound = "gravelstep"
footstep_sound = "gravelstep"

View File

@@ -259,21 +259,14 @@
else
M.visible_message("<span class='warning'>[M] tries to pat out [src]'s flames!</span>",
"<span class='warning'>You try to pat out [src]'s flames! Hot!</span>")
if(do_mob(M, src, 15))
src.fire_stacks -= 0.5
if (prob(10) && (M.fire_stacks <= 0))
M.fire_stacks += 1
M.IgniteMob()
if (M.on_fire)
if(do_mob(M, src, 1.5 SECONDS))
if (M.IgniteMob(prob(10)))
M.visible_message("<span class='danger'>The fire spreads from [src] to [M]!</span>",
"<span class='danger'>The fire spreads to you as well!</span>")
else
src.fire_stacks -= 0.5 //Less effective than stop, drop, and roll - also accounting for the fact that it takes half as long.
if (src.fire_stacks <= 0)
if (src.ExtinguishMob(1))
M.visible_message("<span class='warning'>[M] successfully pats out [src]'s flames.</span>",
"<span class='warning'>You successfully pat out [src]'s flames.</span>")
src.ExtinguishMob()
src.fire_stacks = 0
else
var/t_him = "it"
if (src.gender == MALE)

View File

@@ -1,22 +1,24 @@
/mob/living/carbon/process_resist()
//drop && roll
if(on_fire && !buckled)
fire_stacks -= 1.2
var/obj/effect/decal/cleanable/foam/extinguisher_foam = locate() in src.loc
var/extra = 0
if(extinguisher_foam)
extra = extinguisher_foam.amount * 1.5
ExtinguishMob(1.2 + extra)
Weaken(3)
spin(32,2)
visible_message(
"<span class='danger'>[src] rolls on the floor, trying to put themselves out!</span>",
"<span class='notice'>You stop, drop, and roll!</span>"
)
sleep(30)
sleep(3 SECONDS)
if(fire_stacks <= 0)
visible_message(
"<span class='danger'>[src] has successfully extinguished themselves!</span>",
"<span class='notice'>You extinguish yourself.</span>"
)
ExtinguishMob()
return
..()
@@ -234,4 +236,4 @@
/mob/living/carbon/human/escape_buckle()
if(!restrained())
..()
..()

View File

@@ -63,8 +63,7 @@
if(DROWSY)
drowsyness = max(drowsyness, effect * BLOCKED_MULT(blocked))
if(INCINERATE)
adjust_fire_stacks(effect * BLOCKED_MULT(blocked))
IgniteMob()
IgniteMob(effect * BLOCKED_MULT(blocked))
updatehealth()
return 1
@@ -86,4 +85,4 @@
/mob/living/proc/apply_radiation(var/rads)
total_radiation += rads
if (total_radiation < 0)
total_radiation = 0
total_radiation = 0

View File

@@ -462,8 +462,7 @@ default behaviour is:
BITSET(hud_updateflag, HEALTH_HUD)
BITSET(hud_updateflag, STATUS_HUD)
BITSET(hud_updateflag, LIFE_HUD)
ExtinguishMob()
fire_stacks = 0
ExtinguishMobCompletely()
/mob/living/proc/rejuvenate()
if(!isnull(reagents))
@@ -838,4 +837,4 @@ default behaviour is:
stomach_contents = null
QDEL_NULL(ingested)
return ..()
return ..()

View File

@@ -257,24 +257,42 @@
spawn(1) updatehealth()
return 1
/mob/living/proc/IgniteMob()
/mob/living/proc/IgniteMob(var/fire_stacks_to_add = 0)
if(fire_stacks_to_add)
adjust_fire_stacks(fire_stacks_to_add)
if(fire_stacks > 0 && !on_fire)
on_fire = 1
set_light(light_range + MOB_FIRE_LIGHT_RANGE, light_power + MOB_FIRE_LIGHT_POWER)
update_fire()
return TRUE
/mob/living/proc/ExtinguishMob()
if(on_fire)
return FALSE
/mob/living/proc/ExtinguishMob(var/fire_stacks_to_remove = 0)
if (fire_stacks_to_remove)
adjust_fire_stacks(-fire_stacks_to_remove)
if(fire_stacks <= 0 && on_fire)
on_fire = 0
fire_stacks = 0
set_light(max(0, light_range - MOB_FIRE_LIGHT_RANGE), max(0, light_power - MOB_FIRE_LIGHT_POWER))
update_fire()
return TRUE
return FALSE
/mob/living/proc/ExtinguishMobCompletely()
return ExtinguishMob(fire_stacks)
/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, FIRE_MIN_STACKS, FIRE_MAX_STACKS)
/mob/living/proc/adjust_fire_stacks(var/add_fire_stacks)
fire_stacks = Clamp(fire_stacks + add_fire_stacks, FIRE_MIN_STACKS, FIRE_MAX_STACKS)
return fire_stacks
/mob/living/proc/handle_fire()
if(fire_stacks < 0)
@@ -283,20 +301,19 @@
if(!on_fire)
return 1
else if(fire_stacks <= 0)
ExtinguishMob() //Fire's been put out.
ExtinguishMobCompletely() //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
ExtinguishMobCompletely() //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(2)
IgniteMob()
IgniteMob(2)
/mob/living/proc/get_cold_protection()
return 0
@@ -384,4 +401,4 @@
client.screen += hud_used.hide_actions_toggle
#undef MOB_FIRE_LIGHT_RANGE //These control the intensity and range of light given off by a mob which is on fire
#undef MOB_FIRE_LIGHT_POWER
#undef MOB_FIRE_LIGHT_POWER

View File

@@ -41,7 +41,7 @@
var/update_slimes = 1
var/silent = null // Can't talk. Value goes down every life proc.
var/on_fire = 0 //The "Are we on fire?" var
var/fire_stacks
var/fire_stacks = 0
var/footstep = 0
var/failed_last_breath = 0 //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks.
@@ -77,4 +77,4 @@
var/stop_sight_update = 0 //If true, it won't reset the mob vision flags
var/burn_mod = 1
var/brute_mod = 1
var/brute_mod = 1

View File

@@ -112,6 +112,7 @@ var/global/list/robot_modules = list(
return
/obj/item/weapon/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R, var/rate)
var/obj/item/weapon/extinguisher/E = locate() in src.modules
var/obj/item/device/flash/F = locate() in src.modules
if(F)
if(F.broken)
@@ -121,9 +122,12 @@ var/global/list/robot_modules = list(
else if(F.times_used)
F.times_used--
if(E && E.reagents.total_volume < E.reagents.maximum_volume)
E.reagents.add_reagent("monoammoniumphosphate", E.max_water * 0.2)
if(!synths || !synths.len)
return
for(var/datum/matter_synth/T in synths)
T.add_charge(T.recharge_rate * rate)

View File

@@ -232,8 +232,7 @@ obj/item/weapon/gun/energy/staff/focus/attack_self(mob/living/user as mob)
if(!user.is_wizard())
if(istype(user, /mob/living/carbon/human))
var/mob/living/carbon/human/H = user
H.fire_stacks += 15
H.IgniteMob()
H.IgniteMob(15)
H.visible_message("<span class='danger'>\The [src] explodes in a shower of fire!</span>")
H.drop_item()
qdel(src)
@@ -352,4 +351,4 @@ obj/item/weapon/gun/energy/staff/focus/attack_self(mob/living/user as mob)
H.drop_item()
qdel(src)
return 0
return 1
return 1

View File

@@ -236,14 +236,8 @@
. = ..()
if(istype(M) && isliving(M))
var/mob/living/L = M
var/needed = L.fire_stacks * 10
if(amount > needed)
L.fire_stacks = 0
L.ExtinguishMob()
remove_self(needed)
else
L.adjust_fire_stacks(-(amount / 10))
remove_self(amount)
L.ExtinguishMob(L.on_fire ? amount : amount*0.5)
remove_self(amount)
if(istype(M) && !istype(M, /mob/abstract))
M.color = initial(M.color)

View File

@@ -316,14 +316,8 @@
/datum/reagent/toxin/fertilizer/monoammoniumphosphate/touch_mob(var/mob/living/L, var/amount)
. = ..()
if(istype(L))
var/needed = L.fire_stacks * 10
if(amount > needed)
L.fire_stacks = 0
L.ExtinguishMob()
remove_self(needed)
else
L.adjust_fire_stacks(-amount*0.5)
remove_self(amount)
L.ExtinguishMob(L.on_fire ? amount*3 : amount*1.5)
remove_self(amount)
/datum/reagent/toxin/fertilizer/monoammoniumphosphate/affect_touch(var/mob/living/carbon/slime/S, var/alien, var/removed)
if(istype(S))

View File

@@ -1,67 +1,66 @@
//These spells are given to the owner of a contract when a victim signs it.
//As such they are REALLY REALLY powerful (because the victim is rewarded for signing it, and signing contracts is completely voluntary)
/spell/contract
name = "Contract Spell"
desc = "A spell perfecting the techniques of keeping a servant happy and obedient."
school = "transmutation"
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
var/mob/subject
/spell/contract/New(var/mob/M)
..()
subject = M
name += " ([M.real_name])"
/spell/contract/choose_targets()
return list(subject)
/spell/contract/cast(mob/target,mob/user)
if(!subject)
to_chat(usr, "This spell was not properly given a target. Contact a coder.")
return null
if(istype(target,/list))
target = target[1]
return target
/spell/contract/reward
name = "Reward Contractee"
desc = "A spell that makes your contracted victim feel better."
charge_max = 300
cooldown_min = 100
hud_state = "wiz_jaunt_old"
/spell/contract/reward/cast(mob/living/target,mob/user)
target = ..(target,user)
if(!target)
return
to_chat(target, "<span class='notice'>You feel great!</span>")
target.ExtinguishMob()
/spell/contract/punish
name = "Punish Contractee"
desc = "A spell that sets your contracted victim ablaze."
charge_max = 300
cooldown_min = 100
hud_state = "gen_immolate"
/spell/contract/punish/cast(mob/living/target,mob/user)
target = ..(target,user)
if(!target)
return
to_chat(target, "<span class='danger'>You feel punished!</span>")
target.fire_stacks += 15
target.IgniteMob()
//These spells are given to the owner of a contract when a victim signs it.
//As such they are REALLY REALLY powerful (because the victim is rewarded for signing it, and signing contracts is completely voluntary)
/spell/contract
name = "Contract Spell"
desc = "A spell perfecting the techniques of keeping a servant happy and obedient."
school = "transmutation"
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
var/mob/subject
/spell/contract/New(var/mob/M)
..()
subject = M
name += " ([M.real_name])"
/spell/contract/choose_targets()
return list(subject)
/spell/contract/cast(mob/target,mob/user)
if(!subject)
to_chat(usr, "This spell was not properly given a target. Contact a coder.")
return null
if(istype(target,/list))
target = target[1]
return target
/spell/contract/reward
name = "Extinguish Contractee"
desc = "A spell that extinguishes your contractee from flames."
charge_max = 300
cooldown_min = 100
hud_state = "wiz_jaunt_old"
/spell/contract/reward/cast(mob/living/target,mob/user)
target = ..(target,user)
if(!target)
return
if(target.on_fire && target.fire_stacks > 0)
to_chat(target, "<span class='notice'>Magical energies surround you, putting out all your flames.</span>")
target.ExtinguishMobCompletely()
/spell/contract/punish
name = "Punish Contractee"
desc = "A spell that sets your contracted victim ablaze."
charge_max = 300
cooldown_min = 100
hud_state = "gen_immolate"
/spell/contract/punish/cast(mob/living/target,mob/user)
target = ..(target,user)
if(!target)
return
to_chat(target, "<span class='danger'>Magical energies surround you, immolating you in a furious fashion!</span>")
target.IgniteMob(15)

View File

@@ -52,10 +52,10 @@ var/list/artefact_feedback = list(/obj/structure/closet/wizard/armor = "HS",
var/active_hand = H.hand
to_chat(user, "<span class='warning'>You feel unimaginable agony as your eyes pour over millenia of forbidden knowledge!</span>")
user.show_message("<b>[user]</b> screams in horror!",2)
H.adjust_fire_stacks(2)
H.IgniteMob()
H.updatehealth()
H.ChangeToHusk()
H.adjust_fire_stacks(0, H.fire_stacks)
H.IgniteMob(2)
H.updatehealth()
user.drop_item()
playsound(user, 'sound/hallucinations/i_see_you2.ogg', 100, 1)
if(active_hand)
@@ -229,4 +229,4 @@ var/list/artefact_feedback = list(/obj/structure/closet/wizard/armor = "HS",
/datum/spellbook/spatial = 1,
/datum/spellbook/druid = 1,
/datum/spellbook/necromancer = 1
) //spell's path = cost of spell
) //spell's path = cost of spell