Fire Rework (#9669)

This commit is contained in:
Guti
2024-12-30 18:35:23 +01:00
committed by GitHub
parent 86acad39cb
commit 3beae0bde1
16 changed files with 324 additions and 4 deletions

View File

@@ -0,0 +1,147 @@
/turf/proc/lingering_fire(fl)
return
/turf/simulated/lingering_fire(fl)
if(istype(src, /turf/space) || istype(src, /turf/simulated/floor/water) || istype(src, /turf/simulated/flesh))
return FALSE
if(istype(src, /turf/simulated/open))
var/turf/below = GetBelow(src)
if(below)
return below.lingering_fire(fl)
if(!zone)
return TRUE
if(fire)
fire.firelevel = max(fl, fire.firelevel)
return TRUE
fire = new /obj/fire/lingering(src, fl)
SSair.active_fire_zones |= zone
zone.fire_tiles |= src
return FALSE
/turf/proc/feed_lingering_fire(var/amnt)
return
/turf/simulated/feed_lingering_fire(var/amnt)
if(fire && istype(fire, /obj/fire/lingering))
var/obj/fire/lingering/F = fire
F.firelevel += amnt
if(F.firelevel > 2) // Allow above 0 if fed
F.firelevel = 2
F.ultimate_burnout = 0 // Reset
zone.fire_tiles |= src
// Add C02
var/datum/gas_mixture/air_contents = return_air()
air_contents.adjust_gas(GAS_CO2, rand(1,5))
air_contents.update_values()
/obj/fire/lingering
anchored = TRUE // While it would be funny... Sadly no.
mouse_opacity = 0
icon = 'modular_chomp/icons/effects/fire.dmi'
icon_state = "fire"
light_color = "#ED9200"
layer = GASFIRE_LAYER
var/ultimate_burnout = 0 // If it reaches 1, begin dying down
/obj/fire/lingering/Initialize(mapload, fl)
if(fl > 1)
fl = 1
if(fl <= 0)
fl = 0.001
. = ..(mapload, fl)
// USes parent fire init, so let's clear these
icon_state = "[initial(icon_state)]-[rand(0, 2)]"
color = initial(color)
set_light(3, 1, l_color = light_color)
SSair.lingering_fires++
/obj/fire/lingering/process()
. = 1
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 TRUE
// Don't burn forever, eventually we have no more fuel
ultimate_burnout += 0.001
// Spread while burning out oxigen
var/datum/gas_mixture/air_contents = my_tile.return_air()
var/gas_exchange = rand(0.01, 0.2)
air_contents.remove_by_flag(XGM_GAS_OXIDIZER, gas_exchange)
air_contents.adjust_gas(GAS_CO2, gas_exchange * 1.5) // Lots of CO2
var/starting_energy = air_contents.temperature * air_contents.heat_capacity()
air_contents.temperature = (starting_energy + vsc.fire_fuel_energy_release * (gas_exchange * 1.05)) / air_contents.heat_capacity()
air_contents.update_values()
// Affect contents
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)
A.fire_act(air_contents, air_contents.temperature, air_contents.volume)
// Spreading behaviour
for(var/direction in shuffle(cardinal))
var/turf/simulated/enemy_tile = get_step(my_tile, direction)
if(istype(enemy_tile))
if(my_tile.open_directions & direction)
if(!enemy_tile.zone)
continue
// If extinguisher mist passed over the turf it's trying to spread to, don't spread and end the fire
if(enemy_tile.fire_protection > world.time-60)
firelevel = 0
qdel(src)
my_tile.fire = null
continue
if(enemy_tile.fire)
if(firelevel > 0.5)
// Share with other fires if we have the energy
enemy_tile.fire.firelevel += firelevel / 3
firelevel /= 2
continue
if(firelevel >= 0.15 && prob(60) && my_tile.CanPass(src, enemy_tile) && enemy_tile.CanPass(src, my_tile))
var/splitrate = 0.85
enemy_tile.lingering_fire(firelevel * splitrate)
firelevel -= (1 - splitrate)
else if(prob(20))
enemy_tile.adjacent_fire_act(loc, air_contents, air_contents.temperature, air_contents.volume)
var/total_oxidizers = 0
for(var/g in air_contents.gas)
if(gas_data.flags[g] & XGM_GAS_OXIDIZER)
total_oxidizers += air_contents.gas[g]
var/invalid_fire = total_oxidizers < 1 || air_contents.temperature <= (T0C + 15) || ultimate_burnout >= 1 || my_tile.is_outdoors() || SSair.lingering_fires >= 1000
if(prob(30) || invalid_fire)
if(total_oxidizers < 10 && prob(10))
firelevel *= 0.95
else if(invalid_fire)
firelevel *= 0.5
if(firelevel <= 0.01)
qdel(src)
my_tile.fire = null
/obj/fire/lingering/ex_act(strength)
. = ..()
var/turf/T = get_turf(src)
if(T)
T.fire = null
qdel(src)

