Skip to content

Commit

Permalink
fix(ZAS): liquid fires should now work
Browse files Browse the repository at this point in the history
  • Loading branch information
Filatelele authored Aug 9, 2024
1 parent 215adb9 commit df7ce97
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 41 deletions.
162 changes: 123 additions & 39 deletions code/modules/ZAS/Fire.dm
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,20 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
return simulated

/turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
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 < FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE)
return 0

//vaporize_fuel(air_contents)

var/igniting = 0
if(air_contents.check_combustibility())
var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in src
if(air_contents.check_combustibility(liquid))
igniting = 1

create_fire(exposed_temperature)
return igniting

Expand All @@ -44,17 +46,47 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
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/T in fire_tiles)
for(var/turf/simulated/T in fire_tiles)
if(istype(T.fire))
qdel(T.fire)
T.fire.RemoveFire()
T.fire = null
fire_tiles.Cut()
fuel_objs.Cut()

if(!fire_tiles.len)
SSair.active_fire_zones.Remove(src)

/zone/proc/remove_liquidfuel(used_liquid_fuel, remove_fire=0)
if(!fuel_objs.len)
return

//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. It will mean that sometimes we will remove a tiny bit less fuel then we intended to.

var/fuel_to_remove = used_liquid_fuel/(fuel_objs.len*LIQUIDFUEL_AMOUNT_TO_MOL) //convert back to liquid volume units

for(var/O in fuel_objs)
var/obj/effect/decal/cleanable/liquid_fuel/fuel = O
if(!istype(fuel))
fuel_objs -= fuel
continue

fuel.amount -= fuel_to_remove
if(fuel.amount <= 0)
fuel_objs -= fuel
if(remove_fire)
var/turf/T = fuel.loc
if(istype(T) && T.fire) qdel(T.fire)
qdel(fuel)

/turf/proc/create_fire(fl)
return 0

/turf/simulated/create_fire(fl)
if(fire)
fire.firelevel = max(fl, fire.firelevel)
return 1
Expand All @@ -65,14 +97,17 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
fire = new(src, fl)
SSair.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
//Icon for fire on turfs.

anchored = TRUE
mouse_opacity = MOUSE_OPACITY_UNCLICKABLE
anchored = 1
mouse_opacity = 0

blend_mode = BLEND_ADD

Expand All @@ -86,12 +121,12 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
/obj/fire/Process()
. = 1

var/turf/my_tile = loc
var/turf/simulated/my_tile = loc
if(!istype(my_tile) || !my_tile.zone)
if(my_tile && my_tile.fire == src)
my_tile.fire = null
qdel(src)
return PROCESS_KILL
RemoveFire()
return 1

var/datum/gas_mixture/air_contents = my_tile.return_air()

Expand All @@ -112,15 +147,9 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
for(var/atom/A in loc)
A.fire_act(air_contents, air_contents.temperature, air_contents.volume)

// prioritize nearby fuel overlays first
for(var/direction in GLOB.cardinal)
var/turf/enemy_tile = get_step(my_tile, direction)
if(istype(enemy_tile) && enemy_tile.reagents)
enemy_tile.hotspot_expose(air_contents.temperature, air_contents.volume)

//spread
for(var/direction in GLOB.cardinal)
var/turf/enemy_tile = get_step(my_tile, direction)
var/turf/simulated/enemy_tile = get_step(my_tile, direction)

if(istype(enemy_tile))
if(my_tile.open_directions & direction) //Grab all valid bordering tiles
Expand All @@ -129,11 +158,18 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin

//if(!enemy_tile.zone.fire_tiles.len) TODO - optimize
var/datum/gas_mixture/acs = enemy_tile.return_air()
if(!acs || !acs.check_combustibility())
var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in enemy_tile
if(!acs || !acs.check_combustibility(liquid))
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(prob( 50 + 50 * (firelevel/vsc.fire_firelevel_multiplier) ) && my_tile.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, my_tile, 0,0))
if(prob(50 + 50 * (firelevel / vsc.fire_firelevel_multiplier)) && my_tile.CanPass(src, enemy_tile) && enemy_tile.CanPass(src, my_tile))
enemy_tile.create_fire(firelevel)

else
Expand All @@ -142,11 +178,12 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
animate(src, color = fire_color(air_contents.temperature), 5)
set_light(l_color = color)

/obj/fire/Initialize(mapload, fl)
. = ..()
/obj/fire/New(newLoc,fl)
..()

if(!isturf(loc))
return INITIALIZE_HINT_QDEL
if(!istype(loc, /turf))
qdel(src)
return

