Files
Aurora.3/code/game/objects/effects/fire/fire.dm
T
Batrachophreno 58b01cf856 Various fire bugfixes (#22431)
Fixes https://github.com/Aurorastation/Aurora.3/issues/22384.
Fixes https://github.com/Aurorastation/Aurora.3/issues/22389.
changes:
  - bugfix: "Fixes turf fires not spreading."
  - bugfix: "Fixes atmos fires not consistently igniting."
  - bugfix: "Fixes dead mobs burning forever."
  - bugfix: "Fixes fire_act() runtimes for multiple objects."
2026-05-11 18:12:58 +00:00

237 lines
7.1 KiB
Plaintext

#define TURF_FIRE_REQUIRED_TEMP (T0C+10)
#define TURF_FIRE_TEMP_BASE (T0C+100)
#define TURF_FIRE_POWER_LOSS_ON_LOW_TEMP 3.5
#define TURF_FIRE_TEMP_INCREMENT_PER_POWER 3
#define TURF_FIRE_POWER_LOSS_BASE 0.5
#define TURF_FIRE_VOLUME 150
#define TURF_FIRE_MAX_POWER 50
#define TURF_FIRE_ENERGY_PER_BURNED_OXY_MOL 12000
#define TURF_FIRE_BURN_RATE_BASE 0.06
#define TURF_FIRE_BURN_RATE_PER_POWER 0.02
#define TURF_FIRE_BURN_MINIMUM_OXYGEN_REQUIRED 0.5
#define TURF_FIRE_BURN_PLAY_SOUND_EFFECT_CHANCE 6
#define TURF_FIRE_STATE_SMALL 1
#define TURF_FIRE_STATE_MEDIUM 2
#define TURF_FIRE_STATE_LARGE 3
#define TURF_FIRE_STATE_MAX 4
/obj/turf_fire
icon = 'icons/effects/turf_fire.dmi'
layer = BELOW_DOOR_LAYER
anchored = TRUE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/// How much power have we got. This is treated like fuel, be it flamethrower liquid or any random thing you could come up with
var/fire_power = 20
/// If false, it does not interact with atmos.
var/interact_with_atmos = TRUE
/// If false, it will not lose power by itself. Mainly for adminbus events or mapping.
var/passive_loss = TRUE
/// Visual state of the fire. Kept track to not do too many updates.
var/current_fire_state
light_color = COLOR_ORANGE
///All the subtypes are for adminbussery and or mapping
/obj/turf_fire/magical
interact_with_atmos = FALSE
passive_loss = FALSE
color = COLOR_LIGHT_CYAN
/obj/turf_fire/small
fire_power = 10
/obj/turf_fire/small/magical
interact_with_atmos = FALSE
passive_loss = FALSE
color = COLOR_SPRING_GREEN
/obj/turf_fire/inferno
fire_power = 30
/obj/turf_fire/inferno/magical
interact_with_atmos = FALSE
passive_loss = FALSE
color = COLOR_VIOLET
/obj/turf_fire/Initialize(mapload, power, fire_color)
. = ..()
var/turf/open_turf = loc
if(open_turf.turf_fire)
return INITIALIZE_HINT_QDEL
if(fire_color && ((color != fire_color) && isnull(color))) //Take colour from proc unless base colour was already custom
color = fire_color
if(color != null)
set_color(color)
particles = new /particles/smoke/turf_fire
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
)
AddElement(/datum/element/connect_loc, loc_connections)
open_turf.turf_fire = src
SSturf_fire.fires += src
if(power)
fire_power = min(TURF_FIRE_MAX_POWER, power)
UpdateFireState()
/obj/turf_fire/Destroy()
var/turf/T = loc
T.turf_fire = null
SSturf_fire.fires -= src
return ..()
//Approximates colour. It will not change value or saturation, just hue.
/obj/turf_fire/proc/set_color(_color)
light_color = _color
var/base = rgb2num(COLOR_ORANGE, COLORSPACE_HSV) //Base sprite is red fire, but maybe other fires want to be different
var/target = rgb2num(_color, COLORSPACE_HSV)
var/baseAngle = base[1]
var/targetAngle= target[1]
var/angle = (targetAngle - baseAngle)
filters = filter(type = "color", color = list(1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1,
angle/360,0,0,0), space = FILTER_COLOR_HSV)
color = null //The actual colour should remain white so transform makes sense
/obj/turf_fire/proc/process_waste(seconds_per_tick)
var/total_oxidizer = 0
var/turf/T = loc
var/datum/gas_mixture/env = T.return_air()
for (var/g in env.gas)
if(gas_data.flags[g] & XGM_GAS_OXIDIZER)
total_oxidizer += env.gas[g]
if (total_oxidizer < TURF_FIRE_BURN_MINIMUM_OXYGEN_REQUIRED)
return FALSE
var/burn_rate = (TURF_FIRE_BURN_RATE_BASE * seconds_per_tick) + fire_power * TURF_FIRE_BURN_RATE_PER_POWER
if(burn_rate > total_oxidizer)
burn_rate = total_oxidizer
env.remove_by_flag(XGM_GAS_OXIDIZER, burn_rate)
env.adjust_gas(GAS_CO2, burn_rate)
var/energy_released = burn_rate * TURF_FIRE_ENERGY_PER_BURNED_OXY_MOL
env.add_thermal_energy(energy_released)
SSair.mark_for_update(T)
return TRUE
/obj/turf_fire/process(seconds_per_tick)
var/turf/simulated/T = get_turf(src)
if(!T || T.density)
qdel(src)
return
if(prob(TURF_FIRE_BURN_PLAY_SOUND_EFFECT_CHANCE))
playsound(T, SFX_FIRE, 40, TRUE)
if(T.hotspot) //If we have an active hotspot, let it do the damage instead and lets not loose power
return
if(interact_with_atmos && !process_waste(seconds_per_tick))
qdel(src)
return
if(passive_loss)
if(T.air?.temperature < TURF_FIRE_REQUIRED_TEMP)
fire_power -= TURF_FIRE_POWER_LOSS_ON_LOW_TEMP * seconds_per_tick
fire_power -= TURF_FIRE_POWER_LOSS_BASE * seconds_per_tick
if(fire_power <= 0)
qdel(src)
return
var/effective_temperature = TURF_FIRE_TEMP_BASE + (TURF_FIRE_TEMP_INCREMENT_PER_POWER * fire_power)
T.hotspot_expose(effective_temperature)
//Nearby turfs may also trigger a fire (will only start fires if there's fuel, currently)
//Guaranteed fire spread in the last tick
if(prob(50 + fire_power) || fire_power == 1)
for(var/direction in GLOB.cardinals)
var/turf/simulated/other_tile = get_step(T, direction)
// Exit the loop early if the checked tile is not a valid direction for the fire to spread.
if(!istype(other_tile) || !(T.open_directions && direction) || other_tile.hotspot || other_tile.turf_fire) //Grab all valid bordering tiles
continue
other_tile.hotspot_expose(effective_temperature)
for(var/atom/movable/burning_atom as anything in T)
burning_atom.fire_act(exposed_temperature = effective_temperature, exposed_volume = TURF_FIRE_VOLUME)
UpdateFireState()
if(!interact_with_atmos || prob(fire_power) || !istype(T, /turf/simulated/floor))
return
var/turf/simulated/floor/F = T
F.burn_tile(effective_temperature)
/obj/turf_fire/proc/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
SIGNAL_HANDLER
if(!istype(arrived))
return
var/turf/T = loc
if(T.hotspot) //If we have an active hotspot, let it do the damage instead
return
arrived.fire_act(exposed_temperature = TURF_FIRE_TEMP_BASE + (TURF_FIRE_TEMP_INCREMENT_PER_POWER*fire_power), exposed_volume = TURF_FIRE_VOLUME)
return
/obj/turf_fire/proc/AddPower(power)
fire_power = min(TURF_FIRE_MAX_POWER, fire_power + power)
UpdateFireState()
/obj/turf_fire/proc/UpdateFireState()
var/new_state
switch(fire_power)
if(0 to 10)
new_state = TURF_FIRE_STATE_SMALL
if(11 to 24)
new_state = TURF_FIRE_STATE_MEDIUM
if(25 to 39)
new_state = TURF_FIRE_STATE_LARGE
if(40 to INFINITY)
new_state = TURF_FIRE_STATE_MAX
if(new_state == current_fire_state)
return
current_fire_state = new_state
switch(current_fire_state)
if(TURF_FIRE_STATE_SMALL)
icon_state = "small"
set_light(1.5, 0.5)
if(TURF_FIRE_STATE_MEDIUM)
icon_state = "medium"
set_light(2, 0.5)
if(TURF_FIRE_STATE_LARGE)
icon_state = "big"
set_light(2, 0.6)
if(TURF_FIRE_STATE_MAX)
icon_state = "max"
set_light(3, 0.7)
#undef TURF_FIRE_REQUIRED_TEMP
#undef TURF_FIRE_TEMP_BASE
#undef TURF_FIRE_POWER_LOSS_ON_LOW_TEMP
#undef TURF_FIRE_TEMP_INCREMENT_PER_POWER
#undef TURF_FIRE_VOLUME
#undef TURF_FIRE_MAX_POWER
#undef TURF_FIRE_ENERGY_PER_BURNED_OXY_MOL
#undef TURF_FIRE_BURN_RATE_BASE
#undef TURF_FIRE_BURN_RATE_PER_POWER
#undef TURF_FIRE_BURN_MINIMUM_OXYGEN_REQUIRED
#undef TURF_FIRE_BURN_PLAY_SOUND_EFFECT_CHANCE
#undef TURF_FIRE_STATE_SMALL
#undef TURF_FIRE_STATE_MEDIUM
#undef TURF_FIRE_STATE_LARGE
#undef TURF_FIRE_STATE_MAX