Fixes Fuel Fires

Code update courtesy of @mwerezak from Baystation12.
This commit is contained in:
skull132
2015-12-22 12:44:50 +02:00
parent a3af352f79
commit 14b99501a1
6 changed files with 155 additions and 101 deletions
+102 -75
View File
@@ -35,37 +35,34 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
if(air_contents.check_combustability(liquid))
igniting = 1
create_fire(1000)
create_fire(vsc.fire_firelevel_multiplier)
return igniting
/zone/proc/process_fire()
if(!air.check_combustability())
var/datum/gas_mixture/burn_gas = air.remove_ratio(vsc.fire_consuption_rate, fire_tiles.len)
var/firelevel = burn_gas.zburn(src, fire_tiles, force_burn = 1, no_check = 1)
air.merge(burn_gas)
if (firelevel)
for (var/turf/T in fire_tiles)
if (T.fire)
T.fire.firelevel = firelevel
else
var/obj/effect/decal/cleanable/liquid_fuel/fuel = locate() in T
fire_tiles -= T
fuel_objs -= fuel
else
for(var/turf/simulated/T in fire_tiles)
if(istype(T.fire))
T.fire.RemoveFire()
T.fire = null
fire_tiles.Cut()
fuel_objs.Cut()
if(!fire_tiles.len)
air_master.active_fire_zones.Remove(src)
return
var/datum/gas_mixture/burn_gas = air.remove_ratio(vsc.fire_consuption_rate, fire_tiles.len)
var/gm = burn_gas.group_multiplier
burn_gas.group_multiplier = 1
burn_gas.zburn(force_burn = 1, no_check = 1)
burn_gas.group_multiplier = gm
air.merge(burn_gas)
var/firelevel = air.calculate_firelevel()
for(var/turf/T in fire_tiles)
if(T.fire)
T.fire.firelevel = firelevel
else
fire_tiles -= T
/turf/proc/create_fire(fl)
return 0
@@ -79,8 +76,13 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
return 1
fire = new(src, fl)
zone.fire_tiles |= src
air_master.active_fire_zones |= zone
var/obj/effect/decal/cleanable/liquid_fuel/fuel = locate() in src
zone.fire_tiles |= src
if (fuel)
zone.fuel_objs += fuel
return 0
/obj/fire
@@ -123,8 +125,8 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
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!
for(var/mob/living/L in loc)
L.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure()) //Burn the mobs!
loc.fire_act(air_contents, air_contents.temperature, air_contents.volume)
for(var/atom/A in loc)
@@ -146,10 +148,11 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
if(!enemy_tile.zone || enemy_tile.fire)
continue
if(!enemy_tile.zone.fire_tiles.len)
var/datum/gas_mixture/acs = enemy_tile.return_air()
if(!acs || !acs.check_combustability())
continue
//if(!enemy_tile.zone.fire_tiles.len)
var/datum/gas_mixture/acs = enemy_tile.return_air()
var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in enemy_tile
if(!acs || !acs.check_combustability(liquid))
continue
//If extinguisher mist passed over the turf it's trying to spread to, don't spread and
//reduce firelevel.
@@ -178,10 +181,7 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
/obj/fire/Del()
if (istype(loc, /turf/simulated))
SetLuminosity(0)
loc = null
air_master.active_hotspots.Remove(src)
RemoveFire()
..()
@@ -198,65 +198,101 @@ turf/simulated/apply_fire_protection()
fire_protection = world.time
datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, force_burn, no_check = 0)
datum/gas_mixture/proc/zburn(zone/zone, force_burn, no_check = 0)
. = 0
if((temperature > PLASMA_MINIMUM_BURN_TEMPERATURE || force_burn) && (no_check ||check_recombustability(liquid)))
if ((temperature > PLASMA_MINIMUM_BURN_TEMPERATURE || force_burn) && (no_check ||check_recombustability(zone? zone.fuel_objs : null)))
var/gas_fuel = 0
var/liquid_fuel = 0
var/total_fuel = 0
var/total_oxidizers = 0
for(var/g in gas)
for (var/g in gas)
if(gas_data.flags[g] & XGM_GAS_FUEL)
total_fuel += gas[g]
gas_fuel += gas[g]
if(gas_data.flags[g] & XGM_GAS_OXIDIZER)
total_oxidizers += gas[g]
gas_fuel *= group_multiplier
total_oxidizers *= group_multiplier
if(liquid)
//Liquid Fuel
if(liquid.amount <= 0.1)
del liquid
else
total_fuel += liquid.amount
if (zone)
for (var/obj/effect/decal/cleanable/liquid_fuel/fuel in zone.fuel_objs)
liquid_fuel += fuel.amount*LIQUIDFUEL_AMOUNT_TO_MOL
if(total_fuel == 0)
total_fuel = gas_fuel + liquid_fuel
if (total_fuel <= 0.005)
return 0
//Calculate the firelevel.
var/firelevel = calculate_firelevel(liquid, total_fuel, total_oxidizers, force = 1)
//*** Determine how fast the fire burns
//get the current inner energy of the gas mix
//calculate the firelevel.
var/firelevel = calculate_firelevel(zone? zone.fuel_objs : null, total_fuel, total_oxidizers, force = 1)
//get the current thermal 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/used_oxidizers = min(total_oxidizers, total_fuel / 2)
//determine how far the reaction can progress
var/reaction_limit = min(total_oxidizers*(FIRE_REACTION_FUEL_AMOUNT/FIRE_REACTION_OXIDIZER_AMOUNT), total_fuel) //stoichiometric limit
//determine the amount of fuel actually used
var/used_fuel_ratio = min(2 * total_oxidizers , total_fuel) / total_fuel
total_fuel = total_fuel * used_fuel_ratio
//determine the actual rate of reaction, as measured by the amount of fuel reacting
var/total_reactants = total_fuel + used_oxidizers
//vapour fuels are extremely volatile! The reaction progress is a percentage of the total fuel (similar to old zburn).
var/gas_reaction_progress = max(0.2*group_multiplier, (firelevel/vsc.fire_firelevel_multiplier)*gas_fuel)*FIRE_GAS_BURNRATE_MULT
//liquid fuels are not as volatile, and the reaction progress depends on the size of the area that is burning (which is sort of accounted for by firelevel). Having more fuel means a longer burn.
var/liquid_reaction_progress = (firelevel/vsc.fire_firelevel_multiplier)*FIRE_LIQUID_BURNRATE_MULT
//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
//world << "liquid_reaction_progress = [liquid_reaction_progress]"
//world << "gas_reaction_progress = [gas_reaction_progress]"
var/total_reaction_progress = gas_reaction_progress + liquid_reaction_progress
var/used_fuel = min(total_reaction_progress, reaction_limit)
var/used_oxidizers = used_fuel*(FIRE_REACTION_OXIDIZER_AMOUNT/FIRE_REACTION_FUEL_AMOUNT)
//world << "used_fuel = [used_fuel]; used_oxidizers = [used_oxidizers]; reaction_limit=[reaction_limit]"
if (zone && zone.fuel_objs.len)
if (used_fuel <= FIRE_LIQUD_MIN_BURNRATE)
return 0
else if (used_fuel <= FIRE_GAS_MIN_BURNRATE * group_multiplier)
return 0
//*** Remove fuel and oxidizer, add carbon dioxide and heat
//remove and add gasses as calculated
remove_by_flag(XGM_GAS_OXIDIZER, used_oxidizers * used_reactants_ratio)
remove_by_flag(XGM_GAS_FUEL, total_fuel * used_reactants_ratio)
var/used_gas_fuel = min(used_fuel*(gas_reaction_progress/total_reaction_progress), gas_fuel) //remove in proportion to the relative reaction progress
var/used_liquid_fuel = between(0, used_fuel-used_gas_fuel, liquid_fuel)
adjust_gas("carbon_dioxide", max(total_fuel*used_reactants_ratio, 0))
//remove_by_flag() and adjust_gas() handle the group_multiplier for us.
remove_by_flag(XGM_GAS_OXIDIZER, used_oxidizers)
remove_by_flag(XGM_GAS_FUEL, used_gas_fuel)
adjust_gas("carbon_dioxide", used_oxidizers)
if(liquid)
liquid.amount -= (liquid.amount * used_fuel_ratio * used_reactants_ratio) * 5 // liquid fuel burns 5 times as quick
//As a simplification, we remove fuel equally from all fuel sources. It might be that some fuel sources have more fuel, some have less, but whatever.
if(zone && zone.fuel_objs.len)
var/fuel_to_remove = used_liquid_fuel/(zone.fuel_objs.len*LIQUIDFUEL_AMOUNT_TO_MOL) //convert back to liquid volume units
//world << "used gas fuel = [used_gas_fuel]; used other fuel = [used_fuel-used_gas_fuel]; fuel_to_remove = [fuel_to_remove]"
var/liquidonly = !check_combustability()
for(var/O in zone.fuel_objs)
var/obj/effect/decal/cleanable/liquid_fuel/fuel = O
if(!istype(fuel))
zone.fuel_objs -= fuel
continue
if(liquid.amount <= 0) del liquid
fuel.amount -= fuel_to_remove
if(fuel.amount <= 0)
zone.fuel_objs -= fuel
if(liquidonly)
var/turf/T = fuel.loc
if(istype(T) && T.fire) del(T.fire)
del(fuel)
//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()
temperature = (starting_energy + vsc.fire_fuel_energy_release * used_fuel) / heat_capacity()
update_values()
. = total_reactants * used_reactants_ratio
return firelevel
datum/gas_mixture/proc/check_recombustability(obj/effect/decal/cleanable/liquid_fuel/liquid)
datum/gas_mixture/proc/check_recombustability(list/fuel_objs)
. = 0
for(var/g in gas)
if(gas_data.flags[g] & XGM_GAS_OXIDIZER && gas[g] >= 0.1)
@@ -266,7 +302,7 @@ datum/gas_mixture/proc/check_recombustability(obj/effect/decal/cleanable/liquid_
if(!.)
return 0
if(liquid)
if(fuel_objs && fuel_objs.len)
return 1
. = 0
@@ -275,7 +311,7 @@ datum/gas_mixture/proc/check_recombustability(obj/effect/decal/cleanable/liquid_
. = 1
break
datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fuel/liquid)
datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fuel/liquid = null)
. = 0
for(var/g in gas)
if(gas_data.flags[g] & XGM_GAS_OXIDIZER && QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1)
@@ -294,20 +330,11 @@ datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fu
. = 1
break
datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fuel/liquid, total_fuel = null, total_oxidizers = null, force = 0)
/datum/gas_mixture/proc/calculate_firelevel(list/fuel_objs, total_fuel, total_oxidizers, force = 0)
//Calculates the firelevel based on one equation instead of having to do this multiple times in different areas.
var/firelevel = 0
if(force || check_recombustability(liquid))
if(isnull(total_fuel))
for(var/g in gas)
if(gas_data.flags[g] & XGM_GAS_FUEL)
total_fuel += gas[g]
if(gas_data.flags[g] & XGM_GAS_OXIDIZER)
total_oxidizers += gas[g]
if(liquid)
total_fuel += liquid.amount
if(force || check_recombustability(fuel_objs))
var/total_combustables = (total_fuel + total_oxidizers)
if(total_combustables > 0)
+10 -3
View File
@@ -44,6 +44,7 @@ Class Procs:
/zone/var/invalid = 0
/zone/var/list/contents = list()
/zone/var/list/fire_tiles = list()
/zone/var/list/fuel_objs = list()
/zone/var/needs_update = 0
@@ -72,8 +73,11 @@ Class Procs:
T.zone = src
contents.Add(T)
if(T.fire)
var/obj/effect/decal/cleanable/liquid_fuel/fuel = locate() in T
fire_tiles.Add(T)
air_master.active_fire_zones.Add(src)
air_master.active_fire_zones |= src
if (fuel)
fuel_objs += fuel
T.update_graphic(air.graphic)
/zone/proc/remove(turf/simulated/T)
@@ -85,6 +89,9 @@ Class Procs:
#endif
contents.Remove(T)
fire_tiles.Remove(T)
if (T.fire)
var/obj/effect/decal/cleanable/liquid_fuel/fuel = locate() in T
fuel_objs -= fuel
T.zone = null
T.update_graphic(graphic_remove = air.graphic)
if(contents.len)
@@ -142,7 +149,7 @@ Class Procs:
M << name
for(var/g in air.gas)
M << "[gas_data.name[g]]: [air.gas[g]]"
M << "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]°K ([air.temperature - T0C]°C)"
M << "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]K ([air.temperature - T0C]C)"
M << "O2 per N2: [(air.gas["nitrogen"] ? air.gas["oxygen"]/air.gas["nitrogen"] : "N/A")] Moles: [air.total_moles]"
M << "Simulated: [contents.len] ([air.group_multiplier])"
//M << "Unsimulated: [unsimulated_contents.len]"
@@ -162,4 +169,4 @@ Class Procs:
M << "Space Edges: [space_edges] ([space_coefficient] connections)"
//for(var/turf/T in unsimulated_contents)
// M << "[T] at ([T.x],[T.y])"
// M << "[T] at ([T.x],[T.y])"
+8 -8
View File
@@ -100,7 +100,7 @@
/datum/gas_mixture/proc/add_thermal_energy(var/thermal_energy)
if (total_moles == 0)
return 0
var/heat_capacity = heat_capacity()
if (thermal_energy < 0)
if (temperature < TCMB)
@@ -121,7 +121,7 @@
/datum/gas_mixture/proc/specific_entropy()
if (!gas.len || total_moles == 0)
return SPECIFIC_ENTROPY_VACUUM
. = 0
for(var/g in gas)
. += gas[g] * specific_entropy_gas(g)
@@ -129,24 +129,24 @@
/*
It's arguable whether this should even be called entropy anymore. It's more "based on" entropy than actually entropy now.
Returns the ideal gas specific entropy of a specific gas in the mix. This is the entropy due to that gas per mole of /that/ gas in the mixture, not the entropy due to that gas per mole of gas mixture.
For the purposes of SS13, the specific entropy is just a number that tells you how hard it is to move gas. You can replace this with whatever you want.
Just remember that returning a SMALL number == adding gas to this gas mix is HARD, taking gas away is EASY, and that returning a LARGE number means the opposite (so a vacuum should approach infinity).
So returning a constant/(partial pressure) would probably do what most players expect. Although the version I have implemented below is a bit more nuanced than simply 1/P in that it scales in a way
So returning a constant/(partial pressure) would probably do what most players expect. Although the version I have implemented below is a bit more nuanced than simply 1/P in that it scales in a way
which is bit more realistic (natural log), and returns a fairly accurate entropy around room temperatures and pressures.
*/
/datum/gas_mixture/proc/specific_entropy_gas(var/gasid)
if (!(gasid in gas) || gas[gasid] == 0)
return SPECIFIC_ENTROPY_VACUUM //that gas isn't here
//group_multiplier gets divided out in volume/gas[gasid] - also, V/(m*T) = R/(partial pressure)
var/molar_mass = gas_data.molar_mass[gasid]
var/specific_heat = gas_data.specific_heat[gasid]
return R_IDEAL_GAS_EQUATION * ( log( (IDEAL_GAS_ENTROPY_CONSTANT*volume/(gas[gasid] * temperature)) * (molar_mass*specific_heat*temperature)**(2/3) + 1 ) + 15 )
//alternative, simpler equation
//var/partial_pressure = gas[gasid] * R_IDEAL_GAS_EQUATION * temperature / volume
//return R_IDEAL_GAS_EQUATION * ( log (1 + IDEAL_GAS_ENTROPY_CONSTANT/partial_pressure) + 20 )
@@ -265,7 +265,7 @@
return 1
/datum/gas_mixture/proc/react(atom/dump_location)
zburn(null)
zburn(null, force_burn = 0, no_check = 0)
//Rechecks the gas_mixture and adjusts the graphic list if needed.
//Two lists can be passed by reference if you need know specifically which graphics were added and removed.
+1 -3
View File
@@ -193,9 +193,7 @@ update_flag
else
can_label = 0
if(air_contents.temperature > PLASMA_FLASHPOINT)
air_contents.zburn()
return
air_contents.react()
/obj/machinery/portable_atmospherics/canister/return_air()
return air_contents
@@ -9,29 +9,39 @@ obj/effect/decal/cleanable/liquid_fuel
New(newLoc,amt=1)
src.amount = amt
var/has_spread = 0
//Be absorbed by any other liquid fuel in the tile.
for(var/obj/effect/decal/cleanable/liquid_fuel/other in newLoc)
if(other != src)
other.amount += src.amount
spawn other.Spread()
del src
other.Spread()
has_spread = 1
break
Spread()
. = ..()
if (!has_spread)
Spread()
else
del(src)
proc/Spread()
proc/Spread(exclude = list())
//Allows liquid fuels to sometimes flow into other tiles.
if(amount < 5.0) return
if(amount < 15) return
var/turf/simulated/S = loc
if(!istype(S)) return
for(var/d in cardinal)
if(rand(25))
var/turf/simulated/target = get_step(src,d)
var/turf/simulated/origin = get_turf(src)
if(origin.CanPass(null, target, 0, 0) && target.CanPass(null, origin, 0, 0))
if(!locate(/obj/effect/decal/cleanable/liquid_fuel) in target)
new/obj/effect/decal/cleanable/liquid_fuel(target, amount*0.25)
amount *= 0.75
var/turf/simulated/target = get_step(src, d)
var/turf/simulated/origin = get_turf(src)
if (origin.CanPass(null, target, 0, 0) && target.CanPass(null, origin, 0, 0))
var/obj/effect/decal/cleanable/liquid_fuel/other_fuel = locate() in target
if (other_fuel)
other_fuel.amount += amount * 0.25
if (!(other_fuel in exclude))
exclude += src
other_fuel.Spread(exclude)
else
new/obj/effect/decal/cleanable/liquid_fuel(target, amount * 0.25, 1)
amount *= 0.75
flamethrower_fuel
icon_state = "mustard"
+12
View File
@@ -135,6 +135,18 @@
#define PLASMA_MINIMUM_OXYGEN_PLASMA_RATIO 20
#define PLASMA_OXYGEN_FULLBURN 10
//For other fires
#define FIRE_REACTION_OXIDIZER_AMOUNT 3
#define FIRE_REACTION_FUEL_AMOUNT 2
#define FIRE_GAS_BURNRATE_MULT 1
#define FIRE_LIQUID_BURNRATE_MULT 0.5
#define LIQUIDFUEL_AMOUNT_TO_MOL 1
#define FIRE_GAS_MIN_BURNRATE 0.1
#define FIRE_LIQUD_MIN_BURNRATE 0.05
#define T0C 273.15 // 0degC
#define T20C 293.15 // 20degC
#define TCMB 2.7 // -270.3degC