Files
2024-01-19 00:18:40 +11:00

389 lines
11 KiB
Plaintext

/obj/structure/wood_fire // abstract type, do not use
icon = 'icons/obj/wood_fire.dmi'
density = FALSE
anchored = TRUE
buckle_lying = FALSE
layer = TURF_LAYER + 0.5 // We want it to layer underneath food and things on top of it.
var/base_icon_state = "bonfire"
var/can_dismantle = TRUE
var/burning = FALSE
var/next_fuel_consumption = 0 // world.time of when next item in fuel list gets eatten to sustain the fire.
var/grill = FALSE
var/set_temperature = T0C + 30 //K
var/heating_power = 80000
var/datum/looping_sound/fire_crackles/fire_loop
var/datum/looping_sound/grill/grill_loop // Used when food is cooking on the fire.
/obj/structure/wood_fire/Initialize()
. = ..()
fire_loop = new(list(src), FALSE)
grill_loop = new(list(src), FALSE)
/obj/structure/wood_fire/Destroy()
QDEL_NULL(fire_loop)
QDEL_NULL(grill_loop)
return ..()
/obj/structure/wood_fire/proc/get_upgrade_options()
if(grill || can_buckle)
return null
if(!grill)
LAZYADD(., "Grill")
if(!can_buckle)
LAZYADD(., "Stake")
/obj/structure/wood_fire/proc/try_build_feature(var/mob/user, var/obj/item/stack/rods/rods)
if(!istype(rods))
return FALSE
var/list/upgrade_options = get_upgrade_options()
var/choice
if(!length(upgrade_options))
return FALSE
if(length(upgrade_options) == 1)
choice = upgrade_options[1]
else
choice = input(user, "What would you like to construct?", "Constructing Grill") as null|anything in upgrade_options
if(QDELETED(rods) || rods.get_amount() < 1 || user.incapacitated() || !Adjacent(user))
return TRUE
switch(choice)
if("Stake")
rods.use(1)
can_buckle = TRUE
buckle_require_restraints = TRUE
to_chat(user, SPAN_NOTICE("You add a rod to \the [src]."))
if("Grill")
rods.use(1)
grill = TRUE
to_chat(user, SPAN_NOTICE("You add a grill to \the [src]."))
else
return TRUE
update_icon()
return TRUE
/obj/structure/wood_fire/attackby(obj/item/W, mob/user)
// Place food on the grill.
if(istype(W, /obj/item/reagent_containers/food/snacks) && grill)
if(user.unEquip(W))
W.dropInto(loc)
// Place it on top of the grill.
W.pixel_x = 0
W.pixel_y = 12
return TRUE
if(try_build_feature(user, W))
return TRUE
if(istype(W, /obj/item/stack/material/fuel))
add_fuel(W, user)
return TRUE
if(W.is_hot())
ignite()
return TRUE
return ..()
/obj/structure/wood_fire/attack_hand(mob/user)
if(!has_buckled_mobs())
if(get_fuel_amount())
remove_fuel(user)
return TRUE
if(can_dismantle)
dismantle(user)
return TRUE
return ..()
/obj/structure/wood_fire/proc/dismantle(mob/user)
if(!burning)
user.visible_message("[user] starts dismantling \the [src].", "You start dismantling \the [src].")
if(do_after(user, 5 SECONDS))
for(var/obj/item/thing in contents)
thing.dropInto(loc)
user.visible_message("[user] dismantles down \the [src].", "You dismantle \the [src].")
qdel(src)
else
to_chat(user, SPAN_WARNING("\The [src] is still burning. Extinguish it first if you want to dismantle it."))
/obj/structure/wood_fire/proc/get_fuel_amount()
. = 0
for(var/obj/item/stack/material/fuel/fuel in contents)
. += (fuel.amount * fuel.bonfire_fuel_time) / (2 MINUTES)
/obj/structure/wood_fire/proc/remove_fuel(mob/user)
if(!get_fuel_amount())
return
var/atom/movable/AM = pop(contents)
if(!istype(AM))
return
AM.forceMove(get_turf(src))
to_chat(user, SPAN_NOTICE("You take \the [AM] out of \the [src] before it has a chance to burn away."))
update_icon()
/obj/structure/wood_fire/proc/add_fuel(atom/movable/new_fuel, mob/user)
if(get_fuel_amount() >= 10)
to_chat(user, SPAN_WARNING("\The [src] already has enough fuel!"))
return FALSE
if(istype(new_fuel, /obj/item/stack/material/fuel/wood) || istype(new_fuel, /obj/item/stack/material/fuel/log) )
var/obj/item/stack/F = new_fuel
var/obj/item/stack/S = F.split(1)
if(S)
S.forceMove(src)
to_chat(user, SPAN_WARNING("You add \the [new_fuel] to \the [src]."))
update_icon()
return TRUE
return FALSE
else
to_chat(user, SPAN_WARNING("\The [src] needs raw wood to burn, \a [new_fuel] won't work."))
return FALSE
/obj/structure/wood_fire/proc/consume_fuel()
var/obj/item/stack/consumed_fuel
for(var/atom/movable/thing in contents)
if(!thing.simulated)
continue
consumed_fuel = thing
break
if(!istype(consumed_fuel, /obj/item/stack/material/fuel))
if(consumed_fuel)
qdel(consumed_fuel) // Don't know, don't care.
return FALSE
var/obj/item/stack/material/fuel/fuel_stack = consumed_fuel
next_fuel_consumption = world.time + max(1 MINUTE, fuel_stack.bonfire_fuel_time)
fuel_stack.use(1)
update_icon()
return TRUE
/obj/structure/wood_fire/proc/extinguish()
if(!burning)
return
burning = FALSE
update_icon()
STOP_PROCESSING(SSobj, src)
visible_message(SPAN_NOTICE("\The [src] stops burning."))
if(fire_loop?.started)
fire_loop.stop(src)
/obj/structure/wood_fire/proc/ignite()
if(burning || !get_fuel_amount())
return
burning = TRUE
update_icon()
START_PROCESSING(SSobj, src)
visible_message(SPAN_NOTICE("\The [src] starts burning!"))
if(fire_loop && !fire_loop.started)
fire_loop.start(src)
/obj/structure/wood_fire/proc/get_fuel_overlay(var/fuel_amount)
if(fuel_amount)
var/image/I = image(icon, "[base_icon_state]_fuelled")
I.appearance_flags = RESET_COLOR | KEEP_APART
var/obj/item/stack/material/fuel/fuel = locate() in contents
I.color = fuel?.material?.icon_colour
return I
/obj/structure/wood_fire/update_icon()
cut_overlays()
// Draw our fuel overlay and colour it based on fuel material.
var/fuel_amount = get_fuel_amount()
var/fuel_overlay = get_fuel_overlay(fuel_amount)
if(fuel_overlay)
if(islist(fuel_overlay))
for(var/overlay in fuel_overlay)
add_overlay(overlay)
else
add_overlay(fuel_overlay)
if(burning)
// Draw our actual fire icon.
var/image/I = image(icon, ((fuel_amount >= 5) ? "[base_icon_state]_hot" : "[base_icon_state]_warm"))
I.appearance_flags = RESET_COLOR | KEEP_APART
add_overlay(I)
// If we're capable of burning buckled mobs (usually via a stake),
// draw an intense fire overlay and offset it to cover the mob.
if(fire_is_burning_mobs())
I = image(icon, "[base_icon_state]_intense")
I.pixel_y = 13
I.layer = MOB_LAYER + 0.1
I.appearance_flags = RESET_COLOR | KEEP_APART
add_overlay(I)
// Update our lights.
var/light_strength = max(fuel_amount / 2, 2)
set_light(light_strength, light_strength, COLOR_FIRE_ORANGE)
else
set_light(0)
if(grill)
var/image/grille_image = image(icon, "[base_icon_state]_grill")
grille_image.appearance_flags = RESET_COLOR | KEEP_APART
add_overlay(grille_image)
underlays.Cut()
if(can_buckle)
var/mutable_appearance/rod_underlay = mutable_appearance('icons/obj/structures.dmi', "[base_icon_state]_rod")
rod_underlay.pixel_y = 16
rod_underlay.appearance_flags = RESET_COLOR | PIXEL_SCALE | TILE_BOUND | KEEP_APART
underlays += rod_underlay
/obj/structure/wood_fire/proc/fire_is_burning_mobs()
return has_buckled_mobs() && get_fuel_amount() >= 5
/obj/structure/wood_fire/process()
// Are we even alight?
if(!burning)
return
// Should we even be alight?
var/datum/gas_mixture/env = loc?.return_air()
if(env?.gas["oxygen"] < 1 || (world.time >= next_fuel_consumption && !consume_fuel()))
extinguish()
return
// Ignite anything sitting on the same turf as us.
if(isturf(loc))
var/turf/current_turf = loc
current_turf.hotspot_expose(1000, 500)
// See if we can dry out anything around us, or cook any food.
var/grilling = FALSE
for(var/obj/item/thing in view(1, src))
var/on_top_of_fire = thing.loc == loc
if(on_top_of_fire)
if(!grilling && istype(thing, /obj/item/reagent_containers/food/snacks))
grilling = TRUE
if(!grill)
thing.fire_act(null, 1000, 500)
continue
thing.dry_out(src, max(1, 3 - get_dist(thing, src)), on_top_of_fire)
// If we're cooking food, play a food cooking souond.
if(grill_loop)
if(grilling)
if(!grill_loop.started)
grill_loop.start(src)
else
if(grill_loop.started)
grill_loop.stop(src)
// If we're low enough, don't burn anything or put out
// any significant heat, they need to refuel the fire.
var/fuel_amount = get_fuel_amount()
if(fuel_amount < 5)
return
// Burn anything standing on our turf.
var/adj_fuel_amount = fuel_amount / 4
for(var/mob/living/victim in loc)
victim.adjust_fire_stacks(adj_fuel_amount / 4)
victim.IgniteMob()
// Heat up our environment.
if(!env || abs(env.temperature - set_temperature) <= 0.1)
return
var/transfer_moles = 0.25 * env.total_moles
var/datum/gas_mixture/removed = env.remove(transfer_moles)
var/heat_transfer = removed?.get_thermal_energy_change(set_temperature)
if(heat_transfer > 0)
heat_transfer = min(heat_transfer, heating_power)
removed.add_thermal_energy(heat_transfer)
for(var/mob/living/L in view(3, src))
L.add_modifier(/datum/modifier/endothermic, 10 SECONDS, null, TRUE)
env.merge(removed)
/obj/structure/wood_fire/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
ignite()
/obj/structure/wood_fire/water_act(amount)
if(prob(amount * 10))
extinguish()
/obj/structure/wood_fire/post_buckle_mob(mob/living/M)
if(M.buckled == src) // Just buckled someone
M.pixel_y += 13
else // Just unbuckled someone
M.pixel_y -= 13
update_icon()
// A freestanding fire for cooking food on.
/obj/structure/wood_fire/bonfire
name = "bonfire"
desc = "For grilling, broiling, charring, smoking, heating, roasting, toasting, simmering, searing, melting, and occasionally burning things."
icon_state = "bonfire"
// Pre-fuelled for recipes/maps.
/obj/structure/wood_fire/bonfire/fuelled/Initialize()
. = ..()
for(var/i = 1 to 5)
new /obj/item/stack/material/fuel/log(src)
update_icon()
// Blue wood.
/obj/structure/wood_fire/bonfire/sifwood/Initialize()
. = ..()
for(var/i = 1 to 5)
new /obj/item/stack/material/fuel/log/sif(src)
update_icon()
// A smaller bonfire.
/obj/structure/wood_fire/campfire
name = "campfire"
desc = "A small firepit for camping. Did anyone bring the marshmallows?"
icon_state = "campfire"
base_icon_state = "campfire"
can_dismantle = FALSE
can_buckle = FALSE
set_temperature = T0C + 20 //K
heating_power = 40000
/obj/structure/wood_fire/campfire/get_upgrade_options()
if(!grill)
return list("Grill")
// more like a space heater than a bonfire. A cozier alternative to both.
/obj/structure/wood_fire/fireplace
name = "fireplace"
desc = "The sound of the crackling hearth reminds you of home."
icon_state = "fireplace"
base_icon_state = "fireplace"
density = TRUE
set_temperature = T0C + 20 //K
heating_power = 40000
can_dismantle = FALSE
can_buckle = FALSE
grill = TRUE
/obj/structure/wood_fire/fireplace/get_upgrade_options()
if(!grill)
return list("Grill")
/obj/structure/wood_fire/fireplace/stove
name = "stove"
desc = "A rustic, soot-stained wood-fired stove. Better check your CO detector."
grill = FALSE
icon_state = "stove"
base_icon_state = "stove"
/obj/structure/wood_fire/fireplace/stove/get_upgrade_options()
return
/obj/structure/wood_fire/fireplace/stove/get_fuel_overlay(var/fuel_amount)
. = ..()
if(!.)
. = "[base_icon_state]_cover"
else if(islist(.))
. += "[base_icon_state]_cover"
else
. = list(., "[base_icon_state]_cover")