Files
Cody Brittain 9b5f89a717 Ports Turf Fires (#21659)
Adds turf fires (ported from Baystation, which ported them from
Shiptest), which are now used instead of ZAS fires for fuel decals and
flamethrowers. They also supplement ZAS fires in especially bad atmos
fires.

This makes flamethrowers and related objects more suitable for AOE
denial, rather than cooking the room (including yourself). They still do
the latter, but less so than a gaseous fire.

To make flamethrowers actually useful against them, simple mobs now take
brute damage when on fire.

### Asset Licenses
The following assets that **have not** been created by myself are
included in this PR:

| Path | Original Author | License |
| --- | --- | --- |
| sound/weapons/flamethrower/flamethrower1.ogg |
[rye-rice](https://github.com/rye-rice) (Shiptest) | CC-BY-SA 3.0 |
| sound/weapons/flamethrower/flamethrower2.ogg |
[rye-rice](https://github.com/rye-rice) (Shiptest) | CC-BY-SA 3.0 |
| sound/weapons/flamethrower/flamethrower3.ogg |
[rye-rice](https://github.com/rye-rice) (Shiptest) | CC-BY-SA 3.0 |
| sound/weapons/flamethrower/flamethrower_empty.ogg |
[rye-rice](https://github.com/rye-rice) (Shiptest) | CC-BY-SA 3.0 |
| icons/effects/particles/smoke.dmi |
[rye-rice](https://github.com/shiptest-ss13/Shiptest/commits?author=rye-rice)
(Shiptest) | CC-BY-SA 3.0 |
| icons/effects/turf_fire.dmi | CM Dev (cmss13) | CC-BY-SA 3.0 |
2026-01-31 01:41:11 +00:00

191 lines
5.4 KiB
Plaintext

/*
Overview:
Each zone is a self-contained area where gas values would be the same if tile-based equalization were run indefinitely.
If you're unfamiliar with ZAS, FEA's air groups would have similar functionality if they didn't break in a stiff breeze.
Class Vars:
name - A name of the format "Zone [#]", used for debugging.
invalid - True if the zone has been erased and is no longer eligible for processing.
needs_update - True if the zone has been added to the update list.
edges - A list of edges that connect to this zone.
air - The gas mixture that any turfs in this zone will return. Values are per-tile with a group multiplier.
Class Procs:
add(turf/simulated/T)
Adds a turf to the contents, sets its zone and merges its air.
remove(turf/simulated/T)
Removes a turf, sets its zone to null and erases any gas graphics.
Invalidates the zone if it has no more tiles.
c_merge(zone/into)
Invalidates this zone and adds all its former contents to into.
c_invalidate()
Marks this zone as invalid and removes it from processing.
rebuild()
Invalidates the zone and marks all its former tiles for updates.
add_tile_air(turf/simulated/T)
Adds the air contained in T.air to the zone's air supply. Called when adding a turf.
tick()
Called only when the gas content is changed. Archives values and changes gas graphics.
dbg_data(mob/M)
Sends M a printout of important figures for the zone.
*/
/zone
var/name
var/invalid = 0
var/list/contents = list()
var/list/fire_tiles
var/needs_update = 0
var/list/connection_edge/edges
var/datum/gas_mixture/air = new
var/list/graphic_add = list()
var/list/graphic_remove = list()
/zone/New()
SSair.add_zone(src)
air.temperature = TCMB
air.group_multiplier = 1
air.volume = CELL_VOLUME
/zone/proc/add(turf/simulated/T)
#ifdef ZASDBG
ASSERT(!invalid)
ASSERT(istype(T))
ASSERT(!TURF_HAS_VALID_ZONE(T))
#endif
var/datum/gas_mixture/turf_air = T.return_air()
add_tile_air(turf_air)
T.zone = src
contents += T
if(T.hotspot)
LAZYADD(fire_tiles, T)
SSair.active_fire_zones |= src
T.update_graphic(air.graphic)
/zone/proc/remove(turf/simulated/T)
#ifdef ZASDBG
ASSERT(!invalid)
ASSERT(istype(T))
ASSERT(T.zone == src)
soft_assert(T in contents, "Lists are weird broseph")
#endif
contents -= T
LAZYREMOVE(fire_tiles, T)
T.zone = null
T.update_graphic(graphic_remove = air.graphic)
if(contents.len)
air.group_multiplier = contents.len
else
c_invalidate()
/zone/proc/c_merge(zone/into)
#ifdef ZASDBG
ASSERT(!invalid)
ASSERT(istype(into))
ASSERT(into != src)
ASSERT(!into.invalid)
#endif
c_invalidate()
for(var/turf/simulated/T in contents)
into.add(T)
T.update_graphic(graphic_remove = air.graphic)
#ifdef ZASDBG
T.dbg(GLOB.merged)
#endif
//rebuild the old zone's edges so that they will be possessed by the new zone
for(var/ee in edges)
var/connection_edge/E = ee
if(E.contains_zone(into))
continue //don't need to rebuild this edge
for(var/T in E.connecting_turfs)
SSair.mark_for_update(T)
/zone/proc/c_invalidate()
invalid = 1
SSair.remove_zone(src)
#ifdef ZASDBG
for(var/turf/simulated/T in contents)
T.dbg(GLOB.invalid_zone)
#endif
/zone/proc/rebuild()
set waitfor = FALSE
if(invalid) return //Short circuit for explosions where rebuild is called many times over.
c_invalidate()
for(var/turf/simulated/T in contents)
T.update_graphic(graphic_remove = air.graphic) //we need to remove the overlays so they're not doubled when the zone is rebuilt
//T.dbg(invalid_zone)
T.needs_air_update = 0 //Reset the marker so that it will be added to the list.
SSair.mark_for_update(T)
CHECK_TICK
/zone/proc/add_tile_air(datum/gas_mixture/tile_air)
//air.volume += CELL_VOLUME
air.group_multiplier = 1
air.multiply(contents.len)
air.merge(tile_air)
air.divide(contents.len+1)
air.group_multiplier = contents.len+1
/zone/proc/tick()
// Update fires.
if(air.temperature >= PHORON_FLASHPOINT && !(src in SSair.active_fire_zones) && air.check_combustibility() && contents.len)
var/turf/T = pick(contents)
if(istype(T))
T.create_fire(GLOB.vsc.fire_firelevel_multiplier)
// Update gas overlays.
if(air.check_tile_graphic(graphic_add, graphic_remove))
for(var/turf/simulated/T in contents)
T.update_graphic(graphic_add, graphic_remove)
graphic_add.Cut()
graphic_remove.Cut()
// Update connected edges.
for(var/connection_edge/E in edges)
if(E.sleeping)
E.recheck()
/zone/proc/dbg_data(mob/M)
to_chat(M, name)
for(var/g in air.gas)
to_chat(M, "[gas_data.name[g]]: [air.gas[g]]")
to_chat(M, "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]K ([air.temperature - T0C]C)")
to_chat(M, "O2 per N2: [(air.gas[GAS_NITROGEN] ? air.gas[GAS_OXYGEN]/air.gas[GAS_NITROGEN] : "N/A")] Moles: [air.total_moles]")
to_chat(M, "Simulated: [contents.len] ([air.group_multiplier])")
//to_chat(M, "Unsimulated: [unsimulated_contents.len]")
//to_chat(M, "Edges: [LAZYLEN(edges)]")
if(invalid) to_chat(M, "Invalid!")
var/zone_edges = 0
var/space_edges = 0
var/space_coefficient = 0
for(var/ee in edges)
var/connection_edge/E = ee
if(E.type == /connection_edge/zone) zone_edges++
else
space_edges++
space_coefficient += E.coefficient
to_chat(M, "[E:air:return_pressure()]kPa")
to_chat(M, "Zone Edges: [zone_edges]")
to_chat(M, "Space Edges: [space_edges] ([space_coefficient] connections)")
//for(var/turf/T in unsimulated_contents)
// to_chat(M, "[T] at ([T.x],[T.y])")