View File

@@ -0,0 +1,89 @@
#define TRASH_BURN 0.05
#define LOW_BURN 0.1
#define GOOD_BURN 0.2
#define HIGH_BURN 0.5
#define SUPER_BURN 0.8
#define MEGA_BURN 1
#define LOW_CHANCE 3
#define MED_CHANCE 6
#define HIGH_CHANCE 12
// Additional fire_acts(), macro that assembles a proc that runs every time fire acts on the assigned object path of x.
// If it rolls the prob("c"hance) it will feed the lingering fire a 0 to 1 value as "b"urn. Then ex_act(1) the object while leaving ash behind.
// With great agony, I wish to report that I feel like I'm coding in C98 with this bullshit - Willbird
#define FIREACT_BURNS(x,c,b) x/fire_act(){if(prob(c)){var/turf/T = get_turf(src);T?.feed_lingering_fire(b);new /obj/effect/decal/cleanable/ash(get_turf(src));ex_act(1);}}
//////////////////////////// TRASH BURN ////////////////////////////
FIREACT_BURNS(/obj/item/trash,HIGH_CHANCE,TRASH_BURN)
FIREACT_BURNS(/obj/item/paper,HIGH_CHANCE,TRASH_BURN)
FIREACT_BURNS(/obj/item/soap,LOW_CHANCE,TRASH_BURN)
FIREACT_BURNS(/obj/item/storage/pill_bottle,MED_CHANCE,TRASH_BURN)
FIREACT_BURNS(/obj/item/assembly/mousetrap,HIGH_CHANCE,TRASH_BURN)
FIREACT_BURNS(/obj/structure/table/standard,LOW_CHANCE,TRASH_BURN)
FIREACT_BURNS(/obj/item/deck,LOW_CHANCE,TRASH_BURN)
//////////////////////////// LOW BURN ////////////////////////////
FIREACT_BURNS(/obj/item/stack/material/plastic,LOW_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/paper_bin,HIGH_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/bedsheet,HIGH_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/book,HIGH_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/folder,HIGH_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/storage/fancy/cigar,HIGH_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/structure/flora/pottedplant,LOW_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/storage/box,MED_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/juke_remote,LOW_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/mop,LOW_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/storage/pouch,LOW_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/storage/backpack,LOW_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/storage/bag/trash,LOW_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/reagent_containers/food,LOW_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/packageWrap,HIGH_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/item/tape_roll,LOW_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/structure/sign/christmas,LOW_CHANCE,LOW_BURN) // IT CRIMBO, OH NO IT CRIMBO
FIREACT_BURNS(/obj/structure/table/woodentable,MED_CHANCE,LOW_BURN)
FIREACT_BURNS(/obj/structure/table/gamblingtable,MED_CHANCE,LOW_BURN)
//////////////////////////// GOOD BURN ////////////////////////////
FIREACT_BURNS(/obj/item/stack/material/stick,MED_CHANCE,GOOD_BURN)
FIREACT_BURNS(/obj/item/stack/material/wax,MED_CHANCE,GOOD_BURN)
FIREACT_BURNS(/obj/structure/bookcase,LOW_CHANCE,GOOD_BURN)
FIREACT_BURNS(/obj/structure/simple_door/wood,LOW_CHANCE,GOOD_BURN)
FIREACT_BURNS(/obj/item/instrument,LOW_CHANCE,GOOD_BURN)
FIREACT_BURNS(/obj/item/toy/plushie,MED_CHANCE,GOOD_BURN)
FIREACT_BURNS(/obj/item/towel,HIGH_CHANCE,GOOD_BURN)
FIREACT_BURNS(/obj/structure/closet/crate/wooden,MED_CHANCE,GOOD_BURN)
FIREACT_BURNS(/obj/structure/bed,MED_CHANCE,GOOD_BURN)
//////////////////////////// HIGH BURN ////////////////////////////
FIREACT_BURNS(/obj/item/stack/material/wood,MED_CHANCE,HIGH_BURN)
FIREACT_BURNS(/obj/structure/flora/tree,LOW_CHANCE,HIGH_BURN)
//////////////////////////// MEGA BURN ////////////////////////////
FIREACT_BURNS(/obj/item/stack/material/phoron,MED_CHANCE,MEGA_BURN)
// The remaining proc is defined without the macro to give an example of what the macro used above outputs.
/obj/item/clothing/fire_act()
if(prob(LOW_CHANCE))
var/turf/T = get_turf(src)
T?.feed_lingering_fire(GOOD_BURN)
new /obj/effect/decal/cleanable/ash(get_turf(src))
ex_act(1)
// Suits need special handling to avoid fires destroying rigs
/obj/item/clothing/suit/fire_act()
return
// anti-lag ash cleanup
/obj/effect/decal/cleanable/ash/fire_act()
if(prob(2))
qdel(src)
#undef FIREACT_BURNS
#undef LOW_CHANCE
#undef MED_CHANCE
#undef HIGH_CHANCE
#undef TRASH_BURN
#undef LOW_BURN
#undef GOOD_BURN
#undef HIGH_BURN
#undef SUPER_BURN
#undef MEGA_BURN