set_dir(pick(GLOB.cardinal))

Expand All @@ -157,40 +194,63 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
firelevel = fl
SSair.active_hotspots.Add(src)

if (fl >= 2)
playsound(src.loc, SFX_EXPLOSION_FUEL, 50, FALSE, 15)

/obj/fire/proc/fire_color(env_temperature)
var/temperature = max(4000*sqrt(firelevel/vsc.fire_firelevel_multiplier), env_temperature)
return heat2color(temperature)

/obj/fire/Destroy()
RemoveFire()
return ..()

/obj/fire/proc/RemoveFire()
var/turf/T = loc
if (istype(T))
set_light(0)

T.fire = null
forceMove(null)
SSair.active_hotspots.Remove(src)
. = ..()

/// Protects newly extinguished tiles from being overrun again.
/turf/var/fire_protection = 0
/turf/proc/apply_fire_protection()
fire_protection = world.time

//Returns the firelevel
/datum/gas_mixture/proc/react(zone/zone, force_burn, no_check = 0)
. = 0
if((temperature > FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE || force_burn) && (no_check ||check_recombustibility()))
if((temperature > FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE || force_burn) && (no_check ||check_recombustability(zone? zone.fuel_objs : null)))

#ifdef FIREDBG
log_debug("***************** FIREDBG *****************")
log_debug("Burning [zone? zone.name : "zoneless gas_mixture"]!")
#endif

var/gas_fuel = 0
var/liquid_fuel = 0
var/total_fuel = 0
var/total_oxidizers = 0

//*** Get the fuel and oxidizer amounts
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]
total_fuel *= group_multiplier
gas_fuel *= group_multiplier
total_oxidizers *= group_multiplier

//Liquid Fuel
var/fuel_area = 0
if(zone)
for(var/obj/effect/decal/cleanable/liquid_fuel/fuel in zone.fuel_objs)
liquid_fuel += fuel.amount*LIQUIDFUEL_AMOUNT_TO_MOL
fuel_area++

total_fuel = gas_fuel + liquid_fuel
if(total_fuel <= 0.005)
return 0

Expand All @@ -203,36 +263,54 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
//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

//vapour fuels are extremely volatile! The reaction progress is a percentage of the total fuel (similar to old zburn).)
var/firelevel = calculate_firelevel(total_fuel, total_oxidizers, reaction_limit, volume*group_multiplier) / vsc.fire_firelevel_multiplier
//vapour fuels are extremely volatile! The reaction progress is a percentage of the total fuel (similar to old react).)
var/gas_firelevel = calculate_firelevel(gas_fuel, total_oxidizers, reaction_limit, volume*group_multiplier) / vsc.fire_firelevel_multiplier
var/min_burn = 0.30*volume*group_multiplier/CELL_VOLUME //in moles - so that fires with very small gas concentrations burn out fast
var/total_reaction_progress = min(max(min_burn, firelevel*total_fuel)*FIRE_GAS_BURNRATE_MULT, total_fuel)
var/gas_reaction_progress = min(max(min_burn, gas_firelevel*gas_fuel)*FIRE_GAS_BURNRATE_MULT, gas_fuel)

//liquid fuels are not as volatile, and the reaction progress depends on the size of the area that is burning. Limit the burn rate to a certain amount per area.
var/liquid_firelevel = calculate_firelevel(liquid_fuel, total_oxidizers, reaction_limit, 0) / vsc.fire_firelevel_multiplier
var/liquid_reaction_progress = min((liquid_firelevel*0.2 + 0.05)*fuel_area*FIRE_LIQUID_BURNRATE_MULT, liquid_fuel)

var/firelevel = (gas_fuel*gas_firelevel + liquid_fuel*liquid_firelevel)/total_fuel

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)

#ifdef FIREDBG
log_debug("total_fuel = [total_fuel], total_oxidizers = [total_oxidizers]")
log_debug("gas_fuel = [gas_fuel], liquid_fuel = [liquid_fuel], total_oxidizers = [total_oxidizers]")
log_debug("fuel_area = [fuel_area], total_fuel = [total_fuel], reaction_limit = [reaction_limit]")
log_debug("firelevel -> [firelevel]")
log_debug("firelevel -> [firelevel] (gas: [gas_firelevel], liquid: [liquid_firelevel])")
log_debug("liquid_reaction_progress = [liquid_reaction_progress]")
log_debug("gas_reaction_progress = [gas_reaction_progress]")
log_debug("total_reaction_progress = [total_reaction_progress]")
log_debug("used_fuel = [used_fuel], used_oxidizers = [used_oxidizers]; ")
#endif

