diff --git a/code/__defines/materials.dm b/code/__defines/materials.dm
index 12a671b464..6963adae5d 100644
--- a/code/__defines/materials.dm
+++ b/code/__defines/materials.dm
@@ -3,6 +3,9 @@
#define MAT_STEEL "steel"
#define MAT_PLASTIC "plastic"
#define MAT_GLASS "glass"
+#define MAT_RGLASS "rglass"
+#define MAT_PGLASS "borosilicate glass"
+#define MAT_RPGLASS "reinforced borosilicate glass"
#define MAT_SILVER "silver"
#define MAT_GOLD "gold"
#define MAT_URANIUM "uranium"
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 8480b901a0..17d5689784 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -949,4 +949,42 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
/// How are you described if at all when in pockets (or other 'usually not visible' places)
/obj/item/proc/pocket_description(mob/haver, mob/examiner)
return null // most things are hidden
-
\ No newline at end of file
+
+#define CELLS 8 //Amount of cells per row/column in grid
+#define CELLSIZE (world.icon_size/CELLS) //Size of a cell in pixels
+/*
+Automatic alignment of items to an invisible grid, defined by CELLS and CELLSIZE.
+Since the grid will be shifted to own a cell that is perfectly centered on the turf, we end up with two 'cell halves'
+on edges of each row/column.
+Each item defines a center_of_mass, which is the pixel of a sprite where its projected center of mass toward a turf
+surface can be assumed. For a piece of paper, this will be in its center. For a bottle, it will be (near) the bottom
+of the sprite.
+auto_align() will then place the sprite so the defined center_of_mass is at the bottom left corner of the grid cell
+closest to where the cursor has clicked on.
+Note: This proc can be overwritten to allow for different types of auto-alignment.
+*/
+
+/obj/item/var/list/center_of_mass = list("x" = 16,"y" = 16)
+
+/proc/auto_align(obj/item/W, click_parameters)
+ if(!W.center_of_mass)
+ W.randpixel_xy()
+ return
+
+ if(!click_parameters)
+ return
+
+ var/list/mouse_control = params2list(click_parameters)
+
+ var/mouse_x = text2num(mouse_control["icon-x"])
+ var/mouse_y = text2num(mouse_control["icon-y"])
+
+ if(isnum(mouse_x) && isnum(mouse_y))
+ var/cell_x = max(0, min(CELLS-1, round(mouse_x/CELLSIZE)))
+ var/cell_y = max(0, min(CELLS-1, round(mouse_y/CELLSIZE)))
+
+ W.pixel_x = (CELLSIZE * (0.5 + cell_x)) - W.center_of_mass["x"]
+ W.pixel_y = (CELLSIZE * (0.5 + cell_y)) - W.center_of_mass["y"]
+
+#undef CELLS
+#undef CELLSIZE
\ No newline at end of file
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index 9b006ee27f..825459b8f4 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -15,6 +15,7 @@
var/datum/material/reinf_material
var/reinforcing = 0
var/applies_material_colour = 1
+ var/wall_type = /turf/simulated/wall
/obj/structure/girder/New(var/newloc, var/material_key)
..(newloc)
@@ -249,7 +250,7 @@
wall_fake = 1
var/turf/Tsrc = get_turf(src)
- Tsrc.ChangeTurf(/turf/simulated/wall)
+ Tsrc.ChangeTurf(wall_type)
var/turf/simulated/wall/T = get_turf(src)
T.set_material(M, reinf_material, girder_material)
if(wall_fake)
@@ -397,7 +398,7 @@
if(RCD_FLOORWALL)
to_chat(user, span("notice", "You finish a wall."))
// This is mostly the same as using on a floor. The girder's material is preserved, however.
- T.ChangeTurf(/turf/simulated/wall)
+ T.ChangeTurf(wall_type)
var/turf/simulated/wall/new_T = get_turf(src) // Ref to the wall we just built.
// Apparently set_material(...) for walls requires refs to the material singletons and not strings.
// This is different from how other material objects with their own set_material(...) do it, but whatever.
@@ -412,3 +413,9 @@
qdel(src)
return TRUE
+/obj/structure/girder/bay
+ wall_type = /turf/simulated/wall/bay
+
+/obj/structure/girder/eris
+ wall_type = /turf/simulated/wall/eris
+
\ No newline at end of file
diff --git a/code/game/objects/structures/wall_frame.dm b/code/game/objects/structures/wall_frame.dm
new file mode 100644
index 0000000000..863dd997a2
--- /dev/null
+++ b/code/game/objects/structures/wall_frame.dm
@@ -0,0 +1,623 @@
+// Basically see-through walls. Used for windows
+// If nothing has been built on the low wall, you can climb on it
+
+/obj/structure/low_wall
+ name = "low wall"
+ desc = "A low wall section which serves as the base of windows, amongst other things."
+ layer = TURF_LAYER
+ icon = null
+ icon_state = "frame"
+
+ //atom_flags = ATOM_FLAG_NO_TEMP_CHANGE | ATOM_FLAG_CLIMBABLE | ATOM_FLAG_CAN_BE_PAINTED | ATOM_FLAG_ADJACENT_EXCEPTION
+ anchored = TRUE
+ density = TRUE
+ climbable = TRUE
+ throwpass = 1
+ layer = TABLE_LAYER
+
+ var/icon/frame_masks = 'icons/obj/wall_frame_bay.dmi'
+
+ var/health = 100
+ var/stripe_color
+ //rad_resistance_modifier = 0.5
+
+ // blend_objects defined on subtypes
+ noblend_objects = list(/obj/machinery/door/window)
+
+ var/default_material = DEFAULT_WALL_MATERIAL
+ var/datum/material/material
+ var/grille_type
+
+/obj/structure/low_wall/Initialize(var/mapload, var/materialtype)
+ . = ..()
+ icon_state = "blank"
+ var/turf/T = loc
+ if(!isturf(T) || T.density || T.opacity)
+ warning("[src] on invalid turf [T] at [x],[y],[z]")
+ return INITIALIZE_HINT_QDEL
+
+ if(!materialtype)
+ materialtype = default_material
+
+ material = get_material_by_name(materialtype)
+
+ health = material.integrity
+
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/structure/low_wall/LateInitialize()
+ . = ..()
+ update_connections(1)
+ update_icon()
+
+/obj/structure/low_wall/Destroy()
+ var/turf/location = loc
+ . = ..()
+ for(var/obj/structure/low_wall/W in orange(1, location))
+ W.update_connections()
+ W.update_icon()
+
+
+/obj/structure/low_wall/examine(mob/user)
+ . = ..()
+
+ if(health == material.integrity)
+ to_chat(user, "It seems to be in fine condition.")
+ else
+ var/dam = health / material.integrity
+ if(dam <= 0.3)
+ to_chat(user, "It's got a few dents and scratches.")
+ else if(dam <= 0.7)
+ to_chat(user, "A few pieces of panelling have fallen off.")
+ else
+ to_chat(user, "It's nearly falling to pieces.")
+
+/obj/structure/low_wall/attackby(var/obj/item/W, var/mob/user, var/hit_modifier, var/click_parameters)
+ src.add_fingerprint(user)
+
+ // Making grilles (only works on Bay ones currently)
+ if(istype(W, /obj/item/stack/rods))
+ handle_rod_use(user, W)
+ return
+
+ // Making windows, different per subtype
+ else if(istype(W, /obj/item/stack/material/glass))
+ handle_glass_use(user, W)
+ return
+
+ // Dismantling the half wall
+ if(W.is_wrench())
+ for(var/obj/structure/S in loc)
+ if(istype(S, /obj/structure/window))
+ to_chat(user, "There is still a window on the low wall!")
+ return
+ else if(istype(S, /obj/structure/grille))
+ to_chat(user, "There is still a grille on the low wall!")
+ return
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1)
+ to_chat(user, "Now disassembling the low wall...")
+ if(do_after(user, 40, src))
+ to_chat(user, "You dissasembled the low wall!")
+ dismantle()
+
+ // Handle placing things
+ if(isrobot(user))
+ return
+
+ if(W.loc != user) // This should stop mounted modules ending up outside the module.
+ return
+
+ if(can_place_items() && user.unEquip(W, 0, src.loc) && user.is_preference_enabled(/datum/client_preference/precision_placement))
+ auto_align(W, click_parameters)
+ return 1
+
+ return ..()
+
+/obj/structure/low_wall/proc/can_place_items()
+ for(var/obj/structure/S in loc)
+ if(S == src)
+ continue
+ if(S.density)
+ return FALSE
+ return TRUE
+
+/obj/structure/low_wall/MouseDrop_T(obj/O as obj, mob/user as mob)
+ if(istype(O, /obj/structure/window))
+ var/obj/structure/window/W = O
+ if(Adjacent(W) && !W.anchored)
+ to_chat("You hoist [W] up onto [src].")
+ W.forceMove(loc)
+ return
+ if ((!( istype(O, /obj/item/weapon) ) || user.get_active_hand() != O))
+ return ..()
+ if(isrobot(user))
+ return
+ if(can_place_items())
+ user.unEquip(O, 0, src.loc)
+
+/obj/structure/low_wall/proc/handle_rod_use(mob/user, obj/item/stack/rods/R)
+ if(!grille_type)
+ to_chat(user, "This type of wall frame doesn't support grilles.")
+ return
+ for(var/obj/structure/window/WINDOW in loc)
+ if(WINDOW.dir == get_dir(src, user))
+ to_chat(user, "There is a window in the way.")
+ return
+ if(R.get_amount() < 2)
+ to_chat(user, "You need at least two rods to do this.")
+ return
+ to_chat(user, "Assembling grille...")
+ if(!do_after(user, 1 SECONDS, R, exclusive = TASK_ALL_EXCLUSIVE))
+ return
+ if(!R.use(2))
+ return
+ new grille_type(loc)
+ return
+
+/obj/structure/low_wall/proc/handle_glass_use(mob/user, obj/item/stack/material/glass/G)
+ var/window_type = get_window_build_type(user, G)
+ if(!window_type)
+ to_chat(user, "You can't build that type of window on this type of low wall.")
+ return
+ for(var/obj/structure/window/WINDOW in loc)
+ if(WINDOW.dir == get_dir(src, user))
+ to_chat(user, "There is already a window here.")
+ return
+ if(G.get_amount() < 4)
+ to_chat(user, "You need at least four sheets of glass to do this.")
+ return
+ to_chat(user, "Assembling window...")
+ if(!do_after(user, 4 SECONDS, G, exclusive = TASK_ALL_EXCLUSIVE))
+ return
+ if(!G.use(2))
+ return
+ new window_type(loc, null, TRUE)
+ return
+
+/obj/structure/low_wall/proc/get_window_build_type(mob/user, obj/item/stack/material/glass/G)
+ return null
+
+/obj/structure/low_wall/CanPass(atom/movable/mover, turf/target)
+ if(istype(mover,/obj/item/projectile))
+ return TRUE
+ if(istype(mover) && mover.checkpass(PASSTABLE))
+ return TRUE
+ return FALSE
+
+// Bay's version
+/obj/structure/low_wall/bay/update_icon()
+ cut_overlays()
+
+ var/image/I
+ var/main_color = material.icon_colour
+ for(var/i = 1 to 4)
+ if(other_connections[i] != "0")
+ I = image(icon, "frame_other[other_connections[i]]", dir = 1<<(i-1))
+ I.color = main_color
+ else
+ I = image(icon, "frame[connections[i]]", dir = 1<<(i-1))
+ I.color = main_color
+ add_overlay(I)
+
+ if(stripe_color)
+ for(var/i = 1 to 4)
+ if(other_connections[i] != "0")
+ I = image(icon, "stripe_other[other_connections[i]]", dir = 1<<(i-1))
+ else
+ I = image(icon, "stripe[connections[i]]", dir = 1<<(i-1))
+ I.color = stripe_color
+ add_overlay(I)
+
+// Eris's version
+/obj/structure/low_wall/eris/update_icon()
+ cut_overlays()
+
+ var/image/I
+ var/main_color = material.icon_colour
+ for(var/i = 1 to 4)
+ I = image(icon, "frame[connections[i]]", dir = 1<<(i-1))
+ I.color = main_color
+ add_overlay(I)
+
+ if(other_connections[i] != "0")
+ I = image(icon, "frame_other[other_connections[i]]", dir = 1<<(i-1))
+ I.plane = ABOVE_OBJ_PLANE
+ I.layer = ABOVE_WINDOW_LAYER
+ I.color = main_color
+ add_overlay(I)
+
+/obj/structure/low_wall/bullet_act(var/obj/item/projectile/Proj)
+ var/proj_damage = Proj.get_structure_damage()
+ var/damage = min(proj_damage, 100)
+ take_damage(damage)
+ return
+
+/obj/structure/low_wall/hitby(AM as mob|obj, var/speed)
+ ..()
+ var/tforce = 0
+ if(ismob(AM)) // All mobs have a multiplier and a size according to mob_defines.dm
+ var/mob/I = AM
+ tforce = I.mob_size * (speed/THROWFORCE_SPEED_DIVISOR)
+ else
+ var/obj/O = AM
+ tforce = O.throwforce * (speed/THROWFORCE_SPEED_DIVISOR)
+ if (tforce < 15)
+ return
+ take_damage(tforce)
+
+/obj/structure/low_wall/take_damage(damage)
+ health -= damage
+ if(health <= 0)
+ dismantle()
+
+/obj/structure/low_wall/attack_generic(var/mob/user, var/damage, var/attack_verb)
+ visible_message("[user] [attack_verb] the [src]!")
+ user.do_attack_animation(src)
+ take_damage(damage)
+ return ..()
+
+/obj/structure/low_wall/proc/dismantle()
+ var/stacktype = material?.stack_type
+ if(stacktype)
+ new stacktype(get_turf(src), 3)
+ // If we were violently dismantled
+ for(var/obj/structure/window/W in loc)
+ if(W.anchored)
+ W.shatter()
+ for(var/obj/structure/grille/G in loc)
+ if(G.anchored)
+ G.health = 0
+ G.healthcheck()
+ qdel(src)
+
+/**
+ * The two 'real' types
+ */
+/obj/structure/low_wall/bay
+ icon = 'icons/obj/wall_frame_bay.dmi'
+ grille_type = /obj/structure/grille/bay
+ blend_objects = list(/obj/machinery/door, /turf/simulated/wall/bay)
+
+/obj/structure/low_wall/bay/reinforced
+ default_material = MAT_PLASTEEL
+
+/obj/structure/low_wall/bay/get_window_build_type(mob/user, obj/item/stack/material/glass/G)
+ switch(G.material.name)
+ if(MAT_GLASS)
+ return /obj/structure/window/bay
+ if(MAT_RGLASS)
+ return /obj/structure/window/bay/reinforced
+ if(MAT_PGLASS)
+ return /obj/structure/window/bay/phoronbasic
+ if(MAT_RPGLASS)
+ return /obj/structure/window/bay/phoronreinforced
+
+/obj/structure/low_wall/eris
+ icon = 'icons/obj/wall_frame_eris.dmi'
+ grille_type = null
+ blend_objects = list(/obj/machinery/door, /turf/simulated/wall/eris)
+
+/obj/structure/low_wall/eris/reinforced
+ default_material = MAT_PLASTEEL
+
+/obj/structure/low_wall/eris/get_window_build_type(mob/user, obj/item/stack/material/glass/G)
+ switch(G.material.name)
+ if(MAT_GLASS)
+ return /obj/structure/window/eris
+ if(MAT_RGLASS)
+ return /obj/structure/window/eris/reinforced
+ if(MAT_PGLASS)
+ return /obj/structure/window/eris/phoronbasic
+ if(MAT_RPGLASS)
+ return /obj/structure/window/eris/phoronreinforced
+
+/**
+ * Bay's fancier icon grilles
+ */
+/obj/structure/grille/bay
+ icon = 'icons/obj/bay_grille.dmi'
+ blend_objects = list(/obj/machinery/door, /turf/simulated/wall/bay) // Objects which to blend with
+ noblend_objects = list(/obj/machinery/door/window)
+ color = "#666666"
+
+/obj/structure/grille/bay/Initialize()
+ . = ..()
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/structure/grille/bay/LateInitialize()
+ . = ..()
+ update_connections(1)
+ update_icon()
+
+/obj/structure/grille/bay/Destroy()
+ var/turf/location = loc
+ . = ..()
+ for(var/obj/structure/grille/G in orange(1, location))
+ G.update_connections()
+ G.update_icon()
+
+/obj/structure/grille/bay/update_icon()
+ var/on_frame = locate(/obj/structure/low_wall/bay) in loc
+
+ cut_overlays()
+ if(destroyed)
+ if(on_frame)
+ icon_state = "broke_onframe"
+ else
+ icon_state = "broken"
+ else
+ var/image/I
+ icon_state = ""
+ if(on_frame)
+ for(var/i = 1 to 4)
+ if(other_connections[i] != "0")
+ I = image(icon, "grille_other_onframe[connections[i]]", dir = 1<<(i-1))
+ else
+ I = image(icon, "grille_onframe[connections[i]]", dir = 1<<(i-1))
+ add_overlay(I)
+ else
+ for(var/i = 1 to 4)
+ if(other_connections[i] != "0")
+ I = image(icon, "grille_other[connections[i]]", dir = 1<<(i-1))
+ else
+ I = image(icon, "grille[connections[i]]", dir = 1<<(i-1))
+ add_overlay(I)
+
+/**
+ * The window types for both types of short walls
+ */
+/obj/structure/window/bay
+ icon = 'icons/obj/bay_window.dmi'
+ blend_objects = list(/obj/machinery/door, /turf/simulated/wall/bay)
+ noblend_objects = list(/obj/machinery/door/window)
+ icon_state = "preview_glass"
+ basestate = "window"
+ alpha = 180
+ flags = 0
+ fulltile = TRUE
+ maxhealth = 24
+ glasstype = /obj/item/stack/material/glass
+
+/obj/structure/window/bay/Initialize()
+ . = ..()
+ var/obj/item/stack/material/glass/G = glasstype
+ var/datum/material/M = get_material_by_name(initial(G.default_type))
+ color = M.icon_colour
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/structure/window/bay/LateInitialize()
+ . = ..()
+ icon_state = ""
+ update_icon()
+
+/obj/structure/window/bay/update_icon()
+ cut_overlays()
+ if(!anchored)
+ connections = list("0","0","0","0")
+ other_connections = list("0","0","0","0")
+ else
+ update_connections()
+
+ var/percent_damage = 0 // Used for icon state of damage layer
+ var/damage_alpha = 0 // Used for alpha blending of damage layer
+ if (maxhealth && health < maxhealth)
+ percent_damage = (maxhealth - health) / maxhealth // Percentage of damage received (Not health remaining)
+ percent_damage = round(percent_damage, 0.25) // Round to nearest multiple of 25
+ damage_alpha = 256 * percent_damage - 1
+
+ var/img_dir
+ var/image/I
+ for(var/i = 1 to 4)
+ img_dir = 1<<(i-1)
+ if(other_connections[i] != "0")
+ I = image(icon, "[basestate]_other_onframe[other_connections[i]]", dir = img_dir)
+ I.color = color
+ else
+ I = image(icon, "[basestate]_onframe[connections[i]]", dir = img_dir)
+ I.color = color
+ add_overlay(I)
+
+ if(damage_alpha)
+ var/image/D
+ D = image(icon, "window0_damage", dir = img_dir)
+ D.blend_mode = BLEND_MULTIPLY
+ D.alpha = damage_alpha
+ add_overlay(D)
+
+/obj/structure/window/bay/reinforced
+ name = "reinforced window"
+ desc = "It looks rather strong. Might take a few good hits to shatter it."
+ icon_state = "preview_rglass"
+ basestate = "rwindow"
+ maxhealth = 80
+ reinf = 1
+ maximal_heat = T0C + 750
+ damage_per_fire_tick = 2.0
+ glasstype = /obj/item/stack/material/glass/reinforced
+ force_threshold = 6
+
+/obj/structure/window/bay/phoronbasic
+ name = "phoron window"
+ desc = "A borosilicate alloy window. It seems to be quite strong."
+ icon_state = "preview_phoron"
+ shardtype = /obj/item/weapon/material/shard/phoron
+ glasstype = /obj/item/stack/material/glass/phoronglass
+ maximal_heat = T0C + 2000
+ damage_per_fire_tick = 1.0
+ maxhealth = 40.0
+ force_threshold = 5
+ maxhealth = 80
+
+/obj/structure/window/bay/phoronreinforced
+ name = "reinforced borosilicate window"
+ desc = "A borosilicate alloy window, with rods supporting it. It seems to be very strong."
+ icon_state = "preview_rphoron"
+ basestate = "rwindow"
+ shardtype = /obj/item/weapon/material/shard/phoron
+ glasstype = /obj/item/stack/material/glass/phoronrglass
+ reinf = 1
+ maximal_heat = T0C + 4000
+ damage_per_fire_tick = 1.0 // This should last for 80 fire ticks if the window is not damaged at all. The idea is that borosilicate windows have something like ablative layer that protects them for a while.
+ maxhealth = 160
+ force_threshold = 10
+
+
+/obj/structure/window/eris
+ icon = 'icons/obj/eris_window.dmi'
+ blend_objects = list(/obj/machinery/door, /turf/simulated/wall/eris)
+ noblend_objects = list(/obj/machinery/door/window)
+ icon_state = "preview_glass"
+ basestate = "window"
+ fulltile = TRUE
+ maxhealth = 24
+ alpha = 150
+
+/obj/structure/window/eris/Initialize()
+ . = ..()
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/structure/window/eris/LateInitialize()
+ . = ..()
+ icon_state = ""
+ update_icon()
+
+/obj/structure/window/eris/update_icon()
+ cut_overlays()
+ if(!anchored)
+ connections = list("0","0","0","0")
+ other_connections = list("0","0","0","0")
+ else
+ update_connections()
+
+ var/img_dir
+ var/image/I
+ for(var/i = 1 to 4)
+ img_dir = 1<<(i-1)
+ if(other_connections[i] != "0")
+ I = image(icon, "[basestate][other_connections[i]]", dir = img_dir)
+ else
+ I = image(icon, "[basestate][connections[i]]", dir = img_dir)
+ add_overlay(I)
+
+/obj/structure/window/eris/reinforced
+ name = "reinforced window"
+ desc = "It looks rather strong. Might take a few good hits to shatter it."
+ icon_state = "preview_rglass"
+ basestate = "rwindow"
+ maxhealth = 80
+ reinf = 1
+ maximal_heat = T0C + 750
+ damage_per_fire_tick = 2.0
+ glasstype = /obj/item/stack/material/glass/reinforced
+ force_threshold = 6
+
+/obj/structure/window/eris/phoronbasic
+ name = "phoron window"
+ desc = "A borosilicate alloy window. It seems to be quite strong."
+ basestate = "preview_phoron"
+ icon_state = "pwindow"
+ shardtype = /obj/item/weapon/material/shard/phoron
+ glasstype = /obj/item/stack/material/glass/phoronglass
+ maximal_heat = T0C + 2000
+ damage_per_fire_tick = 1.0
+ maxhealth = 40.0
+ force_threshold = 5
+ maxhealth = 80
+
+/obj/structure/window/eris/phoronreinforced
+ name = "reinforced borosilicate window"
+ desc = "A borosilicate alloy window, with rods supporting it. It seems to be very strong."
+ basestate = "preview_rphoron"
+ icon_state = "rpwindow"
+ shardtype = /obj/item/weapon/material/shard/phoron
+ glasstype = /obj/item/stack/material/glass/phoronrglass
+ reinf = 1
+ maximal_heat = T0C + 4000
+ damage_per_fire_tick = 1.0 // This should last for 80 fire ticks if the window is not damaged at all. The idea is that borosilicate windows have something like ablative layer that protects them for a while.
+ maxhealth = 160
+ force_threshold = 10
+
+/**
+ * Spawner helpers for mapping these in
+ */
+
+/obj/effect/low_wall_spawner
+ name = "low wall spawner"
+
+ var/low_wall_type
+ var/window_type
+ var/grille_type
+
+ icon = null
+
+/obj/effect/low_wall_spawner/Initialize()
+ . = ..()
+ if(locate(/obj/effect/low_wall_spawner) in oview(0, src))
+ warning("Duplicate low wall spawners in [x],[y],[z]!")
+ return INITIALIZE_HINT_QDEL
+
+ if(low_wall_type)
+ new low_wall_type(loc)
+ if(grille_type)
+ new grille_type(loc)
+ if(window_type)
+ new window_type(loc)
+
+ return INITIALIZE_HINT_QDEL
+
+// Bay types
+/obj/effect/low_wall_spawner/bay
+ icon = 'icons/obj/wall_frame_bay.dmi'
+ icon_state = "sp_glass"
+ low_wall_type = /obj/structure/low_wall/bay
+ window_type = /obj/structure/window/bay
+
+/obj/effect/low_wall_spawner/bay/rglass
+ icon_state = "sp_rglass"
+ window_type = /obj/structure/window/bay/reinforced
+
+/obj/effect/low_wall_spawner/bay/phoron
+ icon_state = "sp_phoron"
+ window_type = /obj/structure/window/bay/phoronbasic
+
+/obj/effect/low_wall_spawner/bay/rphoron
+ icon_state = "sp_rphoron"
+ window_type = /obj/structure/window/bay/phoronreinforced
+
+/obj/effect/low_wall_spawner/bay/grille
+ icon = 'icons/obj/wall_frame_bay.dmi'
+ icon_state = "sp_glass_g"
+ low_wall_type = /obj/structure/low_wall/bay
+ grille_type = /obj/structure/grille/bay
+ window_type = /obj/structure/window/bay
+
+/obj/effect/low_wall_spawner/bay/grille/rglass
+ icon_state = "sp_rglass_g"
+ window_type = /obj/structure/window/bay/reinforced
+
+/obj/effect/low_wall_spawner/bay/grille/phoron
+ icon_state = "sp_phoron_g"
+ window_type = /obj/structure/window/bay/phoronbasic
+
+/obj/effect/low_wall_spawner/bay/grille/rphoron
+ icon_state = "sp_rphoron_g"
+ window_type = /obj/structure/window/bay/phoronreinforced
+
+// Eris types
+/obj/effect/low_wall_spawner/eris
+ icon = 'icons/obj/wall_frame_eris.dmi'
+ icon_state = "sp_glass"
+ low_wall_type = /obj/structure/low_wall/eris
+ window_type = /obj/structure/window/eris
+
+/obj/effect/low_wall_spawner/eris/rglass
+ icon_state = "sp_rglass"
+ window_type = /obj/structure/window/eris/reinforced
+
+/obj/effect/low_wall_spawner/eris/phoron
+ icon_state = "sp_phoron"
+ window_type = /obj/structure/window/eris/phoronbasic
+
+/obj/effect/low_wall_spawner/eris/rphoron
+ icon_state = "sp_rphoron"
+ window_type = /obj/structure/window/eris/phoronreinforced
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 12922d655a..a6f334a2f8 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -273,12 +273,14 @@
to_chat(user, "You have [state == 1 ? "un" : ""]fastened the window [state ? "from" : "to"] the frame.")
else if(reinf && state == 0)
anchored = !anchored
+ update_nearby_tiles(need_rebuild=1)
update_nearby_icons()
update_verbs()
playsound(src, W.usesound, 75, 1)
to_chat(user, "You have [anchored ? "" : "un"]fastened the frame [anchored ? "to" : "from"] the floor.")
else if(!reinf)
anchored = !anchored
+ update_nearby_tiles(need_rebuild=1)
update_nearby_icons()
update_verbs()
playsound(src, W.usesound, 75, 1)
diff --git a/code/game/turfs/simulated/wall_icon.dm b/code/game/turfs/simulated/wall_icon.dm
index b6193f4942..3c9df506ae 100644
--- a/code/game/turfs/simulated/wall_icon.dm
+++ b/code/game/turfs/simulated/wall_icon.dm
@@ -51,30 +51,30 @@
var/image/I
if(!density)
- I = image('icons/turf/wall_masks.dmi', "[material.icon_base]fwall_open")
+ I = image(wall_masks, "[material.icon_base]fwall_open")
I.color = material.icon_colour
add_overlay(I)
return
for(var/i = 1 to 4)
- I = image('icons/turf/wall_masks.dmi', "[material.icon_base][wall_connections[i]]", dir = 1<<(i-1))
+ I = image(wall_masks, "[material.icon_base][wall_connections[i]]", dir = 1<<(i-1))
I.color = material.icon_colour
add_overlay(I)
if(reinf_material)
if(construction_stage != null && construction_stage < 6)
- I = image('icons/turf/wall_masks.dmi', "reinf_construct-[construction_stage]")
+ I = image(wall_masks, "reinf_construct-[construction_stage]")
I.color = reinf_material.icon_colour
add_overlay(I)
else
- if("[reinf_material.icon_reinf]0" in cached_icon_states('icons/turf/wall_masks.dmi'))
+ if("[reinf_material.icon_reinf]0" in cached_icon_states(wall_masks))
// Directional icon
for(var/i = 1 to 4)
- I = image('icons/turf/wall_masks.dmi', "[reinf_material.icon_reinf][wall_connections[i]]", dir = 1<<(i-1))
+ I = image(wall_masks, "[reinf_material.icon_reinf][wall_connections[i]]", dir = 1<<(i-1))
I.color = reinf_material.icon_colour
add_overlay(I)
- else
- I = image('icons/turf/wall_masks.dmi', reinf_material.icon_reinf)
+ else if("[reinf_material.icon_reinf]" in cached_icon_states(wall_masks))
+ I = image(wall_masks, reinf_material.icon_reinf)
I.color = reinf_material.icon_colour
add_overlay(I)
@@ -104,14 +104,18 @@
if(!material)
return
var/list/dirs = list()
- for(var/turf/simulated/wall/W in orange(src, 1))
+ var/inrange = orange(src, 1)
+ for(var/turf/simulated/wall/W in inrange)
if(!W.material)
continue
if(propagate)
W.update_connections()
W.update_icon()
- if(can_join_with(W))
+ if(can_join_with_wall(W))
dirs += get_dir(src, W)
+ for(var/obj/structure/low_wall/WF in inrange)
+ if(can_join_with_low_wall(WF))
+ dirs += get_dir(src, WF)
if(material.icon_base == "hull") // Could be improved...
var/additional_dirs = 0
@@ -127,8 +131,7 @@
wall_connections = dirs_to_corner_states(dirs)
-/turf/simulated/wall/proc/can_join_with(var/turf/simulated/wall/W)
- //VOREStation Edit Start
+/turf/simulated/wall/proc/can_join_with_wall(var/turf/simulated/wall/W)
//No blending if no material
if(!material || !W.material)
return 0
@@ -138,5 +141,7 @@
//Also blend if they have the same iconbase
if(material.icon_base == W.material.icon_base)
return 1
- //VOREStation Edit End
return 0
+
+/turf/simulated/wall/proc/can_join_with_low_wall(var/obj/structure/low_wall/WF)
+ return FALSE
\ No newline at end of file
diff --git a/code/game/turfs/simulated/wall_types.dm b/code/game/turfs/simulated/wall_types.dm
index 880210c6f9..87d440f813 100644
--- a/code/game/turfs/simulated/wall_types.dm
+++ b/code/game/turfs/simulated/wall_types.dm
@@ -372,3 +372,44 @@
/obj/structure/hull_corner/long_horiz/get_dirs_to_test()
return list(dir, turn(dir,90), turn(dir,-90))
+
+
+
+// Eris walls
+/turf/simulated/wall/eris
+ icon = 'icons/turf/wall_masks_eris.dmi'
+ icon_state = "generic"
+ wall_masks = 'icons/turf/wall_masks_eris.dmi'
+
+/turf/simulated/wall/eris/can_join_with_low_wall(var/obj/structure/low_wall/WF)
+ return istype(WF, /obj/structure/low_wall/eris)
+
+/turf/simulated/wall/eris/r_wall
+ icon_state = "rgeneric"
+/turf/simulated/wall/eris/r_wall/Initialize(mapload)
+ . = ..(mapload, "plasteel","plasteel")
+
+// Bay walls
+/turf/simulated/wall/bay
+ icon = 'icons/turf/wall_masks_bay.dmi'
+ icon_state = "generic"
+ wall_masks = 'icons/turf/wall_masks_bay.dmi'
+
+ var/stripe_color // Adds a colored stripe to the walls
+
+/turf/simulated/wall/bay/can_join_with_low_wall(var/obj/structure/low_wall/WF)
+ return istype(WF, /obj/structure/low_wall/bay)
+
+/turf/simulated/wall/bay/update_icon()
+ . = ..()
+ if(stripe_color)
+ var/image/I
+ for(var/i = 1 to 4)
+ I = image(wall_masks, "stripe[wall_connections[i]]", dir = 1<<(i-1))
+ I.color = stripe_color
+ add_overlay(I)
+
+/turf/simulated/wall/bay/r_wall
+ icon_state = "rgeneric"
+/turf/simulated/wall/bay/r_wall/Initialize(mapload)
+ . = ..(mapload, "plasteel","plasteel")
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index be1605e0a9..d0bb6d5640 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -9,6 +9,7 @@
thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall
+ var/icon/wall_masks = 'icons/turf/wall_masks.dmi'
var/damage = 0
var/damage_overlay = 0
var/global/damage_overlays[16]
@@ -20,6 +21,7 @@
var/last_state
var/construction_stage
+ // There's basically always going to be wall connections, making this lazy doesn't seem like it'd help much unless you wanted to make it bitflags instead.
var/list/wall_connections = list("0", "0", "0", "0")
// Walls always hide the stuff below them.
diff --git a/code/modules/materials/materials/_materials.dm b/code/modules/materials/materials/_materials.dm
index 83cf22271d..07b1af73ff 100644
--- a/code/modules/materials/materials/_materials.dm
+++ b/code/modules/materials/materials/_materials.dm
@@ -358,9 +358,15 @@ var/list/name_to_material
new /datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
new /datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
new /datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
- new /datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ new /datum/stack_recipe("[display_name] wall girders (standard)", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
+ new /datum/stack_recipe("[display_name] wall girders (bay)", /obj/structure/girder/bay, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
)
-
+ if(icon_base == "solid") // few icons
+ recipes += new /datum/stack_recipe("[display_name] wall girders (eris)", /obj/structure/girder/eris, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new /datum/stack_recipe_list("low walls",list(
+ new /datum/stack_recipe("low wall (bay style)", /obj/structure/low_wall/bay, 3, time = 20, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", recycle_material = "[name]"),
+ new /datum/stack_recipe("low wall (eris style)", /obj/structure/low_wall/eris, 3, time = 20, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", recycle_material = "[name]")
+ ))
if(hardness>50)
recipes += list(
new /datum/stack_recipe("[display_name] fork", /obj/item/weapon/material/kitchen/utensil/fork/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE),
diff --git a/code/modules/materials/materials/glass.dm b/code/modules/materials/materials/glass.dm
index dd1f09821e..1bfffff501 100644
--- a/code/modules/materials/materials/glass.dm
+++ b/code/modules/materials/materials/glass.dm
@@ -1,5 +1,5 @@
/datum/material/glass
- name = "glass"
+ name = MAT_GLASS
stack_type = /obj/item/stack/material/glass
flags = MATERIAL_BRITTLE
icon_colour = "#00E1FF"
@@ -94,7 +94,7 @@
return (hardness > 35) //todo
/datum/material/glass/reinforced
- name = "rglass"
+ name = MAT_RGLASS
display_name = "reinforced glass"
stack_type = /obj/item/stack/material/glass/reinforced
flags = MATERIAL_BRITTLE
@@ -114,7 +114,7 @@
rod_product = null
/datum/material/glass/phoron
- name = "borosilicate glass"
+ name = MAT_PGLASS
display_name = "borosilicate glass"
stack_type = /obj/item/stack/material/glass/phoronglass
flags = MATERIAL_BRITTLE
@@ -128,7 +128,7 @@
rod_product = /obj/item/stack/material/glass/phoronrglass
/datum/material/glass/phoron/reinforced
- name = "reinforced borosilicate glass"
+ name = MAT_RPGLASS
display_name = "reinforced borosilicate glass"
stack_type = /obj/item/stack/material/glass/phoronrglass
stack_origin_tech = list(TECH_MATERIAL = 5)
diff --git a/code/modules/materials/materials/metals/plasteel.dm b/code/modules/materials/materials/metals/plasteel.dm
index 0c436efded..8146980057 100644
--- a/code/modules/materials/materials/metals/plasteel.dm
+++ b/code/modules/materials/materials/metals/plasteel.dm
@@ -1,5 +1,5 @@
/datum/material/plasteel
- name = "plasteel"
+ name = MAT_PLASTEEL
stack_type = /obj/item/stack/material/plasteel
integrity = 400
melting_point = 6000
@@ -23,5 +23,9 @@
new /datum/stack_recipe("knife grip", /obj/item/weapon/material/butterflyhandle, 4, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]"),
new /datum/stack_recipe("dark floor tile", /obj/item/stack/tile/floor/dark, 1, 4, 20, recycle_material = "[name]"),
new /datum/stack_recipe("roller bed", /obj/item/roller, 5, time = 30, on_floor = 1, recycle_material = "[name]"),
- new /datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 10, recycle_material = "[name]")
+ new /datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 10, recycle_material = "[name]"),
+ new /datum/stack_recipe_list("reinforced low walls",list(
+ new /datum/stack_recipe("reinforced low wall (bay style)", /obj/structure/low_wall/bay/reinforced, 3, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", recycle_material = "[name]"),
+ new /datum/stack_recipe("reinforced low wall (eris style)", /obj/structure/low_wall/eris/reinforced, 3, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", recycle_material = "[name]")
+ )),
)
\ No newline at end of file
diff --git a/code/modules/tables/interactions.dm b/code/modules/tables/interactions.dm
index 6cbf77cd99..349624eb78 100644
--- a/code/modules/tables/interactions.dm
+++ b/code/modules/tables/interactions.dm
@@ -142,44 +142,5 @@
auto_align(W, click_parameters)
return 1
-#define CELLS 8 //Amount of cells per row/column in grid
-#define CELLSIZE (world.icon_size/CELLS) //Size of a cell in pixels
-/*
-Automatic alignment of items to an invisible grid, defined by CELLS and CELLSIZE.
-Since the grid will be shifted to own a cell that is perfectly centered on the turf, we end up with two 'cell halves'
-on edges of each row/column.
-Each item defines a center_of_mass, which is the pixel of a sprite where its projected center of mass toward a turf
-surface can be assumed. For a piece of paper, this will be in its center. For a bottle, it will be (near) the bottom
-of the sprite.
-auto_align() will then place the sprite so the defined center_of_mass is at the bottom left corner of the grid cell
-closest to where the cursor has clicked on.
-Note: This proc can be overwritten to allow for different types of auto-alignment.
-*/
-
-/obj/item/var/list/center_of_mass = list("x" = 16,"y" = 16)
-
-/obj/structure/table/proc/auto_align(obj/item/W, click_parameters)
- if(!W.center_of_mass)
- W.randpixel_xy()
- return
-
- if(!click_parameters)
- return
-
- var/list/mouse_control = params2list(click_parameters)
-
- var/mouse_x = text2num(mouse_control["icon-x"])
- var/mouse_y = text2num(mouse_control["icon-y"])
-
- if(isnum(mouse_x) && isnum(mouse_y))
- var/cell_x = max(0, min(CELLS-1, round(mouse_x/CELLSIZE)))
- var/cell_y = max(0, min(CELLS-1, round(mouse_y/CELLSIZE)))
-
- W.pixel_x = (CELLSIZE * (0.5 + cell_x)) - W.center_of_mass["x"]
- W.pixel_y = (CELLSIZE * (0.5 + cell_y)) - W.center_of_mass["y"]
-
-#undef CELLS
-#undef CELLSIZE
-
/obj/structure/table/attack_tk() // no telehulk sorry
return
diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm
index 55d0127661..f428033848 100644
--- a/code/modules/tables/tables.dm
+++ b/code/modules/tables/tables.dm
@@ -28,8 +28,6 @@ var/list/table_icon_cache = list()
var/carpeted = 0
var/carpeted_type = /obj/item/stack/tile/carpet
- var/item_place = 1 //allows items to be placed on the table, but not on benches.
-
/obj/structure/table/examine_icon()
return icon(icon=initial(icon), icon_state=initial(icon_state)) //Basically the map preview version
diff --git a/icons/obj/bay_grille.dmi b/icons/obj/bay_grille.dmi
new file mode 100644
index 0000000000..759cec55b4
Binary files /dev/null and b/icons/obj/bay_grille.dmi differ
diff --git a/icons/obj/bay_window.dmi b/icons/obj/bay_window.dmi
new file mode 100644
index 0000000000..0cc8646beb
Binary files /dev/null and b/icons/obj/bay_window.dmi differ
diff --git a/icons/obj/eris_window.dmi b/icons/obj/eris_window.dmi
new file mode 100644
index 0000000000..d588dd2f07
Binary files /dev/null and b/icons/obj/eris_window.dmi differ
diff --git a/icons/obj/wall_frame_bay.dmi b/icons/obj/wall_frame_bay.dmi
new file mode 100644
index 0000000000..cfe6ee2d56
Binary files /dev/null and b/icons/obj/wall_frame_bay.dmi differ
diff --git a/icons/obj/wall_frame_eris.dmi b/icons/obj/wall_frame_eris.dmi
new file mode 100644
index 0000000000..df4643219c
Binary files /dev/null and b/icons/obj/wall_frame_eris.dmi differ
diff --git a/icons/turf/wall_masks_bay.dmi b/icons/turf/wall_masks_bay.dmi
new file mode 100644
index 0000000000..c30daaa21d
Binary files /dev/null and b/icons/turf/wall_masks_bay.dmi differ
diff --git a/icons/turf/wall_masks_eris.dmi b/icons/turf/wall_masks_eris.dmi
new file mode 100644
index 0000000000..6780acaa0c
Binary files /dev/null and b/icons/turf/wall_masks_eris.dmi differ
diff --git a/vorestation.dme b/vorestation.dme
index b5b5664afa..c46057ae61 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -1565,6 +1565,7 @@
#include "code\game\objects\structures\trash_pile_vr.dm"
#include "code\game\objects\structures\trash_pile_vr_ch.dm"
#include "code\game\objects\structures\under_wardrobe.dm"
+#include "code\game\objects\structures\wall_frame.dm"
#include "code\game\objects\structures\watercloset.dm"
#include "code\game\objects\structures\watercloset_vr.dm"
#include "code\game\objects\structures\windoor_assembly.dm"