View File

@@ -0,0 +1,51 @@
/datum/event/electrical_fire/start()
if(!machines.len)
return
var/list/possible_machines = list()
for(var/obj/machinery/M in machines)
var/area/A = get_area(M)
if(!A)
continue
if(A.flag_check(AREA_FORBID_EVENTS))
continue
if(istype( A, /area/maintenance ))
continue
if(istype( A, /area/shuttle ))
continue
var/turf/T = get_turf(M)
if(!T)
continue
if(T.is_outdoors())
continue
if(!(T.z in using_map.station_levels))
continue
// All of these make fires, a good spread in populated areas
if(istype(M,/obj/machinery/light_switch))
var/obj/machinery/light_switch/L = M
if(L.on)
possible_machines.Add(M) // prefer rooms that are in use
if(istype(M,/obj/machinery/washing_machine) \
|| istype(M,/obj/machinery/microwave) \
|| istype(M,/obj/machinery/recharge_station) \
|| istype(M,/obj/machinery/power/thermoregulator/cryogaia))
if(!(M.stat & NOPOWER)) // Has to be powered
possible_machines.Add(M)
if(!possible_machines.len)
return
// set alight!
var/obj/machinery/M = pick(possible_machines)
if(M)
M.visible_message(span_warning("\The [M] sparks violently and catches fire!"))
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
sparks.set_up(4, 1, get_turf(M))
sparks.start()
var/turf/T = get_turf(M)
T.lingering_fire(0.6)
var/area/A = get_area(T)
log_admin("Electrical event: [M] in [A] caught fire.")
message_admins("Electrical event: [M] in [A] caught fire.")

View File

@@ -125,6 +125,7 @@
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/blob, -100, list(ASSIGNMENT_SECURITY = 40, ASSIGNMENT_HOS = 10, ASSIGNMENT_WARDEN = 10, ASSIGNMENT_ENGINEER = 5), 1, min_jobs = list(ASSIGNMENT_SECURITY = 1)),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Carp Migration", /datum/event/carp_migration, -110, list(ASSIGNMENT_SECURITY = 50, ASSIGNMENT_HOS = 10, ASSIGNMENT_WARDEN = 10), 1, min_jobs = list(ASSIGNMENT_SECURITY = 3)),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Disease Outbreak", /datum/event/disease_outbreak, -30, list(ASSIGNMENT_MEDICAL = 30, ASSIGNMENT_ANY = 1), 1, min_jobs = list(ASSIGNMENT_MEDICAL = 2)),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Electrical Fire", /datum/event/electrical_fire, 5, list(ASSIGNMENT_ENGINEER = 5, ASSIGNMENT_CYBORG = 5), 0),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Exotic Horde Infestation", /datum/event/highdangerinfestation, -50, list(ASSIGNMENT_ENGINEER = 20, ASSIGNMENT_SCIENCE = 5, ASSIGNMENT_ANY = 2), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Horde Infestation", /datum/event/horde_infestation, -60, list(ASSIGNMENT_SECURITY = 20, ASSIGNMENT_HOS = 10, ASSIGNMENT_WARDEN = 10, ASSIGNMENT_ANY = 3), 0),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Infected Room", /datum/event/disease_outbreak/floor, -50, list(ASSIGNMENT_MEDICAL = 25, ASSIGNMENT_JANITOR = 10, ASSIGNMENT_ANY = 1), 1, min_jobs = list(ASSIGNMENT_MEDICAL = 2)),