diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index bd3eb7fe31..71e5170852 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -650,3 +650,7 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
if(AStar(get_turf(us), get_turf(them), /turf/proc/AdjacentTurfsRangedSting, /turf/proc/Distance, max_nodes=25, max_node_depth=range))
return TRUE
return FALSE
+
+// Check if an object should ignite others, like a lit lighter or candle.
+/obj/item/proc/is_hot()
+ return FALSE
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm
index 48ab1df6bb..c8d4eed3ad 100644
--- a/code/game/objects/items/weapons/cigs_lighters.dm
+++ b/code/game/objects/items/weapons/cigs_lighters.dm
@@ -16,16 +16,8 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/weapon/flame
var/lit = 0
-/proc/isflamesource(A)
- if(istype(A, /obj/item/weapon/weldingtool))
- var/obj/item/weapon/weldingtool/WT = A
- return (WT.isOn())
- else if(istype(A, /obj/item/weapon/flame))
- var/obj/item/weapon/flame/F = A
- return (F.lit)
- else if(istype(A, /obj/item/device/assembly/igniter))
- return 1
- return 0
+/obj/item/weapon/flame/is_hot()
+ return lit
///////////
//MATCHES//
@@ -237,7 +229,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/smokable/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
- if(isflamesource(W))
+ if(W.is_hot())
var/text = matchmes
if(istype(W, /obj/item/weapon/flame/match))
text = matchmes
diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm
index 414de6686d..c27db4356d 100644
--- a/code/game/objects/items/weapons/tools.dm
+++ b/code/game/objects/items/weapons/tools.dm
@@ -628,6 +628,9 @@
user.disabilities &= ~NEARSIGHTED
return
+/obj/item/weapon/weldingtool/is_hot()
+ return isOn()
+
/obj/item/weapon/weldingtool/largetank
name = "industrial welding tool"
desc = "A slightly larger welder with a larger tank."
diff --git a/code/game/objects/structures/bonfire.dm b/code/game/objects/structures/bonfire.dm
new file mode 100644
index 0000000000..339c93385d
--- /dev/null
+++ b/code/game/objects/structures/bonfire.dm
@@ -0,0 +1,238 @@
+/obj/structure/bonfire
+ name = "bonfire"
+ desc = "For grilling, broiling, charring, smoking, heating, roasting, toasting, simmering, searing, melting, and occasionally burning things."
+ icon = 'icons/obj/structures.dmi'
+ icon_state = "bonfire"
+ density = FALSE
+ anchored = TRUE
+ buckle_lying = FALSE
+ 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/material/material
+
+/obj/structure/bonfire/New(newloc, material_name)
+ ..(newloc)
+ if(!material_name)
+ material_name = "wood"
+ material = get_material_by_name("[material_name]")
+ if(!material)
+ qdel(src)
+ return
+ color = material.icon_colour
+
+// Blue wood.
+/obj/structure/bonfire/sifwood/New(newloc, material_name)
+ ..(newloc, "alien wood")
+
+/obj/structure/bonfire/permanent/New(newloc, material_name)
+ ..()
+ ignite()
+
+/obj/structure/bonfire/permanent/sifwood/New(newloc, material_name)
+ ..(newloc, "alien wood")
+
+/obj/structure/bonfire/attackby(obj/item/W, mob/user)
+ if(istype(W, /obj/item/stack/rods) && !can_buckle && !grill)
+ var/obj/item/stack/rods/R = W
+ var/choice = input(user, "What would you like to construct?", "Bonfire") as null|anything in list("Stake","Grill")
+ switch(choice)
+ if("Stake")
+ R.use(1)
+ can_buckle = TRUE
+ buckle_require_restraints = TRUE
+ to_chat(user, "You add a rod to \the [src].")
+ var/mutable_appearance/rod_underlay = mutable_appearance('icons/obj/structures.dmi', "bonfire_rod")
+ rod_underlay.pixel_y = 16
+ rod_underlay.appearance_flags = RESET_COLOR|PIXEL_SCALE|TILE_BOUND
+ underlays += rod_underlay
+ if("Grill")
+ R.use(1)
+ grill = TRUE
+ to_chat(user, "You add a grill to \the [src].")
+ update_icon()
+ else
+ return ..()
+
+ else if(istype(W, /obj/item/stack/material/wood) || istype(W, /obj/item/stack/material/log) )
+ add_fuel(W, user)
+
+ else if(W.is_hot())
+ ignite()
+ else
+ return ..()
+
+/obj/structure/bonfire/attack_hand(mob/user)
+ if(buckled_mob)
+ return ..()
+
+ if(get_fuel_amount())
+ remove_fuel(user)
+ else
+ dismantle(user)
+
+
+/obj/structure/bonfire/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/i = 1 to 5)
+ material.place_dismantled_product(get_turf(src))
+ user.visible_message("[user] dismantles down \the [src].", "You dismantle \the [src].")
+ qdel(src)
+ else
+ to_chat(user, "\The [src] is still burning. Extinguish it first if you want to dismantle it.")
+
+/obj/structure/bonfire/proc/get_fuel_amount()
+ var/F = 0
+ for(var/A in contents)
+ if(istype(A, /obj/item/stack/material/wood))
+ F += 0.5
+ if(istype(A, /obj/item/stack/material/log))
+ F += 1.0
+ return F
+
+/obj/structure/bonfire/permanent/get_fuel_amount()
+ return 10
+
+/obj/structure/bonfire/proc/remove_fuel(mob/user)
+ if(get_fuel_amount())
+ var/atom/movable/AM = pop(contents)
+ AM.forceMove(get_turf(src))
+ to_chat(user, "You take \the [AM] out of \the [src] before it has a chance to burn away.")
+ update_icon()
+
+/obj/structure/bonfire/permanent/remove_fuel(mob/user)
+ dismantle(user)
+
+/obj/structure/bonfire/proc/add_fuel(atom/movable/new_fuel, mob/user)
+ if(get_fuel_amount() >= 10)
+ to_chat(user, "\The [src] already has enough fuel!")
+ return FALSE
+ if(istype(new_fuel, /obj/item/stack/material/wood) || istype(new_fuel, /obj/item/stack/material/log) )
+ var/obj/item/stack/F = new_fuel
+ var/obj/item/stack/S = F.split(1)
+ if(S)
+ S.forceMove(src)
+ to_chat(user, "You add \the [new_fuel] to \the [src].")
+ update_icon()
+ return TRUE
+ return FALSE
+ else
+ to_chat(user, "\The [src] needs raw wood to burn, \a [new_fuel] won't work.")
+ return FALSE
+
+/obj/structure/bonfire/permanent/add_fuel(mob/user)
+ to_chat(user, "\The [src] has plenty of fuel and doesn't need more fuel.")
+
+/obj/structure/bonfire/proc/consume_fuel(var/obj/item/stack/consumed_fuel)
+ if(!istype(consumed_fuel))
+ qdel(consumed_fuel) // Don't know, don't care.
+ return FALSE
+
+ if(istype(consumed_fuel, /obj/item/stack/material/log))
+ next_fuel_consumption = world.time + 2 MINUTES
+ qdel(consumed_fuel)
+ update_icon()
+ return TRUE
+
+ else if(istype(consumed_fuel, /obj/item/stack/material/wood)) // One log makes two planks of wood.
+ next_fuel_consumption = world.time + 1 MINUTE
+ qdel(consumed_fuel)
+ update_icon()
+ return TRUE
+ return FALSE
+
+/obj/structure/bonfire/permanent/consume_fuel()
+ return TRUE
+
+/obj/structure/bonfire/proc/check_oxygen()
+ var/datum/gas_mixture/G = loc.return_air()
+ if(G.gas["oxygen"] < 1)
+ return FALSE
+ return TRUE
+
+
+/obj/structure/bonfire/proc/extinguish()
+ if(burning)
+ burning = FALSE
+ update_icon()
+ processing_objects -= src
+ visible_message("\The [src] stops burning.")
+
+/obj/structure/bonfire/proc/ignite()
+ if(!burning && get_fuel_amount())
+ burning = TRUE
+ update_icon()
+ processing_objects += src
+ visible_message("\The [src] starts burning!")
+
+/obj/structure/bonfire/proc/burn()
+ var/turf/current_location = get_turf(src)
+ current_location.hotspot_expose(1000, 500)
+ for(var/A in current_location)
+ if(A == src)
+ continue
+ if(isobj(A))
+ var/obj/O = A
+ O.fire_act(null, 1000, 500)
+ else if(isliving(A) && get_fuel_amount() > 4)
+ var/mob/living/L = A
+ L.adjust_fire_stacks(get_fuel_amount() / 4)
+ L.IgniteMob()
+
+/obj/structure/bonfire/update_icon()
+ overlays.Cut()
+ if(burning)
+ var/state
+ switch(get_fuel_amount())
+ if(0 to 4)
+ state = "bonfire_warm"
+ if(5 to 10)
+ state = "bonfire_hot"
+ var/image/I = image(icon, state)
+ I.appearance_flags = RESET_COLOR
+ overlays += I
+
+ if(buckled_mob && get_fuel_amount() >= 5)
+ I = image(icon, "bonfire_intense")
+ I.pixel_y = 13
+ I.layer = MOB_LAYER + 0.1
+ I.appearance_flags = RESET_COLOR
+ overlays += I
+
+ var/light_strength = max(get_fuel_amount() / 2, 2)
+ set_light(light_strength, light_strength, "#FF9933")
+ else
+ set_light(0)
+
+ if(grill)
+ var/image/grille_image = image(icon, "bonfire_grill")
+ grille_image.appearance_flags = RESET_COLOR
+ overlays += grille_image
+
+
+/obj/structure/bonfire/process()
+ if(!check_oxygen())
+ extinguish()
+ return
+ if(world.time >= next_fuel_consumption)
+ if(!consume_fuel(pop(contents)))
+ extinguish()
+ return
+ if(!grill)
+ burn()
+
+/obj/structure/bonfire/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ ignite()
+
+/obj/structure/bonfire/water_act(amount)
+ if(prob(amount * 10))
+ extinguish()
+
+/obj/structure/bonfire/post_buckle_mob(mob/living/M)
+ if(buckled_mob) // Just buckled someone
+ M.pixel_y += 13
+ else // Just unbuckled someone
+ M.pixel_y -= 13
+ update_icon()
\ No newline at end of file
diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm
index e8fe1d4b3e..e583085513 100644
--- a/code/game/objects/structures/flora.dm
+++ b/code/game/objects/structures/flora.dm
@@ -196,7 +196,9 @@
name = "unusual potted plant"
desc = "This is an unusual plant. It's bulbous ends emit a soft blue light."
icon_state = "plant-09"
- set_light(l_range = 1, l_power = 0.5, l_color = "#0000FF")
+ light_range = 2
+ light_power = 1
+ light_color = "#33CCFF"
/obj/structure/flora/pottedplant/orientaltree
name = "potted oriental tree"
@@ -252,7 +254,9 @@
name = "subterranean potted plant"
desc = "This is a subterranean plant. It's bulbous ends glow faintly."
icon_state = "plant-20"
- set_light(l_range = 1, l_power = 0.5, l_color = "#FF6633")
+ light_range = 2
+ light_power = 1
+ light_color = "#FF6633"
/obj/structure/flora/pottedplant/minitree
name = "potted tree"
@@ -288,3 +292,25 @@
name = "small christmas tree"
desc = "This is a tiny well lit decorative christmas tree."
icon_state = "plant-xmas"
+
+/obj/structure/flora/sif
+ icon = 'icons/obj/flora/sifflora.dmi'
+
+/obj/structure/flora/sif/subterranean
+ name = "subterranean plant"
+ desc = "This is a subterranean plant. It's bulbous ends glow faintly."
+ icon_state = "glowplant"
+ light_range = 2
+ light_power = 1
+ light_color = "#FF6633"
+
+/obj/structure/flora/sif/subterranean/initialize()
+ icon_state = "[initial(icon_state)][rand(1,2)]"
+
+/obj/structure/flora/sif/eyes
+ name = "mysterious bulbs"
+ desc = "This is a mysterious looking plant. They kind of look like eyeballs. Creepy."
+ icon_state = "eyeplant"
+
+/obj/structure/flora/sif/eyes/initialize()
+ icon_state = "[initial(icon_state)][rand(1,3)]"
\ No newline at end of file
diff --git a/code/modules/assembly/igniter.dm b/code/modules/assembly/igniter.dm
index c7b0b619ba..4c23f988cd 100644
--- a/code/modules/assembly/igniter.dm
+++ b/code/modules/assembly/igniter.dm
@@ -34,4 +34,7 @@
/obj/item/device/assembly/igniter/attack_self(mob/user as mob)
activate()
add_fingerprint(user)
- return
\ No newline at end of file
+ return
+
+/obj/item/device/assembly/igniter/is_hot()
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
index ecc0f61d83..ad6301f985 100644
--- a/code/modules/materials/material_recipes.dm
+++ b/code/modules/materials/material_recipes.dm
@@ -140,7 +140,8 @@
recipes += new/datum/stack_recipe("coilgun stock", /obj/item/weapon/coilgun_assembly, 5)
/material/wood/log/generate_recipes()
- return // Feel free to add log-only recipes here later if desired.
+ recipes = list()
+ recipes += new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 5, time = 50, supplied_material = "[name]")
/material/cardboard/generate_recipes()
..()
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index f66d2425c6..c662141fbd 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -214,6 +214,7 @@
/obj/item/stack/material/log/sif
name = "alien log"
+ default_type = "alien log"
color = "#0099cc"
/obj/item/stack/material/log/attackby(var/obj/item/W, var/mob/user)
diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm
index ebb6fc56f3..6ad4a6487d 100644
--- a/code/modules/materials/materials.dm
+++ b/code/modules/materials/materials.dm
@@ -697,13 +697,14 @@ var/list/name_to_material
name = "log"
icon_base = "log"
stack_type = /obj/item/stack/material/log
- sheet_singular_name = "log"
- sheet_plural_name = "logs"
+ sheet_singular_name = null
+ sheet_plural_name = "pile"
/material/wood/log/sif
name = "alien log"
icon_colour = "#0099cc" // Cyan-ish
stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
+ stack_type = /obj/item/stack/material/log/sif
/material/wood/holographic
name = "holowood"
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 8f8974473a..6bc3136a73 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -1258,7 +1258,7 @@ var/global/list/damage_icon_parts = list()
/mob/living/carbon/human/update_fire(var/update_icons=1)
overlays_standing[FIRE_LAYER] = null
if(on_fire)
- overlays_standing[FIRE_LAYER] = image("icon"='icons/mob/OnFire.dmi', "icon_state" = get_fire_icon_state(), "layer"=FIRE_LAYER)
+ overlays_standing[FIRE_LAYER] = image("icon"='icons/mob/OnFire.dmi', "icon_state" = get_fire_icon_state())
if(update_icons) update_icons()
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 29bb1680b4..ee7ac035c6 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -202,7 +202,7 @@
return TRUE
else if(on_fire)
- set_light(light_range + 3, round(fire_stacks), l_color = "#FF9933")
+ set_light(min(round(fire_stacks), 3), round(fire_stacks), l_color = "#FF9933")
return TRUE
else
diff --git a/icons/obj/flora/sifflora.dmi b/icons/obj/flora/sifflora.dmi
new file mode 100644
index 0000000000..213f1f5a8d
Binary files /dev/null and b/icons/obj/flora/sifflora.dmi differ
diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi
index 3b4604cdfd..d79ceab8c3 100644
Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ
diff --git a/polaris.dme b/polaris.dme
index 3bc20a7499..f142f442df 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -1001,6 +1001,7 @@
#include "code\game\objects\structures\alien_props.dm"
#include "code\game\objects\structures\barsign.dm"
#include "code\game\objects\structures\bedsheet_bin.dm"
+#include "code\game\objects\structures\bonfire.dm"
#include "code\game\objects\structures\catwalk.dm"
#include "code\game\objects\structures\coathanger.dm"
#include "code\game\objects\structures\curtains.dm"