diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 8f8afa9b..c86debe7 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -223,6 +223,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("sauna oven", /obj/structure/sauna_oven, 30, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 10, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("ore box", /obj/structure/ore_box, 4, time = 50, one_per_turf = TRUE, on_floor = TRUE),\
@@ -900,4 +901,4 @@ GLOBAL_LIST_INIT(plaswood_recipes, list ( \
return ..()
/obj/item/stack/sheet/mineral/plaswood/fifty
- amount = 50
\ No newline at end of file
+ amount = 50
diff --git a/hyperstation/code/game/objects/structures/sauna_oven.dm b/hyperstation/code/game/objects/structures/sauna_oven.dm
new file mode 100644
index 00000000..c1186178
--- /dev/null
+++ b/hyperstation/code/game/objects/structures/sauna_oven.dm
@@ -0,0 +1,117 @@
+#define SAUNA_H2O_TEMP T20C + 20
+#define SAUNA_LOG_FUEL 150
+#define SAUNA_PAPER_FUEL 5
+#define SAUNA_MAXIMUM_FUEL 3000
+#define SAUNA_WATER_PER_WATER_UNIT 5
+
+/obj/structure/sauna_oven
+ name = "sauna oven"
+ desc = "A modest sauna oven with rocks. Add some fuel, pour some water and enjoy the moment."
+ icon = 'hyperstation/icons/obj/structures/sauna_oven.dmi'
+ icon_state = "sauna_oven"
+ density = TRUE
+ anchored = TRUE
+ resistance_flags = FIRE_PROOF
+ var/lit = FALSE
+ var/fuel_amount = 0
+ var/water_amount = 0
+
+/obj/structure/sauna_oven/examine(mob/user)
+ . = ..()
+ . += "The rocks are [water_amount ? "moist" : "dry"]."
+ . += "There's [fuel_amount ? "some fuel" : "no fuel"] in the oven."
+
+/obj/structure/sauna_oven/Destroy()
+ if(lit)
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/structure/sauna_oven/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
+ if(lit)
+ lit = FALSE
+ STOP_PROCESSING(SSobj, src)
+ user.visible_message("[user] turns on [src].", "You turn on [src].")
+ else if (fuel_amount)
+ lit = TRUE
+ START_PROCESSING(SSobj, src)
+ user.visible_message("[user] turns off [src].", "You turn off [src].")
+ update_icon()
+
+/obj/structure/sauna_oven/update_overlays()
+ . = ..()
+ if(lit)
+ . += "sauna_oven_on_overlay"
+
+/obj/structure/sauna_oven/update_icon()
+ ..()
+ icon_state = "[lit ? "sauna_oven_on" : initial(icon_state)]"
+
+/obj/structure/sauna_oven/attackby(obj/item/T, mob/user)
+ if(T.tool_behaviour == TOOL_WRENCH)
+ to_chat(user, "You begin to deconstruct [src].")
+ if(T.use_tool(src, user, 60, volume=50))
+ to_chat(user, "You successfully deconstructed [src].")
+ new /obj/item/stack/sheet/mineral/wood(get_turf(src), 30)
+ qdel(src)
+
+ else if(istype(T, /obj/item/reagent_containers))
+ var/obj/item/reagent_containers/reagent_container = T
+ if(!reagent_container.is_open_container())
+ return ..()
+ if(reagent_container.reagents.has_reagent(/datum/reagent/water))
+ reagent_container.reagents.remove_reagent(/datum/reagent/water, 5)
+ user.visible_message("[user] pours some \
+ water into [src].", "You pour \
+ some water to [src].")
+ water_amount += 5 * SAUNA_WATER_PER_WATER_UNIT
+ else
+ to_chat(user, "There's no water in [reagent_container]")
+
+ else if(istype(T, /obj/item/stack/sheet/mineral/wood))
+ var/obj/item/stack/sheet/mineral/wood/wood = T
+ if(fuel_amount > SAUNA_MAXIMUM_FUEL)
+ to_chat(user, "You can't fit any more of [T] in [src]!")
+ return FALSE
+ fuel_amount += SAUNA_LOG_FUEL * wood.amount
+ wood.use(wood.amount)
+ user.visible_message("[user] tosses some \
+ wood into [src].", "You add \
+ some fuel to [src].")
+ return TRUE
+ else if(istype(T, /obj/item/paper_bin))
+ var/obj/item/paper_bin/paper_bin = T
+ user.visible_message("[user] throws [T] into \
+ [src].", "You add [T] to [src].\
+ ")
+ fuel_amount += SAUNA_PAPER_FUEL * paper_bin.total_paper
+ qdel(paper_bin)
+ return TRUE
+ else if(istype(T, /obj/item/paper))
+ user.visible_message("[user] throws [T] into \
+ [src].", "You throw [T] into [src].\
+ ")
+ fuel_amount += SAUNA_PAPER_FUEL
+ qdel(T)
+ return TRUE
+ return ..()
+
+/obj/structure/sauna_oven/process()
+ if(water_amount)
+ water_amount--
+ var/turf/pos = get_turf(src)
+ if(pos)
+ pos.atmos_spawn_air("water_vapor=10;TEMP=[SAUNA_H2O_TEMP]")
+ fuel_amount--
+ if(fuel_amount <= 0)
+ lit = FALSE
+ STOP_PROCESSING(SSobj, src)
+ update_icon()
+
+#undef SAUNA_H2O_TEMP
+#undef SAUNA_LOG_FUEL
+#undef SAUNA_PAPER_FUEL
+#undef SAUNA_MAXIMUM_FUEL
+#undef SAUNA_WATER_PER_WATER_UNIT
diff --git a/hyperstation/icons/obj/structures/sauna_oven.dmi b/hyperstation/icons/obj/structures/sauna_oven.dmi
new file mode 100644
index 00000000..fb0871ca
Binary files /dev/null and b/hyperstation/icons/obj/structures/sauna_oven.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 508e8ff7..115184bd 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -3072,6 +3072,7 @@
#include "hyperstation\code\game\objects\items\cosmetics.dm"
#include "hyperstation\code\game\objects\items\storage\big_bag.dm"
#include "hyperstation\code\game\objects\structures\ghost_role_spawners.dm"
+#include "hyperstation\code\game\objects\structures\sauna_oven.dm"
#include "hyperstation\code\gamemode\traitor_lewd.dm"
#include "hyperstation\code\gamemode\traitor_thief.dm"
#include "hyperstation\code\gamemode\werewolf\werewolf.dm"