//if the reaction is progressing too slow then it isn't self-sustaining anymore and burns out
if(zone && (!total_fuel || used_fuel <= FIRE_GAS_MIN_BURNRATE*zone.contents.len))
return 0
if(zone) //be less restrictive with canister and tank reactions
if((!liquid_fuel || used_fuel <= FIRE_LIQUD_MIN_BURNRATE) && (!gas_fuel || used_fuel <= FIRE_GAS_MIN_BURNRATE*zone.contents.len))
return 0


//*** Remove fuel and oxidizer, add carbon dioxide and heat

//remove and add gasses as calculated
used_fuel = min(used_fuel, total_fuel)
var/used_gas_fuel = min(max(0.25, used_fuel*(gas_reaction_progress/total_reaction_progress)), gas_fuel) //remove in proportion to the relative reaction progress
var/used_liquid_fuel = min(max(0.25, used_fuel-used_gas_fuel), liquid_fuel)

//remove_by_flag() and adjust_gas() handle the group_multiplier for us.
remove_by_flag(XGM_GAS_OXIDIZER, used_oxidizers)
var/datum/gas_mixture/burned_fuel = remove_by_flag(XGM_GAS_FUEL, used_fuel)
var/datum/gas_mixture/burned_fuel = remove_by_flag(XGM_GAS_FUEL, used_gas_fuel)
for(var/g in burned_fuel.gas)
adjust_gas(gas_data.burn_product[g], burned_fuel.gas[g])

if(zone)
zone.remove_liquidfuel(used_liquid_fuel, !check_combustibility())

//calculate the energy produced by the reaction and then set the new temperature of the mix
temperature = (starting_energy + vsc.fire_fuel_energy_release * used_fuel) / heat_capacity()
temperature = (starting_energy + vsc.fire_fuel_energy_release * (used_gas_fuel + used_liquid_fuel)) / heat_capacity()
update_values()

#ifdef FIREDBG
Expand All @@ -242,7 +320,7 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin

return firelevel

/datum/gas_mixture/proc/check_recombustibility()
/datum/gas_mixture/proc/check_recombustability(list/fuel_objs)
. = 0
for(var/g in gas)
if(gas[g] >= 0.1)
Expand All @@ -253,14 +331,17 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
if(!.)
return 0

if(fuel_objs && fuel_objs.len)
return 1

. = 0
for(var/g in gas)
if(gas[g] >= 0.1)
if(gas_data.flags[g] & XGM_GAS_OXIDIZER)
. = 1
break

/datum/gas_mixture/proc/check_combustibility()
/datum/gas_mixture/proc/check_combustibility(obj/effect/decal/cleanable/liquid_fuel/liquid = null)
. = 0
for(var/g in gas)
if(QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1)
Expand All @@ -271,6 +352,9 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
if(!.)
return 0

if(liquid)
return 1

. = 0
for(var/g in gas)
if(QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1)
Expand Down
7 changes: 7 additions & 0 deletions code/modules/ZAS/Zone.dm
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Class Procs:
var/list/graphic_remove = list()
var/last_air_temperature = TCMB
var/condensing = FALSE
var/list/fuel_objs = list()

/zone/New()
SSair.add_zone(src)
Expand All @@ -72,6 +73,9 @@ Class Procs:
T.zone = src
contents.Add(T)
if(T.fire)
var/obj/effect/decal/cleanable/liquid_fuel/fuel = locate() in T
if(fuel)
fuel_objs += fuel
fire_tiles.Add(T)
SSair.active_fire_zones |= src
T.update_graphic(air.graphic)
Expand All @@ -87,6 +91,9 @@ Class Procs:
T.c_copy_air() // to avoid losing contents
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(air.graphic)
if(contents.len)
Expand Down
4 changes: 2 additions & 2 deletions code/modules/atmospherics/datum_pipeline.dm
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
possible_expansions += item
item.getting_pipelined = TRUE
members += item
register_signal(item, SIGNAL_QDELETING, nameof(.proc/on_member_qdel))
register_signal(item, SIGNAL_QDELETING, nameof(.proc/on_member_qdel), TRUE)

volume += item.volume

Expand All @@ -122,7 +122,7 @@

if(edge_check > 0)
edges += borderline
register_signal(borderline, SIGNAL_QDELETING, nameof(.proc/on_borderline_qdel))
register_signal(borderline, SIGNAL_QDELETING, nameof(.proc/on_borderline_qdel), TRUE)

possible_expansions -= borderline

Expand Down

0 comments on commit df7ce97

Please sign in to comment.