mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-01-07 08:02:49 +00:00
Adds new color coded fires, determined by the temperature of the air. This will allow you to roughly approximate the temperature of fires even from the other side of walls based on their glow. In order from coolest to hottest (all temperatures are in Kelvin): - "Black fire": Below 75K - Red fire: Between 75K and 1100K - Orange fire: Between 1100K and 1300K - Yellow fire: Between 1300K and 1500K - White fire: Between 1500K and 1800K - Cyan fire: Between 1800K and 5300K - Blue fire: Between 5300K and 7150K - Dark Blue / Purple fire: Between 7150K and 9000K - "Rainbow Fire": Over 9000K Due to some issues with sprite editing, I temporarily disabled the use of 2/3 of the fire tile sprites until I can properly update them while maintaining their transparent portions. Until this is done,, all fires will use the highest firelevel sprite set.
412 lines
12 KiB
Plaintext
412 lines
12 KiB
Plaintext
/*
|
|
|
|
Making Bombs with ZAS:
|
|
Make burny fire with lots of burning
|
|
Draw off 5000K gas from burny fire
|
|
Separate gas into oxygen and plasma components
|
|
Obtain plasma and oxygen tanks filled up about 50-75% with normal-temp gas
|
|
Fill rest with super hot gas from separated canisters, they should be about 125C now.
|
|
Attach to transfer valve and open. BOOM.
|
|
|
|
*/
|
|
/atom
|
|
var/autoignition_temperature = 0 // In Kelvin. 0 = Not flammable
|
|
var/on_fire=0
|
|
var/fire_dmi = 'icons/effects/fire.dmi'
|
|
var/fire_sprite = "fire"
|
|
var/ashtype = /obj/effect/decal/cleanable/ash
|
|
var/fire_time_min = 5 // Seconds
|
|
var/fire_time_max = 10 // Seconds
|
|
|
|
/atom/proc/ignite(var/temperature)
|
|
on_fire=1
|
|
visible_message("\The [src] bursts into flame!")
|
|
overlays += image(fire_dmi,fire_sprite)
|
|
spawn(rand(fire_time_min,fire_time_max) SECONDS)
|
|
if(!on_fire)
|
|
return
|
|
new ashtype(src.loc)
|
|
qdel(src)
|
|
|
|
/atom/proc/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
|
if(autoignition_temperature && !on_fire && exposed_temperature > autoignition_temperature)
|
|
ignite(exposed_temperature)
|
|
|
|
turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
|
|
|
|
|
|
turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
|
|
if(fire_protection > world.time-300)
|
|
return 0
|
|
if(locate(/obj/fire) in src)
|
|
return 1
|
|
var/datum/gas_mixture/air_contents = return_air()
|
|
if(!air_contents || exposed_temperature < PLASMA_MINIMUM_BURN_TEMPERATURE)
|
|
return 0
|
|
|
|
var/igniting = 0
|
|
var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in src
|
|
|
|
if(air_contents.check_combustability(liquid))
|
|
igniting = 1
|
|
|
|
if(! (locate(/obj/fire) in src))
|
|
|
|
new /obj/fire(src,1000)
|
|
|
|
return igniting
|
|
|
|
/obj/fire
|
|
//Icon for fire on turfs.
|
|
|
|
anchored = 1
|
|
mouse_opacity = 0
|
|
|
|
//luminosity = 3
|
|
|
|
icon = 'icons/effects/fire.dmi'
|
|
icon_state = "1"
|
|
l_color = "#010000"
|
|
layer = TURF_LAYER
|
|
|
|
var/firelevel = 10000 //Calculated by gas_mixture.calculate_firelevel()
|
|
|
|
/obj/fire/proc/GenColor(var/datum/gas_mixture/ac)
|
|
var/temperature = ac.temperature
|
|
//All temperatures are in Kelvin for the color assignment
|
|
if(temperature > 9000)
|
|
//rainbow, wtf?
|
|
l_color = pick("#0092ED", "#EDEDED", "#ED9200", "#ED00ED", "#0000ED", "#010000", "#00EDED", "#EDED00", "#ED0000")
|
|
else if(temperature >= 7150)
|
|
//dark blue
|
|
l_color = "#0000ED"
|
|
else if(temperature >= 5300)
|
|
//blue
|
|
l_color = "#0092ED"
|
|
else if(temperature >= 1800)
|
|
//cyan
|
|
l_color = "#00EDED"
|
|
else if(temperature >= 1500)
|
|
//white
|
|
l_color = "#EDEDED"
|
|
else if(temperature >= 1300)
|
|
//yellow
|
|
l_color = "#EDED00"
|
|
else if(temperature >= 1100)
|
|
//orange
|
|
l_color = "#ED9200"
|
|
else if(temperature >= 75)
|
|
//red
|
|
l_color = "#ED0000"
|
|
else
|
|
//black fire, go atmos!
|
|
l_color = "#010000"
|
|
|
|
/obj/fire/process()
|
|
. = 1
|
|
|
|
//get location and check if it is in a proper ZAS zone
|
|
var/turf/simulated/S = loc
|
|
|
|
if(!istype(S))
|
|
del src
|
|
return
|
|
|
|
if(!S.zone)
|
|
del src
|
|
return
|
|
|
|
var/datum/gas_mixture/air_contents = S.return_air()
|
|
//get liquid fuels on the ground.
|
|
var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in S
|
|
//and the volatile stuff from the air
|
|
var/datum/gas/volatile_fuel/fuel = locate() in air_contents.trace_gases
|
|
|
|
//since the air is processed in fractions, we need to make sure not to have any minuscle residue or
|
|
//the amount of moles might get to low for some functions to catch them and thus result in wonky behaviour
|
|
if(air_contents.oxygen < 0.1)
|
|
air_contents.oxygen = 0
|
|
if(air_contents.toxins < 0.1)
|
|
air_contents.toxins = 0
|
|
if(fuel)
|
|
if(fuel.moles < 0.1)
|
|
air_contents.trace_gases.Remove(fuel)
|
|
|
|
//check if there is something to combust
|
|
if(!air_contents.check_combustability(liquid))
|
|
//del src
|
|
RemoveFire()
|
|
return
|
|
|
|
//get a firelevel and set the icon
|
|
firelevel = air_contents.calculate_firelevel(liquid)
|
|
|
|
if(firelevel > 6)
|
|
icon_state = "3"
|
|
SetLuminosity(7)
|
|
else if(firelevel > 2.5)
|
|
icon_state = "3"
|
|
SetLuminosity(5)
|
|
else
|
|
icon_state = "3"
|
|
SetLuminosity(3)
|
|
|
|
//im not sure how to implement a version that works for every creature so for now monkeys are firesafe
|
|
for(var/mob/living/carbon/human/M in loc)
|
|
M.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure() ) //Burn the humans!
|
|
|
|
loc.fire_act(air_contents, air_contents.temperature, air_contents.return_volume())
|
|
for(var/atom/A in loc)
|
|
A.fire_act(air_contents, air_contents.temperature, air_contents.return_volume())
|
|
// Burn the turf, too.
|
|
S.fire_act(air_contents, air_contents.temperature, air_contents.return_volume())
|
|
|
|
//Update color of the fire
|
|
src.GenColor(air_contents)
|
|
|
|
//spread
|
|
for(var/direction in cardinal)
|
|
var/turf/simulated/enemy_tile = get_step(S, direction)
|
|
|
|
if(istype(enemy_tile))
|
|
if(S.open_directions & direction) //Grab all valid bordering tiles
|
|
var/datum/gas_mixture/acs = enemy_tile.return_air()
|
|
var/obj/effect/decal/cleanable/liquid_fuel/liq = locate() in enemy_tile
|
|
if(!acs) continue
|
|
if(!acs.check_combustability(liq)) continue
|
|
//If extinguisher mist passed over the turf it's trying to spread to, don't spread and
|
|
//reduce firelevel.
|
|
if(enemy_tile.fire_protection > world.time-30)
|
|
firelevel -= 1.5
|
|
continue
|
|
|
|
//Spread the fire.
|
|
if(!(locate(/obj/fire) in enemy_tile))
|
|
if( prob( 50 + 50 * (firelevel/vsc.fire_firelevel_multiplier) ) && S.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, S, 0,0))
|
|
new/obj/fire(enemy_tile,firelevel)
|
|
|
|
else
|
|
enemy_tile.adjacent_fire_act(loc, air_contents, air_contents.temperature, air_contents.return_volume())
|
|
|
|
//seperate part of the present gas
|
|
//this is done to prevent the fire burning all gases in a single pass
|
|
var/datum/gas_mixture/flow = air_contents.remove_ratio(vsc.fire_consuption_rate)
|
|
///////////////////////////////// FLOW HAS BEEN CREATED /// DONT DELETE THE FIRE UNTIL IT IS MERGED BACK OR YOU WILL DELETE AIR ///////////////////////////////////////////////
|
|
|
|
if(flow)
|
|
//burn baby burn!
|
|
flow.zburn(liquid,1)
|
|
//merge the air back
|
|
S.assume_air(flow)
|
|
|
|
///////////////////////////////// FLOW HAS BEEN REMERGED /// feel free to delete the fire again from here on //////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/obj/fire/New(newLoc,fl)
|
|
..()
|
|
|
|
if(!istype(loc, /turf))
|
|
del src
|
|
|
|
dir = pick(cardinal)
|
|
SetLuminosity(3)
|
|
firelevel = fl
|
|
air_master.active_hotspots.Add(src)
|
|
|
|
|
|
/obj/fire/Del()
|
|
if (istype(loc, /turf/simulated))
|
|
SetLuminosity(0)
|
|
|
|
loc = null
|
|
air_master.active_hotspots.Remove(src)
|
|
|
|
..()
|
|
|
|
/obj/fire/proc/RemoveFire()
|
|
if (istype(loc, /turf/simulated))
|
|
SetLuminosity(0)
|
|
loc = null
|
|
air_master.active_hotspots.Remove(src)
|
|
|
|
|
|
|
|
turf/simulated/var/fire_protection = 0 //Protects newly extinguished tiles from being overrun again.
|
|
turf/proc/apply_fire_protection()
|
|
turf/simulated/apply_fire_protection()
|
|
fire_protection = world.time
|
|
|
|
|
|
datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, force_burn)
|
|
var/value = 0
|
|
|
|
if((temperature > PLASMA_MINIMUM_BURN_TEMPERATURE || force_burn) && check_recombustability(liquid))
|
|
var/total_fuel = 0
|
|
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
|
|
|
|
total_fuel += toxins
|
|
|
|
if(fuel)
|
|
//Volatile Fuel
|
|
total_fuel += fuel.moles
|
|
|
|
if(liquid)
|
|
//Liquid Fuel
|
|
if(liquid.amount <= 0.1)
|
|
del liquid
|
|
else
|
|
total_fuel += liquid.amount
|
|
|
|
if(total_fuel == 0)
|
|
return 0
|
|
|
|
//Calculate the firelevel.
|
|
var/firelevel = calculate_firelevel(liquid)
|
|
|
|
//get the current inner energy of the gas mix
|
|
//this must be taken here to prevent the addition or deletion of energy by a changing heat capacity
|
|
var/starting_energy = temperature * heat_capacity()
|
|
|
|
//determine the amount of oxygen used
|
|
var/total_oxygen = min(oxygen, 2 * total_fuel)
|
|
|
|
//determine the amount of fuel actually used
|
|
var/used_fuel_ratio = min(oxygen / 2 , total_fuel) / total_fuel
|
|
total_fuel = total_fuel * used_fuel_ratio
|
|
|
|
var/total_reactants = total_fuel + total_oxygen
|
|
|
|
//determine the amount of reactants actually reacting
|
|
var/used_reactants_ratio = min( max(total_reactants * firelevel / vsc.fire_firelevel_multiplier, 0.2), total_reactants) / total_reactants
|
|
|
|
//remove and add gasses as calculated
|
|
oxygen -= min(oxygen, total_oxygen * used_reactants_ratio )
|
|
|
|
toxins -= min(toxins, (toxins * used_fuel_ratio * used_reactants_ratio ) * 3)
|
|
if(toxins < 0)
|
|
toxins = 0
|
|
|
|
carbon_dioxide += max(2 * total_fuel, 0)
|
|
|
|
if(fuel)
|
|
fuel.moles -= (fuel.moles * used_fuel_ratio * used_reactants_ratio) * 5 //Fuel burns 5 times as quick
|
|
if(fuel.moles <= 0) del fuel
|
|
|
|
if(liquid)
|
|
liquid.amount -= (liquid.amount * used_fuel_ratio * used_reactants_ratio) * 5 // liquid fuel burns 5 times as quick
|
|
|
|
if(liquid.amount <= 0) del liquid
|
|
|
|
//calculate the energy produced by the reaction and then set the new temperature of the mix
|
|
temperature = (starting_energy + vsc.fire_fuel_energy_release * total_fuel) / heat_capacity()
|
|
|
|
update_values()
|
|
value = total_reactants * used_reactants_ratio
|
|
return value
|
|
|
|
datum/gas_mixture/proc/check_recombustability(obj/effect/decal/cleanable/liquid_fuel/liquid)
|
|
//this is a copy proc to continue a fire after its been started.
|
|
|
|
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
|
|
|
|
if(oxygen && (toxins || fuel || liquid))
|
|
if(liquid)
|
|
return 1
|
|
if(toxins >= 0.1)
|
|
return 1
|
|
if(fuel && fuel.moles >= 0.1)
|
|
return 1
|
|
|
|
return 0
|
|
|
|
datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fuel/liquid)
|
|
//this check comes up very often and is thus centralized here to ease adding stuff
|
|
|
|
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
|
|
|
|
if(oxygen && (toxins || fuel || liquid))
|
|
if(liquid)
|
|
return 1
|
|
if(QUANTIZE(toxins * vsc.fire_consuption_rate) >= 0.1)
|
|
return 1
|
|
if(fuel && QUANTIZE(fuel.moles * vsc.fire_consuption_rate) >= 0.1)
|
|
return 1
|
|
|
|
return 0
|
|
|
|
datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fuel/liquid)
|
|
//Calculates the firelevel based on one equation instead of having to do this multiple times in different areas.
|
|
|
|
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
|
|
var/total_fuel = 0
|
|
var/firelevel = 0
|
|
|
|
if(check_recombustability(liquid))
|
|
|
|
total_fuel += toxins
|
|
|
|
if(liquid)
|
|
total_fuel += liquid.amount
|
|
|
|
if(fuel)
|
|
total_fuel += fuel.moles
|
|
|
|
var/total_combustables = (total_fuel + oxygen)
|
|
|
|
if(total_fuel > 0 && oxygen > 0)
|
|
|
|
//slows down the burning when the concentration of the reactants is low
|
|
var/dampening_multiplier = total_combustables / (total_combustables + nitrogen + carbon_dioxide)
|
|
//calculates how close the mixture of the reactants is to the optimum
|
|
var/mix_multiplier = 1 / (1 + (5 * ((oxygen / total_combustables) ** 2)))
|
|
//toss everything together
|
|
firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * dampening_multiplier
|
|
|
|
return max( 0, firelevel)
|
|
|
|
|
|
/mob/living/proc/FireBurn(var/firelevel, var/last_temperature, var/pressure)
|
|
var/mx = 5 * firelevel/vsc.fire_firelevel_multiplier * min(pressure / ONE_ATMOSPHERE, 1)
|
|
apply_damage(2.5*mx, BURN)
|
|
|
|
|
|
/mob/living/carbon/human/FireBurn(var/firelevel, var/last_temperature, var/pressure)
|
|
//Burns mobs due to fire. Respects heat transfer coefficients on various body parts.
|
|
//Due to TG reworking how fireprotection works, this is kinda less meaningful.
|
|
|
|
var/head_exposure = 1
|
|
var/chest_exposure = 1
|
|
var/groin_exposure = 1
|
|
var/legs_exposure = 1
|
|
var/arms_exposure = 1
|
|
|
|
//Get heat transfer coefficients for clothing.
|
|
|
|
for(var/obj/item/clothing/C in src)
|
|
if(l_hand == C || r_hand == C)
|
|
continue
|
|
|
|
if( C.max_heat_protection_temperature >= last_temperature )
|
|
if(C.body_parts_covered & HEAD)
|
|
head_exposure = 0
|
|
if(C.body_parts_covered & UPPER_TORSO)
|
|
chest_exposure = 0
|
|
if(C.body_parts_covered & LOWER_TORSO)
|
|
groin_exposure = 0
|
|
if(C.body_parts_covered & LEGS)
|
|
legs_exposure = 0
|
|
if(C.body_parts_covered & ARMS)
|
|
arms_exposure = 0
|
|
//minimize this for low-pressure enviroments
|
|
var/mx = 5 * firelevel/vsc.fire_firelevel_multiplier * min(pressure / ONE_ATMOSPHERE, 1)
|
|
|
|
//Always check these damage procs first if fire damage isn't working. They're probably what's wrong.
|
|
|
|
apply_damage(2.5*mx*head_exposure, BURN, "head", 0, 0, "Fire")
|
|
apply_damage(2.5*mx*chest_exposure, BURN, "chest", 0, 0, "Fire")
|
|
apply_damage(2.0*mx*groin_exposure, BURN, "groin", 0, 0, "Fire")
|
|
apply_damage(0.6*mx*legs_exposure, BURN, "l_leg", 0, 0, "Fire")
|
|
apply_damage(0.6*mx*legs_exposure, BURN, "r_leg", 0, 0, "Fire")
|
|
apply_damage(0.4*mx*arms_exposure, BURN, "l_arm", 0, 0, "Fire")
|
|
apply_damage(0.4*mx*arms_exposure, BURN, "r_arm", 0, 0, "Fire")
|