diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index bc93d20bb5..17f4121a76 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -198,3 +198,9 @@
throw_range = 20
flags = 0
no_variants = FALSE
+
+/obj/item/stack/tile/roofing
+ name = "roofing"
+ singular_name = "roofing"
+ desc = "A section of roofing material. You can use it to repair the ceiling, or expand it."
+ icon_state = "techtile_grid"
\ No newline at end of file
diff --git a/code/game/turfs/simulated/floor_attackby.dm b/code/game/turfs/simulated/floor_attackby.dm
index 91371e7beb..940e2df548 100644
--- a/code/game/turfs/simulated/floor_attackby.dm
+++ b/code/game/turfs/simulated/floor_attackby.dm
@@ -9,6 +9,51 @@
attack_tile(C, L) // Be on help intent if you want to decon something.
return
+ if(istype(C, /obj/item/stack/tile/roofing))
+ var/expended_tile = FALSE // To track the case. If a ceiling is built in a multiz zlevel, it also necessarily roofs it against weather
+ var/turf/T = GetAbove(src)
+ var/obj/item/stack/tile/roofing/R = C
+
+ // Patch holes in the ceiling
+ if(T)
+ if(istype(T, /turf/simulated/open) || istype(T, /turf/space))
+ // Must be build adjacent to an existing floor/wall, no floating floors
+ var/list/cardinalTurfs = list() // Up a Z level
+ for(var/dir in cardinal)
+ var/turf/B = get_step(T, dir)
+ if(B)
+ cardinalTurfs += B
+
+ var/turf/simulated/A = locate(/turf/simulated/floor) in cardinalTurfs
+ if(!A)
+ A = locate(/turf/simulated/wall) in cardinalTurfs
+ if(!A)
+ to_chat(user, "There's nothing to attach the ceiling to!")
+ return
+
+ if(R.use(1)) // Cost of roofing tiles is 1:1 with cost to place lattice and plating
+ T.ReplaceWithLattice()
+ T.ChangeTurf(/turf/simulated/floor)
+ playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
+ user.visible_message("[user] patches a hole in the ceiling.", "You patch a hole in the ceiling.")
+ expended_tile = TRUE
+ else
+ to_chat(user, "There aren't any holes in the ceiling to patch here.")
+ return
+
+ // Create a ceiling to shield from the weather
+ if(src.outdoors)
+ for(var/dir in cardinal)
+ var/turf/A = get_step(src, dir)
+ if(A && !A.outdoors)
+ if(expended_tile || R.use(1))
+ src.outdoors = FALSE
+ SSplanets.unallocateTurf(src)
+ playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
+ user.visible_message("[user] roofs a tile, shielding it from the elements.", "You roof this tile, shielding it from the elements.")
+ break
+ return
+
if(flooring)
if(istype(C, /obj/item/weapon))
try_deconstruct_tile(C, user)
diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm
index 1eaca16e76..4d87e2e87e 100644
--- a/code/game/turfs/simulated/wall_attacks.dm
+++ b/code/game/turfs/simulated/wall_attacks.dm
@@ -84,16 +84,16 @@
if(rotting)
if(reinf_material)
- user << "\The [reinf_material.display_name] feels porous and crumbly."
+ to_chat(user, "\The [reinf_material.display_name] feels porous and crumbly.")
else
- user << "\The [material.display_name] crumbles under your touch!"
+ to_chat(user, "\The [material.display_name] crumbles under your touch!")
dismantle_wall()
return 1
if(..()) return 1
if(!can_open)
- user << "You push the wall, but nothing happens."
+ to_chat(user, "You push the wall, but nothing happens.")
playsound(src, 'sound/weapons/Genhit.ogg', 25, 1)
else
toggle_open(user)
@@ -138,28 +138,58 @@
user.setClickCooldown(user.get_attack_speed(W))
if (!user.)
- user << "You don't have the dexterity to do this!"
+ to_chat(user, "You don't have the dexterity to do this!")
return
//get the user's location
- if(!istype(user.loc, /turf)) return //can't do this stuff whilst inside objects and such
+ if(!istype(user.loc, /turf))
+ return //can't do this stuff whilst inside objects and such
if(W)
radiate()
if(is_hot(W))
burn(is_hot(W))
+ if(istype(W, /obj/item/stack/tile/roofing))
+ var/expended_tile = FALSE // To track the case. If a ceiling is built in a multiz zlevel, it also necessarily roofs it against weather
+ var/turf/T = GetAbove(src)
+ var/obj/item/stack/tile/roofing/R = W
+
+ // Place plating over a wall
+ if(T)
+ if(istype(T, /turf/simulated/open) || istype(T, /turf/space))
+ if(R.use(1)) // Cost of roofing tiles is 1:1 with cost to place lattice and plating
+ T.ReplaceWithLattice()
+ T.ChangeTurf(/turf/simulated/floor)
+ playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
+ user.visible_message("[user] patches a hole in the ceiling.", "You patch a hole in the ceiling.")
+ expended_tile = TRUE
+ else
+ to_chat(user, "There aren't any holes in the ceiling to patch here.")
+ return
+
+ // Create a ceiling to shield from the weather
+ if(outdoors)
+ if(expended_tile || R.use(1)) // Don't need to check adjacent turfs for a wall, we're building on one
+ outdoors = FALSE
+ SSplanets.unallocateTurf(src)
+ if(!expended_tile) // Would've already played a sound
+ playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
+ user.visible_message("[user] roofs \the [src], shielding it from the elements.", "You roof \the [src] tile, shielding it from the elements.")
+ return
+
+
if(locate(/obj/effect/overlay/wallrot) in src)
if(istype(W, /obj/item/weapon/weldingtool) )
var/obj/item/weapon/weldingtool/WT = W
if( WT.remove_fuel(0,user) )
- user << "You burn away the fungi with \the [WT]."
+ to_chat(user, "You burn away the fungi with \the [WT].")
playsound(src, WT.usesound, 10, 1)
for(var/obj/effect/overlay/wallrot/WR in src)
qdel(WR)
return
else if(!is_sharp(W) && W.force >= 10 || W.force >= 20)
- user << "\The [src] crumbles away under the force of your [W.name]."
+ to_chat(user, "\The [src] crumbles away under the force of your [W.name].")
src.dismantle_wall(1)
return
@@ -179,7 +209,7 @@
var/obj/item/weapon/melee/energy/blade/EB = W
EB.spark_system.start()
- user << "You slash \the [src] with \the [EB]; the thermite ignites!"
+ to_chat(user, "You slash \the [src] with \the [EB]; the thermite ignites!")
playsound(src, "sparks", 50, 1)
playsound(src, 'sound/weapons/blade1.ogg', 50, 1)
@@ -196,13 +226,13 @@
return
if(WT.remove_fuel(0,user))
- user << "You start repairing the damage to [src]."
+ to_chat(user, "You start repairing the damage to [src].")
playsound(src.loc, WT.usesound, 100, 1)
if(do_after(user, max(5, damage / 5) * WT.toolspeed) && WT && WT.isOn())
- user << "You finish repairing the damage to [src]."
+ to_chat(user, "You finish repairing the damage to [src].")
take_damage(-damage)
else
- user << "You need more welding fuel to complete this task."
+ to_chat(user, "You need more welding fuel to complete this task.")
return
user.update_examine_panel(src)
return
@@ -219,7 +249,7 @@
if(!WT.isOn())
return
if(!WT.remove_fuel(0,user))
- user << "You need more welding fuel to complete this task."
+ to_chat(user, "You need more welding fuel to complete this task.")
return
dismantle_verb = "cutting"
dismantle_sound = W.usesound
@@ -236,7 +266,7 @@
if(dismantle_verb)
- user << "You begin [dismantle_verb] through the outer plating."
+ to_chat(user, "You begin [dismantle_verb] through the outer plating.")
if(dismantle_sound)
playsound(src, dismantle_sound, 100, 1)
@@ -246,7 +276,7 @@
if(!do_after(user,cut_delay * W.toolspeed))
return
- user << "You remove the outer plating."
+ to_chat(user, "You remove the outer plating.")
dismantle_wall()
user.visible_message("The wall was torn open by [user]!")
return
@@ -259,24 +289,24 @@
playsound(src, W.usesound, 100, 1)
construction_stage = 5
user.update_examine_panel(src)
- user << "You cut through the outer grille."
+ to_chat(user, "You cut through the outer grille.")
update_icon()
return
if(5)
if (istype(W, /obj/item/weapon/screwdriver))
- user << "You begin removing the support lines."
+ to_chat(user, "You begin removing the support lines.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,40 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 5)
return
construction_stage = 4
user.update_examine_panel(src)
update_icon()
- user << "You unscrew the support lines."
+ to_chat(user, "You unscrew the support lines.")
return
else if (istype(W, /obj/item/weapon/wirecutters))
construction_stage = 6
user.update_examine_panel(src)
- user << "You mend the outer grille."
+ to_chat(user, "You mend the outer grille.")
playsound(src, W.usesound, 100, 1)
update_icon()
return
@@ -289,51 +319,51 @@
if(WT.remove_fuel(0,user))
cut_cover=1
else
- user << "You need more welding fuel to complete this task."
+ to_chat(user, "You need more welding fuel to complete this task.")
return
else if (istype(W, /obj/item/weapon/pickaxe/plasmacutter))
cut_cover = 1
if(cut_cover)
- user << "You begin slicing through the metal cover."
+ to_chat(user, "You begin slicing through the metal cover.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user, 60 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 4)
return
construction_stage = 3
user.update_examine_panel(src)
update_icon()
- user << "You press firmly on the cover, dislodging it."
+ to_chat(user, "You press firmly on the cover, dislodging it.")
return
else if (istype(W, /obj/item/weapon/screwdriver))
- user << "You begin screwing down the support lines."
+ to_chat(user, "You begin screwing down the support lines.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,40 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 4)
return
construction_stage = 5
user.update_examine_panel(src)
update_icon()
- user << "You screw down the support lines."
+ to_chat(user, "You screw down the support lines.")
return
if(3)
if (istype(W, /obj/item/weapon/crowbar))
- user << "You struggle to pry off the cover."
+ to_chat(user, "You struggle to pry off the cover.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,100 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 3)
return
construction_stage = 2
user.update_examine_panel(src)
update_icon()
- user << "You pry off the cover."
+ to_chat(user, "You pry off the cover.")
return
if(2)
if (istype(W, /obj/item/weapon/wrench))
- user << "You start loosening the anchoring bolts which secure the support rods to their frame."
+ to_chat(user, "You start loosening the anchoring bolts which secure the support rods to their frame.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,40 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 2)
return
construction_stage = 1
user.update_examine_panel(src)
update_icon()
- user << "You remove the bolts anchoring the support rods."
+ to_chat(user, "You remove the bolts anchoring the support rods.")
return
if(1)
var/cut_cover
@@ -342,28 +372,28 @@
if( WT.remove_fuel(0,user) )
cut_cover=1
else
- user << "You need more welding fuel to complete this task."
+ to_chat(user, "You need more welding fuel to complete this task.")
return
else if(istype(W, /obj/item/weapon/pickaxe/plasmacutter))
cut_cover = 1
if(cut_cover)
- user << "You begin slicing through the support rods."
+ to_chat(user, "You begin slicing through the support rods.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,70 * W.toolspeed) || !istype(src, /turf/simulated/wall) || construction_stage != 1)
return
construction_stage = 0
user.update_examine_panel(src)
update_icon()
- user << "The slice through the support rods."
+ to_chat(user, "The slice through the support rods.")
return
if(0)
if(istype(W, /obj/item/weapon/crowbar))
- user << "You struggle to pry off the outer sheath."
+ to_chat(user, "You struggle to pry off the outer sheath.")
playsound(src, W.usesound, 100, 1)
if(!do_after(user,100 * W.toolspeed) || !istype(src, /turf/simulated/wall) || !user || !W || !T )
return
if(user.loc == T && user.get_active_hand() == W )
- user << "You pry off the outer sheath."
+ to_chat(user, "You pry off the outer sheath.")
dismantle_wall()
return
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index 13368bb7ed..1c700eec85 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -33,18 +33,18 @@
/turf/space/attackby(obj/item/C as obj, mob/user as mob)
- if (istype(C, /obj/item/stack/rods))
+ if(istype(C, /obj/item/stack/rods))
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
if(L)
return
var/obj/item/stack/rods/R = C
if (R.use(1))
- user << "Constructing support lattice ..."
+ to_chat(user, "Constructing support lattice ...")
playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
ReplaceWithLattice()
return
- if (istype(C, /obj/item/stack/tile/floor))
+ if(istype(C, /obj/item/stack/tile/floor))
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
if(L)
var/obj/item/stack/tile/floor/S = C
@@ -56,7 +56,33 @@
ChangeTurf(/turf/simulated/floor/airless)
return
else
- user << "The plating is going to need some support."
+ to_chat(user, "The plating is going to need some support.")
+
+ if(istype(C, /obj/item/stack/tile/roofing))
+ var/turf/T = GetAbove(src)
+ var/obj/item/stack/tile/roofing/R = C
+
+ // Patch holes in the ceiling
+ if(T)
+ if(istype(T, /turf/simulated/open) || istype(T, /turf/space))
+ // Must be build adjacent to an existing floor/wall, no floating floors
+ var/turf/simulated/A = locate(/turf/simulated/floor) in T.CardinalTurfs()
+ if(!A)
+ A = locate(/turf/simulated/wall) in T.CardinalTurfs()
+ if(!A)
+ to_chat(user, "There's nothing to attach the ceiling to!")
+ return
+
+ if(R.use(1)) // Cost of roofing tiles is 1:1 with cost to place lattice and plating
+ T.ReplaceWithLattice()
+ T.ChangeTurf(/turf/simulated/floor)
+ playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
+ user.visible_message("[user] expands the ceiling.", "You expand the ceiling.")
+ else
+ to_chat(user, "There aren't any holes in the ceiling to patch here.")
+ return
+ // Space shouldn't have weather of the sort planets with atmospheres do.
+ // If that's changed, then you'll want to swipe the rest of the roofing code from code/game/turfs/simulated/floor_attackby.dm
return
@@ -64,7 +90,7 @@
/turf/space/Entered(atom/movable/A as mob|obj)
if(movement_disabled)
- usr << "Movement is admin-disabled." //This is to identify lag problems
+ to_chat(usr, "Movement is admin-disabled.") //This is to identify lag problems
return
..()
if ((!(A) || src != A.loc)) return
diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm
index b355ec6328..1d77686661 100644
--- a/code/game/turfs/turf_changing.dm
+++ b/code/game/turfs/turf_changing.dm
@@ -40,6 +40,7 @@
var/old_affecting_lights = affecting_lights
var/old_lighting_overlay = lighting_overlay
var/old_corners = corners
+ var/old_outdoors = outdoors
//world << "Replacing [src.type] with [N]"
@@ -108,3 +109,4 @@
lighting_build_overlay()
else
lighting_clear_overlay()
+ outdoors = old_outdoors
\ No newline at end of file
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
index 6e75d97a0d..232ef46e3e 100644
--- a/code/modules/materials/material_recipes.dm
+++ b/code/modules/materials/material_recipes.dm
@@ -53,6 +53,7 @@
recipes += new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1)
recipes += new/datum/stack_recipe("cannon frame", /obj/item/weapon/cannonframe, 10, time = 15, one_per_turf = 0, on_floor = 0)
recipes += new/datum/stack_recipe("regular floor tile", /obj/item/stack/tile/floor, 1, 4, 20)
+ recipes += new/datum/stack_recipe("roofing tile", /obj/item/stack/tile/roofing, 3, 4, 20)
recipes += new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60)
recipes += new/datum/stack_recipe("frame", /obj/item/frame, 5, time = 25, one_per_turf = 1, on_floor = 1)
recipes += new/datum/stack_recipe("mirror frame", /obj/item/frame/mirror, 1, time = 5, one_per_turf = 0, on_floor = 1)
diff --git a/html/changelogs/Atermonera - Ceilings.yml b/html/changelogs/Atermonera - Ceilings.yml
new file mode 100644
index 0000000000..760df592f5
--- /dev/null
+++ b/html/changelogs/Atermonera - Ceilings.yml
@@ -0,0 +1,7 @@
+author: Atermonera
+delete-after: True
+changes:
+ - rscadd: "Steel sheets can be used to construct Roofing Tiles"
+ - rscadd: "Roofing tiles can be used on tiles under open spaces or space tiles in multiZ maps to place a lattice and plating on the space above"
+ - rscadd: "Roofing tiles can be used on outdoor turfs to make them indoors"
+ - rscadd: "Both functions work together on multiZ maps with outdoor turfs, only one roofing tile is used per tile roofed."