diff --git a/_maps/map_files/stations/boxstation.dmm b/_maps/map_files/stations/boxstation.dmm
index 942ebda57b2..c5a0337434f 100644
--- a/_maps/map_files/stations/boxstation.dmm
+++ b/_maps/map_files/stations/boxstation.dmm
@@ -1537,7 +1537,6 @@
/turf/space,
/area/shuttle/gamma/station)
"ahG" = (
-/obj/structure/rack,
/obj/item/gun/projectile/shotgun/riot{
pixel_x = -3;
pixel_y = -3
@@ -1547,13 +1546,7 @@
pixel_y = 3
},
/obj/item/gun/projectile/shotgun/riot,
-/obj/structure/window/reinforced{
- dir = 8
- },
-/obj/structure/window/reinforced{
- dir = 1;
- layer = 2.9
- },
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "vault"
@@ -1676,7 +1669,6 @@
},
/area/station/security/brig)
"aif" = (
-/obj/structure/rack,
/obj/item/storage/box/teargas{
pixel_x = -3;
pixel_y = -3
@@ -1696,6 +1688,7 @@
/obj/structure/window/reinforced{
dir = 4
},
+/obj/structure/shelf/security,
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
@@ -1768,7 +1761,6 @@
},
/area/station/security/armory/secure)
"aiq" = (
-/obj/structure/rack,
/obj/structure/window/reinforced{
dir = 1
},
@@ -1781,9 +1773,7 @@
pixel_x = -3;
pixel_y = -3
},
-/obj/structure/window/reinforced{
- dir = 4
- },
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "vault"
@@ -1928,7 +1918,6 @@
},
/area/station/security/brig)
"aiN" = (
-/obj/structure/rack,
/obj/item/gun/energy/gun{
pixel_x = 3;
pixel_y = 3
@@ -1938,9 +1927,7 @@
pixel_x = -3;
pixel_y = -3
},
-/obj/structure/window/reinforced{
- dir = 4
- },
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "vault"
@@ -2234,7 +2221,6 @@
},
/area/station/security/armory/secure)
"ajr" = (
-/obj/structure/rack,
/obj/structure/window/reinforced,
/obj/item/gun/energy/disabler{
pixel_x = 3;
@@ -2245,9 +2231,7 @@
pixel_x = -3;
pixel_y = -3
},
-/obj/structure/window/reinforced{
- dir = 4
- },
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "vault"
@@ -8723,7 +8707,6 @@
/obj/item/stack/rods{
amount = 50
},
-/obj/structure/rack,
/obj/item/stack/cable_coil{
pixel_x = -3;
pixel_y = 3
@@ -8732,6 +8715,7 @@
amount = 5
},
/obj/effect/decal/cleanable/dirt,
+/obj/structure/shelf/engineering,
/turf/simulated/floor/plasteel,
/area/station/maintenance/electrical)
"aCV" = (
@@ -16306,10 +16290,6 @@
},
/area/station/ai_monitored/storage/eva)
"baj" = (
-/obj/structure/rack{
- dir = 8;
- layer = 2.9
- },
/obj/item/clothing/shoes/magboots{
pixel_x = 2;
pixel_y = 2
@@ -16330,6 +16310,7 @@
pixel_x = 2;
pixel_y = 2
},
+/obj/structure/shelf/command,
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
@@ -21853,9 +21834,9 @@
/turf/simulated/floor/plasteel,
/area/station/hallway/secondary/entry/lounge)
"bpG" = (
-/obj/structure/table,
/obj/item/reagent_containers/glass/bucket,
/obj/item/reagent_containers/glass/bucket,
+/obj/structure/shelf/service,
/turf/simulated/floor/plasteel{
icon_state = "hydrofloor"
},
@@ -26020,9 +26001,9 @@
},
/area/station/science/robotics)
"bEO" = (
-/obj/structure/rack,
/obj/effect/spawner/random_spawners/cobweb_left_frequent,
/obj/effect/decal/cleanable/dirt,
+/obj/effect/spawner/random/storage,
/obj/effect/spawner/random/maintenance,
/turf/simulated/floor/plasteel,
/area/station/maintenance/apmaint)
@@ -27657,10 +27638,6 @@
},
/area/station/hallway/primary/central/west)
"bKT" = (
-/obj/structure/rack{
- dir = 8;
- layer = 2.9
- },
/obj/item/storage/belt/utility,
/obj/item/clothing/head/welding{
pixel_x = -3;
@@ -27670,6 +27647,7 @@
pixel_x = -3
},
/obj/item/clothing/glasses/welding,
+/obj/structure/shelf/science,
/turf/simulated/floor/plasteel{
dir = 1;
icon_state = "whitepurple"
@@ -28790,7 +28768,7 @@
pixel_x = 6;
pixel_y = -2
},
-/obj/structure/rack,
+/obj/structure/shelf/medbay,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "whiteyellow"
@@ -42608,10 +42586,6 @@
},
/area/station/engineering/smes)
"cOf" = (
-/obj/structure/rack{
- dir = 8;
- layer = 2.9
- },
/obj/item/tank/internals/emergency_oxygen/engi,
/obj/item/clothing/suit/storage/hazardvest/staff,
/obj/item/clothing/suit/storage/hazardvest/staff,
@@ -42625,6 +42599,7 @@
name = "west bump";
pixel_x = -28
},
+/obj/structure/shelf/engineering,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "caution"
@@ -42840,10 +42815,6 @@
/turf/simulated/wall/r_wall,
/area/station/engineering/atmos/distribution)
"cOY" = (
-/obj/structure/rack{
- dir = 8;
- layer = 2.9
- },
/obj/item/clothing/suit/storage/hazardvest/staff,
/obj/item/tank/internals/emergency_oxygen/engi,
/obj/item/clothing/suit/storage/hazardvest/staff,
@@ -42860,6 +42831,7 @@
d2 = 4;
icon_state = "0-4"
},
+/obj/structure/shelf/engineering,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "caution"
@@ -43793,7 +43765,6 @@
},
/area/station/science/xenobiology)
"cSh" = (
-/obj/structure/table,
/obj/item/clothing/glasses/science{
pixel_y = 4
},
@@ -43801,6 +43772,7 @@
/obj/structure/sign/poster/official/safety_eye_protection{
pixel_y = 32
},
+/obj/structure/shelf/science,
/turf/simulated/floor/plasteel{
dir = 1;
icon_state = "whitepurple"
@@ -55500,6 +55472,11 @@
icon_state = "redcorner"
},
/area/station/security/prisonershuttle)
+"fvC" = (
+/obj/effect/spawner/random/storage,
+/obj/effect/spawner/random/maintenance,
+/turf/simulated/floor/plating,
+/area/station/maintenance/fsmaint)
"fvV" = (
/obj/structure/table,
/obj/item/toy/crayon/spraycan,
@@ -56738,7 +56715,6 @@
/area/station/public/dorms)
"gdp" = (
/obj/machinery/alarm/directional/west,
-/obj/structure/rack,
/obj/item/clothing/head/helmet/space/plasmaman{
pixel_x = -3;
pixel_y = 2
@@ -56757,6 +56733,7 @@
pixel_x = -3;
pixel_y = 2
},
+/obj/structure/shelf/medbay,
/turf/simulated/floor/plasteel{
icon_state = "darkred"
},
@@ -63922,10 +63899,6 @@
/turf/simulated/floor/plating,
/area/station/security/permabrig)
"jFJ" = (
-/obj/structure/rack{
- dir = 1
- },
-/obj/item/storage/box/lights/mixed,
/obj/item/storage/box/lights/mixed,
/obj/item/storage/box/lights/mixed,
/obj/item/storage/box/lights/mixed,
@@ -63937,6 +63910,7 @@
name = "west bump";
pixel_x = -28
},
+/obj/structure/shelf/service,
/turf/simulated/floor/plasteel,
/area/station/service/janitor)
"jGd" = (
@@ -71170,6 +71144,11 @@
icon_state = "neutralfull"
},
/area/station/hallway/secondary/exit)
+"njn" = (
+/obj/effect/spawner/random/storage,
+/obj/effect/spawner/random/maintenance,
+/turf/simulated/floor/plating,
+/area/station/maintenance/apmaint)
"nju" = (
/obj/structure/disposalpipe/segment/corner{
dir = 4
@@ -71613,7 +71592,7 @@
/turf/simulated/floor/plating,
/area/station/maintenance/fpmaint2)
"nyC" = (
-/obj/structure/rack,
+/obj/effect/spawner/random/storage,
/turf/simulated/floor/plating,
/area/station/maintenance/aft)
"nzc" = (
@@ -86237,7 +86216,6 @@
pixel_x = -4
},
/obj/item/tank/internals/emergency_oxygen/nitrogen,
-/obj/structure/rack,
/obj/item/tank/internals/emergency_oxygen/plasma{
pixel_x = 5
},
@@ -86246,6 +86224,7 @@
},
/obj/item/clothing/mask/breath/vox,
/obj/item/clothing/mask/breath/vox,
+/obj/structure/shelf/medbay,
/turf/simulated/floor/plasteel{
icon_state = "darkbluefull"
},
@@ -118962,8 +118941,8 @@ cwl
wFR
fnV
cwz
-sCW
-sCW
+njn
+njn
cgQ
dCM
ieW
@@ -135609,7 +135588,7 @@ aHb
aHb
aOG
aGX
-aHb
+fvC
aOG
aGY
aTg
diff --git a/_maps/map_files/stations/cerestation.dmm b/_maps/map_files/stations/cerestation.dmm
index 6c25b7379ce..cd57fa0c0e3 100644
--- a/_maps/map_files/stations/cerestation.dmm
+++ b/_maps/map_files/stations/cerestation.dmm
@@ -2332,8 +2332,8 @@
},
/area/station/security/permabrig)
"aoE" = (
-/obj/structure/table,
/obj/effect/spawner/random/maintenance,
+/obj/effect/spawner/random/storage,
/turf/simulated/floor/plating,
/area/station/maintenance/disposal/northeast)
"aoF" = (
@@ -6850,12 +6850,6 @@
/obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance,
/turf/simulated/floor/plating,
/area/station/maintenance/disposal/east)
-"aUB" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
-/turf/simulated/floor/plasteel{
- icon_state = "darkgreenfull"
- },
-/area/station/service/hydroponics)
"aUE" = (
/obj/machinery/light{
dir = 8
@@ -15137,7 +15131,6 @@
},
/area/station/science/genetics)
"bLf" = (
-/obj/structure/rack,
/obj/item/gun/projectile/shotgun/riot{
pixel_x = -3;
pixel_y = 3
@@ -15147,16 +15140,10 @@
pixel_x = 3;
pixel_y = -3
},
-/obj/structure/window/reinforced{
- dir = 8
- },
-/obj/structure/window/reinforced{
- dir = 1;
- layer = 2.9
- },
/obj/machinery/camera{
c_tag = "Brig Secure Armory"
},
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "vault"
@@ -15222,6 +15209,9 @@
pixel_x = 3;
pixel_y = -3
},
+/obj/structure/window/reinforced{
+ dir = 8
+ },
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "vault"
@@ -18675,9 +18665,6 @@
/obj/item/clothing/head/helmet/alt,
/obj/item/clothing/suit/armor/bulletproof,
/obj/item/clothing/head/helmet/alt,
-/obj/structure/window/reinforced{
- dir = 8
- },
/obj/structure/window/reinforced,
/turf/simulated/floor/plasteel{
dir = 8;
@@ -18685,7 +18672,6 @@
},
/area/station/security/armory/secure)
"ccO" = (
-/obj/structure/rack,
/obj/item/gun/energy/disabler{
pixel_x = -3;
pixel_y = 3
@@ -18699,6 +18685,7 @@
dir = 4
},
/obj/structure/window/reinforced,
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "vault"
@@ -19397,7 +19384,6 @@
},
/area/station/security/warden)
"cgG" = (
-/obj/structure/rack,
/obj/item/storage/box/seccarts{
pixel_x = 3;
pixel_y = 2
@@ -19412,17 +19398,16 @@
pixel_x = -3;
pixel_y = -3
},
-/obj/structure/window/reinforced,
/obj/structure/window/reinforced{
dir = 4
},
+/obj/structure/shelf/security,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "vault"
},
/area/station/security/armory/secure)
"cgL" = (
-/obj/structure/rack,
/obj/item/gun/energy/laser{
pixel_x = -3;
pixel_y = 3
@@ -19432,20 +19417,13 @@
pixel_x = 3;
pixel_y = -3
},
-/obj/structure/window/reinforced{
- dir = 8
- },
-/obj/structure/window/reinforced{
- dir = 1;
- layer = 2.9
- },
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "vault"
},
/area/station/security/armory/secure)
"cgR" = (
-/obj/structure/rack,
/obj/item/gun/energy/gun{
pixel_x = -3;
pixel_y = 3
@@ -19458,10 +19436,7 @@
/obj/structure/window/reinforced{
dir = 4
},
-/obj/structure/window/reinforced{
- dir = 1;
- layer = 2.9
- },
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "vault"
@@ -26914,11 +26889,6 @@
icon_state = "redcorner"
},
/area/station/security/prison/cell_block/A)
-"dcR" = (
-/obj/structure/table,
-/obj/effect/spawner/random/maintenance,
-/turf/simulated/floor/plating/asteroid/ancient,
-/area/station/maintenance/port)
"dda" = (
/obj/machinery/atmospherics/unary/vent_scrubber/on{
dir = 8
@@ -28052,6 +28022,17 @@
/obj/machinery/ai_status_display,
/turf/simulated/wall/r_wall,
/area/station/security/prisonlockers)
+"dkb" = (
+/obj/machinery/requests_console/directional/south,
+/obj/structure/cable/orange{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
+/turf/simulated/floor/plasteel{
+ icon_state = "grimy"
+ },
+/area/station/security/detective)
"dkc" = (
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 4
@@ -33867,11 +33848,11 @@
/obj/machinery/light/small{
dir = 1
},
-/obj/structure/rack,
/obj/effect/spawner/random/maintenance,
/obj/structure/window/basic{
dir = 8
},
+/obj/effect/spawner/random/storage,
/turf/simulated/floor/plating,
/area/station/maintenance/disposal)
"eot" = (
@@ -35929,12 +35910,6 @@
},
/turf/simulated/floor/plating,
/area/station/maintenance/port)
-"eTe" = (
-/obj/machinery/hologram/holopad,
-/turf/simulated/floor/plasteel{
- icon_state = "dark"
- },
-/area/station/service/hydroponics)
"eTg" = (
/obj/machinery/recharge_station,
/turf/simulated/floor/plasteel{
@@ -35981,7 +35956,8 @@
/turf/simulated/floor/grass,
/area/station/hallway/spacebridge/scidock)
"eTI" = (
-/obj/effect/decal/cleanable/blood/splatter,
+/obj/structure/table,
+/obj/effect/spawner/random/maintenance,
/turf/simulated/floor/plating/asteroid/ancient,
/area/station/maintenance/port)
"eTJ" = (
@@ -36443,9 +36419,9 @@
/turf/simulated/floor/plating,
/area/station/engineering/smes)
"fcE" = (
-/obj/structure/table,
/obj/item/stack/packageWrap,
/obj/item/destTagger,
+/obj/structure/shelf/command,
/turf/simulated/floor/plasteel{
dir = 1;
icon_state = "darkblue"
@@ -37654,6 +37630,13 @@
},
/turf/simulated/floor/plating,
/area/station/hallway/primary/central/west)
+"fvV" = (
+/obj/structure/chair/office/dark{
+ dir = 4
+ },
+/obj/effect/landmark/start/detective,
+/turf/simulated/floor/carpet,
+/area/station/security/detective)
"fwd" = (
/obj/effect/decal/cleanable/crayon,
/turf/simulated/floor/wood,
@@ -38774,6 +38757,12 @@
icon_state = "dark"
},
/area/station/engineering/control)
+"fPD" = (
+/obj/structure/reagent_dispensers/fueltank,
+/turf/simulated/floor/plating{
+ icon_state = "asteroidplating"
+ },
+/area/station/maintenance/port)
"fPE" = (
/obj/structure/disposalpipe/segment/corner{
dir = 4
@@ -41282,25 +41271,6 @@
icon_state = "whitepurple"
},
/area/station/science/genetics)
-"gEI" = (
-/obj/machinery/door/airlock/public/glass{
- name = "Walkway"
- },
-/obj/machinery/door/firedoor,
-/obj/machinery/door/poddoor/preopen{
- id_tag = "servlockdown";
- layer = 2.6;
- name = "Service Lockdown"
- },
-/obj/structure/disposalpipe/segment{
- color = "#954535"
- },
-/obj/effect/turf_decal/caution/red,
-/turf/simulated/floor/plasteel{
- dir = 8;
- icon_state = "neutralcorner"
- },
-/area/station/hallway/spacebridge/sercom)
"gEJ" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 4
@@ -43834,7 +43804,6 @@
/area/station/service/bar)
"htz" = (
/obj/effect/spawner/random_spawners/dirt_often,
-/obj/effect/turf_decal/delivery,
/turf/simulated/floor/plasteel{
icon_state = "darkgreenfull"
},
@@ -44696,11 +44665,11 @@
pixel_x = 8;
pixel_y = 2
},
-/obj/structure/table/glass,
/obj/item/radio/intercom{
pixel_y = 28;
name = "custom placement"
},
+/obj/structure/shelf/medbay,
/turf/simulated/floor/plasteel{
dir = 1;
icon_state = "whiteblue"
@@ -44900,8 +44869,8 @@
d2 = 2;
icon_state = "1-2"
},
-/obj/structure/rack,
/obj/effect/spawner/random/maintenance,
+/obj/effect/spawner/random/storage,
/turf/simulated/floor/plating,
/area/station/maintenance/fore2)
"hIo" = (
@@ -46238,12 +46207,12 @@
/turf/simulated/floor/carpet/blue,
/area/station/command/office/blueshield)
"hZk" = (
-/obj/structure/rack,
/obj/item/storage/belt/utility,
/obj/item/storage/belt/utility,
/obj/item/clothing/mask/gas,
/obj/item/clothing/mask/gas,
/obj/item/clothing/mask/gas,
+/obj/structure/shelf/engineering,
/turf/simulated/floor/plasteel{
icon_state = "darkyellow"
},
@@ -47286,6 +47255,13 @@
icon_state = "browncorner"
},
/area/station/hallway/primary/fore/east)
+"inP" = (
+/obj/structure/rack,
+/obj/effect/spawner/random/maintenance,
+/turf/simulated/floor/plating{
+ icon_state = "asteroidplating"
+ },
+/area/station/maintenance/port)
"inQ" = (
/obj/machinery/door/airlock/maintenance{
name = "Port Asteroid Maintenance"
@@ -50504,6 +50480,21 @@
icon_state = "dark"
},
/area/station/hallway/primary/starboard/south)
+"jeu" = (
+/obj/machinery/hologram/holopad,
+/obj/structure/cable/orange{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
+ dir = 1
+ },
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,
+/turf/simulated/floor/plasteel{
+ icon_state = "dark"
+ },
+/area/station/service/hydroponics)
"jeB" = (
/obj/structure/transit_tube/station/reverse/flipped{
dir = 4
@@ -51168,6 +51159,22 @@
/obj/structure/disposalpipe/segment,
/turf/simulated/floor/plasteel,
/area/station/security/lobby)
+"joS" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
+ dir = 4
+ },
+/obj/structure/cable/orange{
+ d1 = 4;
+ d2 = 8;
+ icon_state = "4-8"
+ },
+/obj/machinery/atmospherics/pipe/simple/hidden/supply{
+ dir = 4
+ },
+/turf/simulated/floor/plasteel{
+ icon_state = "dark"
+ },
+/area/station/service/hydroponics)
"joZ" = (
/obj/machinery/atmospherics/unary/vent_scrubber/on{
dir = 4
@@ -51969,8 +51976,8 @@
/turf/simulated/floor/plasteel/white,
/area/station/command/office/rd)
"jyk" = (
-/obj/structure/rack,
/obj/effect/spawner/random/maintenance,
+/obj/effect/spawner/random/storage,
/turf/simulated/floor/plating,
/area/station/maintenance/fsmaint)
"jyn" = (
@@ -55810,15 +55817,6 @@
/area/station/medical/medbay)
"kAT" = (
/obj/machinery/hologram/holopad,
-/obj/structure/cable/orange{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/manifold/hidden/supply{
- dir = 1
- },
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers,
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
@@ -57780,12 +57778,6 @@
},
/turf/simulated/floor/plating,
/area/station/maintenance/port)
-"lhc" = (
-/obj/effect/spawner/random_spawners/dirt_often,
-/turf/simulated/floor/plasteel{
- icon_state = "darkgreenfull"
- },
-/area/station/service/hydroponics)
"lhf" = (
/obj/effect/spawner/window/reinforced/grilled,
/obj/structure/cable/orange{
@@ -58019,6 +58011,10 @@
},
/turf/simulated/floor/plasteel/freezer,
/area/station/service/kitchen)
+"ljz" = (
+/obj/effect/decal/cleanable/blood/splatter,
+/turf/simulated/floor/plating/asteroid/ancient,
+/area/station/maintenance/port)
"ljL" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/disposalpipe/segment,
@@ -61319,11 +61315,12 @@
/turf/simulated/floor/plating,
/area/station/maintenance/port)
"mgq" = (
-/obj/structure/reagent_dispensers/fueltank,
-/turf/simulated/floor/plating{
- icon_state = "asteroidplating"
+/obj/effect/spawner/random_spawners/dirt_often,
+/obj/effect/turf_decal/delivery,
+/turf/simulated/floor/plasteel{
+ icon_state = "darkgreenfull"
},
-/area/station/maintenance/port)
+/area/station/service/hydroponics)
"mgu" = (
/obj/docking_port/stationary{
dir = 4;
@@ -65409,16 +65406,8 @@
/turf/simulated/floor/plating,
/area/station/engineering/tech_storage)
"nsy" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
- dir = 4
- },
-/obj/structure/cable/orange{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/obj/machinery/atmospherics/pipe/simple/hidden/supply{
- dir = 4
+/obj/machinery/atmospherics/unary/vent_pump/on{
+ dir = 1
},
/turf/simulated/floor/plasteel{
icon_state = "dark"
@@ -68212,17 +68201,6 @@
},
/turf/simulated/floor/plating,
/area/station/maintenance/asmaint)
-"olh" = (
-/obj/machinery/light{
- dir = 4
- },
-/obj/machinery/atmospherics/unary/vent_scrubber/on{
- dir = 8
- },
-/turf/simulated/floor/plasteel{
- icon_state = "darkgreenfull"
- },
-/area/station/service/hydroponics)
"olr" = (
/obj/structure/table,
/obj/item/paper{
@@ -84532,14 +84510,6 @@
icon_state = "asteroidplating"
},
/area/station/maintenance/port)
-"sNb" = (
-/obj/machinery/atmospherics/unary/vent_pump/on{
- dir = 1
- },
-/turf/simulated/floor/plasteel{
- icon_state = "dark"
- },
-/area/station/service/hydroponics)
"sNm" = (
/obj/structure/disposalpipe/segment,
/obj/effect/turf_decal/stripes/line{
@@ -87195,12 +87165,12 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
-/obj/structure/table,
/obj/item/stack/packageWrap,
/obj/item/destTagger{
pixel_x = 4;
pixel_y = 3
},
+/obj/structure/shelf/science,
/turf/simulated/floor/plasteel{
icon_state = "whitepurple"
},
@@ -87468,6 +87438,22 @@
/obj/item/storage/backpack/satchel/explorer,
/turf/simulated/floor/plating/asteroid/ancient,
/area/station/maintenance/starboard)
+"tDi" = (
+/obj/item/storage/bag/plants/portaseeder,
+/obj/item/storage/bag/plants/portaseeder,
+/obj/item/storage/bag/plants,
+/obj/item/storage/bag/plants,
+/obj/structure/shelf/service,
+/obj/machinery/light{
+ dir = 4
+ },
+/obj/machinery/atmospherics/unary/vent_scrubber/on{
+ dir = 8
+ },
+/turf/simulated/floor/plasteel{
+ icon_state = "darkgreenfull"
+ },
+/area/station/service/hydroponics)
"tDm" = (
/obj/machinery/firealarm/directional/south,
/turf/simulated/floor/plasteel{
@@ -88048,6 +88034,12 @@
/obj/effect/spawner/airlock/s_to_n,
/turf/simulated/wall,
/area/station/hallway/primary/central/north)
+"tMD" = (
+/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/turf/simulated/floor/plasteel{
+ icon_state = "darkgreenfull"
+ },
+/area/station/service/hydroponics)
"tMN" = (
/obj/machinery/door/airlock/external{
id_tag = "laborcamp_home";
@@ -92059,7 +92051,7 @@
/turf/simulated/floor/plating,
/area/station/engineering/tech_storage)
"uQB" = (
-/obj/machinery/atmospherics/pipe/simple/hidden/supply,
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/turf/simulated/floor/plasteel{
icon_state = "darkgreenfull"
},
@@ -99330,7 +99322,6 @@
},
/area/station/public/fitness)
"wOh" = (
-/obj/structure/table,
/obj/structure/disposalpipe/segment{
dir = 4
},
@@ -99343,6 +99334,7 @@
name = "south bump";
pixel_y = -28
},
+/obj/structure/shelf/supply,
/turf/simulated/floor/plasteel{
icon_state = "darkbrown"
},
@@ -102017,13 +102009,25 @@
icon_state = "dark"
},
/area/station/engineering/control)
-"xCH" = (
-/obj/structure/rack,
-/obj/effect/spawner/random/maintenance,
-/turf/simulated/floor/plating{
- icon_state = "asteroidplating"
+"xCu" = (
+/obj/machinery/door/airlock/public/glass{
+ name = "Walkway"
},
-/area/station/maintenance/port)
+/obj/machinery/door/firedoor,
+/obj/machinery/door/poddoor/preopen{
+ id_tag = "servlockdown";
+ layer = 2.6;
+ name = "Service Lockdown"
+ },
+/obj/structure/disposalpipe/segment{
+ color = "#954535"
+ },
+/obj/effect/turf_decal/caution/red,
+/turf/simulated/floor/plasteel{
+ dir = 8;
+ icon_state = "neutralcorner"
+ },
+/area/station/hallway/spacebridge/sercom)
"xCR" = (
/obj/machinery/computer/security/telescreen/entertainment,
/turf/simulated/mineral/ancient,
@@ -102400,13 +102404,6 @@
/obj/machinery/light/small,
/turf/simulated/floor/plating/asteroid/ancient,
/area/station/maintenance/port)
-"xHt" = (
-/obj/structure/chair/office/dark{
- dir = 4
- },
-/obj/effect/landmark/start/detective,
-/turf/simulated/floor/carpet,
-/area/station/security/detective)
"xHF" = (
/obj/structure/cable/orange{
d1 = 4;
@@ -103232,17 +103229,6 @@
icon_state = "whitepurple"
},
/area/station/maintenance/apmaint)
-"xTG" = (
-/obj/machinery/requests_console/directional/south,
-/obj/structure/cable/orange{
- d1 = 4;
- d2 = 8;
- icon_state = "4-8"
- },
-/turf/simulated/floor/plasteel{
- icon_state = "grimy"
- },
-/area/station/security/detective)
"xTL" = (
/turf/simulated/floor/plasteel{
icon_state = "white"
@@ -113294,7 +113280,7 @@ rho
uSf
ygl
wzC
-mgq
+fPD
aXn
aXn
aXn
@@ -113551,7 +113537,7 @@ aXn
wGX
ygl
wzC
-xCH
+inP
aXn
aXn
aXn
@@ -114587,7 +114573,7 @@ eHn
ohJ
gUw
xZV
-eTI
+ljz
iuf
mkL
aXn
@@ -115104,7 +115090,7 @@ aXn
aXn
dLa
hwS
-eTI
+ljz
kad
uCK
aXn
@@ -116086,7 +116072,7 @@ eHu
aXn
aXn
aXn
-xCH
+inP
eCI
ltk
wzC
@@ -117875,7 +117861,7 @@ uCK
aXn
aXn
hvI
-dcR
+eTI
pAV
pXy
dHZ
@@ -119922,7 +119908,7 @@ aXn
aXn
eCI
pDl
-xCH
+inP
aXn
aXn
ock
@@ -120156,8 +120142,8 @@ chV
evL
qwd
pPN
-xHt
-xTG
+fvV
+dkb
emw
abW
nxA
@@ -122795,7 +122781,7 @@ btd
btd
uql
cBs
-nsy
+joS
cBs
cBs
biB
@@ -122998,7 +122984,7 @@ bpf
pbY
pbY
pbY
-gEI
+xCu
abT
jSU
grv
@@ -123052,9 +123038,9 @@ cuk
prN
mcu
pcu
-kAT
+jeu
jKU
-sNb
+nsy
biB
hqe
btd
@@ -123829,7 +123815,7 @@ biB
biB
xNP
biB
-eTe
+kAT
kDy
biB
etV
@@ -124344,7 +124330,7 @@ glI
gIv
uCO
noy
-olh
+tDi
nWX
qxR
btd
@@ -124603,7 +124589,7 @@ lJR
lJR
btd
pNE
-htz
+mgq
btd
cEM
eQC
@@ -125364,11 +125350,11 @@ muv
lYO
riS
mcu
-aUB
-aUB
-aUB
-hpP
uQB
+uQB
+uQB
+hpP
+tMD
haI
lUc
xAS
@@ -125621,7 +125607,7 @@ baF
jUW
fPp
cxx
-lhc
+htz
xnz
wFD
rxy
diff --git a/_maps/map_files/stations/deltastation.dmm b/_maps/map_files/stations/deltastation.dmm
index 18e3bccec2b..d99242fca89 100644
--- a/_maps/map_files/stations/deltastation.dmm
+++ b/_maps/map_files/stations/deltastation.dmm
@@ -2805,10 +2805,9 @@
},
/area/station/maintenance/fore2)
"aqn" = (
-/obj/structure/rack,
-/obj/item/crowbar,
-/obj/effect/spawner/random/maintenance,
/obj/effect/decal/cleanable/dirt,
+/obj/effect/spawner/random/storage,
+/obj/effect/spawner/random/maintenance,
/turf/simulated/floor/plasteel{
icon_state = "neutral"
},
@@ -17818,12 +17817,12 @@
/area/station/service/kitchen)
"bdN" = (
/obj/machinery/alarm/directional/west,
-/obj/structure/rack,
/obj/item/stack/packageWrap,
/obj/item/hand_labeler,
/obj/item/book/manual/wiki/chef_recipes,
/obj/effect/turf_decal/delivery/hollow,
/obj/item/wrench,
+/obj/structure/shelf/service,
/turf/simulated/floor/plasteel{
icon_state = "white"
},
@@ -20864,7 +20863,6 @@
},
/area/station/security/processing)
"bme" = (
-/obj/structure/rack,
/obj/item/gun/energy/laser{
pixel_x = 3;
pixel_y = 3
@@ -20875,6 +20873,7 @@
pixel_y = -3
},
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel/dark,
/area/station/security/armory/secure)
"bmg" = (
@@ -21366,7 +21365,6 @@
name = "west bump";
pixel_x = -30
},
-/obj/structure/rack,
/obj/item/storage/toolbox/emergency{
pixel_x = 3;
pixel_y = -4
@@ -21377,6 +21375,7 @@
/obj/item/pickaxe,
/obj/item/pickaxe,
/obj/effect/turf_decal/delivery/hollow,
+/obj/structure/shelf/supply,
/turf/simulated/floor/plasteel,
/area/station/supply/miningdock)
"bnk" = (
@@ -22776,7 +22775,6 @@
},
/area/station/security/processing)
"bqW" = (
-/obj/structure/rack,
/obj/item/gun/projectile/shotgun/riot{
pixel_x = 3;
pixel_y = 3
@@ -22787,6 +22785,7 @@
pixel_y = -3
},
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel/dark,
/area/station/security/armory/secure)
"bqX" = (
@@ -27819,7 +27818,6 @@
},
/area/station/public/storage/tools)
"bDP" = (
-/obj/structure/table/reinforced,
/obj/item/stack/rods,
/obj/item/stack/cable_coil/random,
/obj/item/stack/cable_coil/random,
@@ -27829,6 +27827,7 @@
icon_state = "0-4"
},
/obj/effect/turf_decal/delivery/hollow,
+/obj/structure/shelf,
/turf/simulated/floor/plasteel,
/area/station/public/storage/tools)
"bDQ" = (
@@ -28504,7 +28503,6 @@
/turf/simulated/floor/carpet,
/area/station/command/bridge)
"bFL" = (
-/obj/structure/rack,
/obj/item/storage/toolbox/emergency,
/obj/item/wrench,
/obj/machinery/light/small,
@@ -28512,6 +28510,7 @@
pixel_y = -3
},
/obj/item/multitool/command,
+/obj/structure/shelf/command,
/turf/simulated/floor/plasteel{
dir = 10;
icon_state = "darkblue"
@@ -30523,7 +30522,6 @@
/turf/simulated/floor/plasteel/dark,
/area/station/engineering/tech_storage)
"bKA" = (
-/obj/structure/rack,
/obj/item/book/manual/wiki/hacking,
/obj/item/book/manual/wiki/engineering_guide,
/obj/item/book/manual/wiki/engineering_construction,
@@ -30531,6 +30529,7 @@
pixel_x = -32
},
/obj/effect/turf_decal/delivery/hollow,
+/obj/structure/shelf,
/turf/simulated/floor/plasteel,
/area/station/public/storage/tools)
"bKB" = (
@@ -38570,12 +38569,12 @@
},
/area/station/security/evidence)
"cgp" = (
-/obj/structure/table,
/obj/item/hand_labeler,
/obj/item/storage/box/evidence,
/obj/item/storage/box/evidence,
/obj/item/pen,
/obj/machinery/firealarm/directional/south,
+/obj/structure/shelf/security,
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
@@ -44755,11 +44754,11 @@
/turf/simulated/floor/plating/airless,
/area/station/engineering/control)
"cxH" = (
-/obj/structure/rack,
/obj/item/clothing/gloves/color/black,
/obj/item/wrench,
/obj/item/clothing/glasses/meson/engine,
/obj/effect/turf_decal/delivery/hollow,
+/obj/structure/shelf/engineering,
/turf/simulated/floor/plasteel,
/area/station/engineering/hardsuitstorage)
"cxI" = (
@@ -46961,8 +46960,8 @@
/turf/simulated/floor/plasteel/dark,
/area/station/ai_monitored/storage/eva)
"cDP" = (
-/obj/structure/rack,
/obj/machinery/light/small,
+/obj/structure/shelf,
/turf/simulated/floor/plating,
/area/station/maintenance/port)
"cDQ" = (
@@ -71516,7 +71515,6 @@
},
/area/station/hallway/secondary/exit)
"ibR" = (
-/obj/structure/rack,
/obj/item/gun/energy/gun{
pixel_x = 3;
pixel_y = 3
@@ -71532,6 +71530,7 @@
pixel_x = -3;
pixel_y = -3
},
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel/dark,
/area/station/security/armory/secure)
"ibT" = (
@@ -73048,8 +73047,8 @@
},
/area/station/hallway/primary/central/nw)
"iXL" = (
-/obj/structure/rack,
/obj/effect/spawner/random/maintenance,
+/obj/effect/spawner/random/storage,
/turf/simulated/floor/plating,
/area/station/maintenance/fsmaint)
"iXM" = (
@@ -79061,7 +79060,6 @@
/turf/simulated/floor/plasteel,
/area/station/maintenance/port2)
"mEk" = (
-/obj/structure/rack,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/obj/item/gun/energy/disabler{
pixel_x = 3;
@@ -79072,6 +79070,7 @@
pixel_x = -3;
pixel_y = -3
},
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel/dark,
/area/station/security/armory/secure)
"mEu" = (
@@ -85947,7 +85946,6 @@
},
/area/station/medical/storage)
"qys" = (
-/obj/structure/table/glass,
/obj/item/storage/box/syringes{
pixel_x = 4;
pixel_y = 4
@@ -85957,6 +85955,7 @@
name = "east bump";
pixel_x = 28
},
+/obj/structure/shelf/medbay,
/turf/simulated/floor/plasteel{
dir = 4;
icon_state = "whiteblue"
@@ -95004,6 +95003,11 @@
/obj/item/weldingtool/research,
/turf/simulated/floor/plasteel/white,
/area/station/science/explab)
+"vys" = (
+/obj/effect/spawner/random/maintenance,
+/obj/effect/spawner/random/storage,
+/turf/simulated/floor/plating,
+/area/station/maintenance/port)
"vyO" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
@@ -119857,7 +119861,7 @@ cie
cie
cie
bXU
-jJj
+vys
drn
dhG
cHA
diff --git a/_maps/map_files/stations/metastation.dmm b/_maps/map_files/stations/metastation.dmm
index 744fe6d45ab..8b402a5b12f 100644
--- a/_maps/map_files/stations/metastation.dmm
+++ b/_maps/map_files/stations/metastation.dmm
@@ -4770,11 +4770,11 @@
},
/area/station/security/permabrig)
"aBx" = (
-/obj/structure/rack,
/obj/structure/reagent_dispensers/peppertank{
pixel_x = -32
},
/obj/item/gun/energy/ionrifle,
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 4;
icon_state = "darkred"
@@ -5853,7 +5853,6 @@
/turf/simulated/floor/plasteel,
/area/station/engineering/control)
"aGb" = (
-/obj/structure/table,
/obj/effect/turf_decal/delivery/hollow,
/obj/item/storage/belt/utility,
/obj/item/storage/belt/utility,
@@ -5861,6 +5860,7 @@
/obj/item/clothing/glasses/meson,
/obj/item/clothing/glasses/meson,
/obj/item/clothing/glasses/meson,
+/obj/structure/shelf/engineering,
/turf/simulated/floor/plasteel,
/area/station/engineering/control)
"aGc" = (
@@ -7944,7 +7944,6 @@
/turf/simulated/floor/plasteel,
/area/station/public/construction)
"aMN" = (
-/obj/structure/rack,
/obj/item/gun/energy/gun{
pixel_y = 6
},
@@ -7952,6 +7951,7 @@
pixel_y = 3
},
/obj/item/gun/energy/gun,
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 4;
icon_state = "darkred"
@@ -15477,6 +15477,10 @@
name = "south bump";
pixel_y = -28
},
+/obj/item/destTagger{
+ pixel_x = 4;
+ pixel_y = 3
+ },
/turf/simulated/floor/plasteel{
dir = 1;
icon_state = "brown"
@@ -15597,7 +15601,6 @@
/turf/simulated/floor/plating,
/area/station/maintenance/maintcentral)
"bjd" = (
-/obj/structure/rack,
/obj/item/stack/packageWrap{
pixel_x = 2;
pixel_y = -3
@@ -15616,10 +15619,7 @@
},
/obj/item/stack/wrapping_paper,
/obj/item/stack/wrapping_paper,
-/obj/item/destTagger{
- pixel_x = 4;
- pixel_y = 3
- },
+/obj/structure/shelf/supply,
/turf/simulated/floor/plasteel{
dir = 1;
icon_state = "brown"
@@ -21394,7 +21394,6 @@
/area/station/command/bridge)
"byx" = (
/obj/machinery/light,
-/obj/structure/rack,
/obj/item/storage/toolbox/emergency,
/obj/item/storage/toolbox/emergency{
pixel_x = -2;
@@ -21407,6 +21406,7 @@
pixel_y = -28
},
/obj/item/multitool/command,
+/obj/structure/shelf/command,
/turf/simulated/floor/plasteel{
dir = 1;
icon_state = "darkblue"
@@ -29611,11 +29611,11 @@
pixel_x = -2;
pixel_y = -2
},
-/obj/structure/table/reinforced,
/obj/machinery/requests_console/directional/north,
/obj/machinery/light{
dir = 1
},
+/obj/structure/shelf/medbay,
/turf/simulated/floor/plasteel{
icon_state = "whitebluefull"
},
@@ -30001,7 +30001,7 @@
/turf/simulated/floor/plating,
/area/station/maintenance/port)
"cdG" = (
-/obj/structure/rack,
+/obj/effect/spawner/random/storage,
/obj/effect/spawner/random/maintenance,
/turf/simulated/floor/plating,
/area/station/maintenance/port)
@@ -30222,7 +30222,6 @@
/obj/structure/sign/poster/official/random{
pixel_y = -32
},
-/obj/structure/table/glass,
/obj/item/reagent_containers/spray/plantbgone{
pixel_x = 2;
pixel_y = 6
@@ -30243,6 +30242,7 @@
/obj/machinery/atmospherics/unary/vent_pump/on{
dir = 1
},
+/obj/structure/shelf/service,
/turf/simulated/floor/plasteel,
/area/station/service/hydroponics)
"ceE" = (
@@ -44286,7 +44286,6 @@
},
/area/station/security/main)
"dCp" = (
-/obj/structure/rack,
/obj/machinery/firealarm/directional/west,
/obj/item/gun/energy/disabler{
pixel_y = 6
@@ -44295,6 +44294,7 @@
pixel_y = 3
},
/obj/item/gun/energy/disabler,
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 4;
icon_state = "darkred"
@@ -53420,7 +53420,6 @@
/turf/simulated/floor/plasteel,
/area/station/maintenance/starboard2)
"htP" = (
-/obj/structure/table,
/obj/item/reagent_containers/condiment/milk{
pixel_x = 6;
pixel_y = 8
@@ -53441,6 +53440,7 @@
/obj/structure/noticeboard{
pixel_y = 32
},
+/obj/structure/shelf,
/turf/simulated/floor/plasteel/dark,
/area/station/service/cafeteria)
"huo" = (
@@ -68122,7 +68122,6 @@
/turf/simulated/floor/plasteel,
/area/station/hallway/secondary/bridge)
"nxO" = (
-/obj/structure/rack,
/obj/item/gun/projectile/shotgun/riot{
pixel_y = 6
},
@@ -68136,6 +68135,7 @@
icon_state = "4-8"
},
/obj/machinery/alarm/directional/north,
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 6;
icon_state = "darkred"
@@ -70089,13 +70089,13 @@
/turf/simulated/floor/greengrid,
/area/station/science/robotics/chargebay)
"otp" = (
-/obj/structure/table,
/obj/structure/sign/poster/official/random{
pixel_y = -32
},
/obj/item/book/manual/wiki/sop_supply,
/obj/item/storage/belt/utility,
/obj/item/screwdriver/cargo,
+/obj/structure/shelf/supply,
/turf/simulated/floor/plasteel{
dir = 1;
icon_state = "brown"
@@ -70235,7 +70235,6 @@
/turf/simulated/floor/plasteel,
/area/station/security/permabrig)
"oAs" = (
-/obj/structure/table/reinforced,
/obj/machinery/firealarm/directional/west,
/obj/structure/extinguisher_cabinet{
name = "north bump";
@@ -70257,6 +70256,7 @@
pixel_y = 4
},
/obj/item/mecha_parts/core,
+/obj/structure/shelf/science,
/turf/simulated/floor/plasteel,
/area/station/science/robotics)
"oAL" = (
@@ -83284,7 +83284,6 @@
/turf/simulated/floor/carpet,
/area/station/legal/magistrate)
"uba" = (
-/obj/structure/rack,
/obj/item/gun/energy/laser{
pixel_y = 6
},
@@ -83292,6 +83291,7 @@
pixel_y = 3
},
/obj/item/gun/energy/laser,
+/obj/structure/gunrack,
/turf/simulated/floor/plasteel{
dir = 4;
icon_state = "darkred"
diff --git a/code/__DEFINES/dcs/movable_signals.dm b/code/__DEFINES/dcs/movable_signals.dm
index 2d197e1d0dd..c0ac15e5393 100644
--- a/code/__DEFINES/dcs/movable_signals.dm
+++ b/code/__DEFINES/dcs/movable_signals.dm
@@ -39,6 +39,8 @@
#define COMSIG_MOVABLE_POST_THROW "movable_post_throw"
///from base of datum/thrownthing/finalize(): (obj/thrown_object, datum/thrownthing) used for when a throw is finished
#define COMSIG_MOVABLE_THROW_LANDED "movable_throw_landed"
+///from base of atom/movable/shove_impact(): (mob/living/target, mob/living/attacker)
+#define COMSIG_MOVABLE_SHOVE_IMPACT "movable_shove_impact"
///from base of atom/movable/onTransitZ(): (old_z, new_z)
#define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit"
diff --git a/code/__DEFINES/dcs/obj_signals.dm b/code/__DEFINES/dcs/obj_signals.dm
index 1cee071550e..936667d709f 100644
--- a/code/__DEFINES/dcs/obj_signals.dm
+++ b/code/__DEFINES/dcs/obj_signals.dm
@@ -20,3 +20,16 @@
#define COMSIG_CURSED_SLOT_MACHINE_LOST "cursed_slot_machine_lost"
/// from /obj/structure/cursed_slot_machine/determine_victor() when someone finally wins.
#define COMSIG_GLOB_CURSED_SLOT_MACHINE_WON "cursed_slot_machine_won"
+
+
+// other subtypes
+
+/// from /datum/component/shelved/UnregisterFromParent(): (parent_uid)
+#define COMSIG_SHELF_ITEM_REMOVED "shelf_item_removed"
+/// from /datum/component/shelver/add_item(): (obj/item/to_add, placement_idx, list/position_details)
+#define COMSIG_SHELF_ITEM_ADDED "shelf_item_added"
+/// from Initialize on objects implementing /datum/component/shelved
+#define COMSIG_SHELF_ADDED_ON_MAPLOAD "shelf_added_on_mapload"
+/// from /datum/component/shelver/shelf_items()
+#define COMSIG_SHELF_ATTEMPT_PICKUP "shelf_attempt_pickup"
+ #define SHELF_PICKUP_FAILURE (1 << 0)
diff --git a/code/datums/components/shelved.dm b/code/datums/components/shelved.dm
new file mode 100644
index 00000000000..86692d7b6b1
--- /dev/null
+++ b/code/datums/components/shelved.dm
@@ -0,0 +1,290 @@
+#define MAX_SHELF_ITEMS 6
+
+/datum/component/shelver
+ /// A list whose keys are a 4-tuple of (left, bottom, right, top) bounding boxes to position details.
+ /// Position details include "x" and "y" as pixel offsets, and "layer" as appearance layer for a placed object.
+ var/list/placement_zones = list()
+ /// A list of slots, one per placement zone. Either empty, or containing the UID of the object in that place.
+ var/list/used_places = list()
+ /// A list of types which are are valid to place on this shelf.
+ var/list/allowed_types = list()
+ /// The default scale transformation for objects placed on the shelf.
+ var/default_scale = 0.70
+ /// The default rotation transformation for objects placed on the shelf.
+ var/default_rotation = 0
+ /// Whether objects auto-shelved by the component are placed in random order on the shelf.
+ var/random_pickup_locations = FALSE
+
+/datum/component/shelver/Initialize(list/allowed_types_ = null, random_pickup_locations_ = FALSE)
+ if(!isstructure(parent))
+ return COMPONENT_INCOMPATIBLE
+ used_places.len = length(placement_zones)
+ if(length(allowed_types_))
+ allowed_types += allowed_types_
+ random_pickup_locations = random_pickup_locations_
+
+/datum/component/shelver/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_SHELF_ATTEMPT_PICKUP, PROC_REF(on_shelf_attempt_pickup))
+ RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, PROC_REF(on_attackby))
+ RegisterSignal(parent, COMSIG_SHELF_ITEM_REMOVED, PROC_REF(on_shelf_item_removed))
+ RegisterSignal(parent, COMSIG_SHELF_ADDED_ON_MAPLOAD, PROC_REF(prepare_autoshelf))
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
+
+/datum/component/shelver/proc/on_examine(datum/source, mob/user, list/examine_list)
+ SIGNAL_HANDLER // COMSIG_PARENT_EXAMINE
+ var/list/results = list()
+ for(var/uid in used_places)
+ if(uid)
+ var/obj/item/I = locateUID(uid)
+ if(istype(I))
+ results += "\a [I.name]"
+
+ if(!length(results))
+ return
+
+ var/joined_results = english_list(results)
+ examine_list += "It currently holds: [joined_results]."
+
+/datum/component/shelver/proc/prepare_autoshelf()
+ SIGNAL_HANDLER // COMSIG_SHELF_ADDED_ON_MAPLOAD
+
+ // See /obj/structure/closet/Initialize for explanation of
+ // addtimer use here
+ addtimer(CALLBACK(src, PROC_REF(shelf_items)), 0)
+
+/datum/component/shelver/proc/shelf_items()
+ var/obj/structure/structure_parent = parent
+
+ var/list/nearby_empty_tiles = list()
+ for(var/turf/turf_in_view in view(2, get_turf(structure_parent)))
+ if(!isfloorturf(turf_in_view))
+ continue
+ for(var/turf/potential_blockage as anything in get_line(get_turf(structure_parent), turf_in_view))
+ if(!is_blocked_turf(potential_blockage, exclude_mobs = TRUE, excluded_objs = list(parent)))
+ nearby_empty_tiles += turf_in_view
+
+ var/itemcount = 1
+ for(var/obj/item/I in structure_parent.loc)
+ if(I.density || I.anchored || I == structure_parent)
+ continue
+ if(itemcount > MAX_SHELF_ITEMS)
+ // If we can't fit it on the shelf, toss it somewhere nearby
+ if(length(nearby_empty_tiles))
+ var/turf/T = pick(nearby_empty_tiles)
+ I.pixel_x = 0
+ I.pixel_y = 0
+ I.forceMove(T)
+ if(!(SEND_SIGNAL(structure_parent, COMSIG_SHELF_ATTEMPT_PICKUP, I) & SHELF_PICKUP_FAILURE))
+ itemcount++
+
+/datum/component/shelver/proc/on_shelf_attempt_pickup(datum/source, obj/item/to_add)
+ SIGNAL_HANDLER // COMSIG_SHELF_ATTEMPT_PICKUP
+
+ if(!istype(to_add))
+ return SHELF_PICKUP_FAILURE
+
+ var/free_slot = get_free_slot()
+ if(!free_slot)
+ return SHELF_PICKUP_FAILURE
+
+ var/coords = placement_zones[free_slot]
+ var/position_details = placement_zones[coords]
+ add_item(to_add, free_slot, position_details)
+
+/datum/component/shelver/proc/get_free_slot()
+ var/list/free_slots = list()
+ for(var/i in 1 to length(used_places))
+ if(!used_places[i])
+ free_slots += i
+
+ if(!length(free_slots))
+ return
+
+ if(random_pickup_locations)
+ return pick(free_slots)
+
+ return free_slots[1]
+
+/datum/component/shelver/proc/on_shelf_item_removed(datum/source, uid)
+ SIGNAL_HANDLER // COMSIG_SHELF_ITEM_REMOVED
+
+ for(var/i in 1 to length(used_places))
+ if(used_places[i] == uid)
+ used_places[i] = null
+
+ var/obj/O = parent
+ if(istype(O))
+ O.update_appearance(UPDATE_ICON)
+
+/datum/component/shelver/proc/on_attackby(datum/source, obj/item/attacker, mob/user, params)
+ SIGNAL_HANDLER // COMSIG_PARENT_ATTACKBY
+
+ if(isrobot(user))
+ return COMPONENT_NO_AFTERATTACK
+ if(attacker.flags & ABSTRACT)
+ return COMPONENT_NO_AFTERATTACK
+ if(user.a_intent == INTENT_HARM)
+ return
+
+ if(length(allowed_types) && !(attacker.type in allowed_types))
+ to_chat(user, "[attacker] won't fit on [parent]!")
+ return COMPONENT_NO_AFTERATTACK
+
+ var/list/PL = params2list(params)
+ var/icon_x = text2num(PL["icon-x"])
+ var/icon_y = text2num(PL["icon-y"])
+
+ var/i = 0
+ for(var/coords in placement_zones)
+ i++
+ if(icon_x >= coords[1] && icon_x <= coords[3] && icon_y >= coords[2] && icon_y <= coords[4])
+ if(used_places[i])
+ to_chat(user, "There's already something there on [parent].")
+ return COMPONENT_NO_AFTERATTACK
+
+ var/position_details = placement_zones[coords]
+ if(user.drop_item())
+ add_item(attacker, i, position_details)
+ user.visible_message(
+ "[user] places [attacker] on [parent].",
+ "You place [attacker] on [parent].",
+ )
+ return COMPONENT_NO_AFTERATTACK
+
+/**
+ * Add an item to the shelf.
+ *
+ * Arguments:
+ * * to_add - The item to add. Adding will fail if not an `/obj/item`.
+ * * placement_idx - The slot on the shelf to add the item to.
+ * * position_details - A list containing the "x" and "y" pixel offsets of the position, and the "layer" the object will be set to, if applicable.
+ */
+/datum/component/shelver/proc/add_item(obj/item/to_add, placement_idx, list/position_details)
+ if(!istype(to_add))
+ return
+ to_add.forceMove(get_turf(parent))
+ to_add.AddComponent(/datum/component/shelved, parent)
+ to_add.pixel_x = position_details["x"]
+ to_add.pixel_y = position_details["y"]
+ to_add.appearance_flags |= PIXEL_SCALE
+ if("layer" in position_details)
+ to_add.layer = position_details["layer"]
+ used_places[placement_idx] = to_add.UID()
+ var/obj/O = parent
+ if(istype(O))
+ O.update_appearance(UPDATE_ICON)
+
+ if(default_scale)
+ to_add.transform *= default_scale
+ if(default_rotation)
+ to_add.transform = turn(to_add.transform, default_rotation)
+
+ SEND_SIGNAL(to_add, COMSIG_SHELF_ITEM_ADDED, default_scale)
+
+/datum/component/shelver/basic_shelf
+ placement_zones = list(
+ // Bottom Shelf
+ list(1, 1, 10, 16) = list("x" = -9, "y" = -5, "layer" = BELOW_OBJ_LAYER),
+ list(11, 1, 20, 16) = list("x" = 0, "y" = -5, "layer" = BELOW_OBJ_LAYER),
+ list(21, 1, 32, 16) = list("x" = 9, "y" = -5, "layer" = BELOW_OBJ_LAYER),
+
+ // Top Shelf
+ list(1, 17, 10, 32) = list("x" = -9, "y" = 9),
+ list(11, 17, 20, 32) = list("x" = 0, "y" = 9),
+ list(21, 17, 32, 32) = list("x" = 9, "y" = 9),
+ )
+
+/datum/component/shelver/gun_rack
+ placement_zones = list(
+ list(1, 1, 10, 32) = list("x" = -8, "y" = -1),
+ list(11, 1, 20, 32) = list("x" = 0, "y" = -1),
+ list(21, 1, 32, 32) = list("x" = 8, "y" = -1),
+ )
+ default_scale = 0.80
+ default_rotation = -90
+
+/// A component for items stored on shelves, propagated by [/datum/component/shelver] components.
+/datum/component/shelved
+ /// The UID of the object acting as the shelf
+ var/shelf_uid
+ /// A copy of the shelved object's original transform, to restore after removing from the shelf.
+ var/matrix/original_transform
+ /// A copy of the shelved object's original layer, to restore after removing from the shelf.
+ var/original_layer
+ /// A copy of the shelved object's original appearance flags, to restore after removing from the shelf.
+ var/original_appearance_flags
+
+/datum/component/shelved/Initialize(atom/shelf)
+ if(!isobj(parent))
+ return COMPONENT_INCOMPATIBLE
+ var/obj/O = parent
+
+ shelf_uid = shelf.UID()
+ original_transform = O.transform
+ original_layer = O.layer
+ original_appearance_flags = O.appearance_flags
+
+/datum/component/shelved/RegisterWithParent()
+ . = ..()
+ RegisterSignal(parent, COMSIG_ITEM_PICKUP, PROC_REF(on_item_pickup))
+ var/obj/shelf = locateUID(shelf_uid)
+ if(shelf)
+ RegisterSignal(shelf, COMSIG_MOVABLE_SHOVE_IMPACT, PROC_REF(on_movable_shove_impact))
+ RegisterSignal(shelf, COMSIG_ATOM_HITBY, PROC_REF(on_atom_hitby))
+ RegisterSignal(shelf, COMSIG_OBJ_DECONSTRUCT, PROC_REF(on_shelf_deconstruct))
+
+/datum/component/shelved/proc/on_shelf_deconstruct()
+ SIGNAL_HANDLER // COMSIG_OBJ_DECONSTRUCT
+ qdel(src)
+
+/datum/component/shelved/proc/on_item_pickup(obj/item/I, mob/user)
+ SIGNAL_HANDLER // COMSIG_ITEM_PICKUP
+ qdel(src)
+
+/datum/component/shelved/UnregisterFromParent()
+ . = ..()
+ var/obj/O = parent
+ O.transform = original_transform
+ O.layer = original_layer
+ O.appearance_flags = original_appearance_flags
+ O.pixel_x = 0
+ O.pixel_y = 0
+
+ var/obj/shelf = locateUID(shelf_uid)
+ if(istype(shelf))
+ UnregisterSignal(shelf, COMSIG_MOVABLE_SHOVE_IMPACT)
+ UnregisterSignal(shelf, COMSIG_ATOM_HITBY)
+
+ SEND_SIGNAL(shelf, COMSIG_SHELF_ITEM_REMOVED, parent.UID())
+
+/datum/component/shelved/proc/scatter()
+ var/list/clear_turfs = list()
+ var/obj/O = parent
+ for(var/turf/T in orange(1, get_turf(O)))
+ if(isfloorturf(T) && T != get_turf(O))
+ clear_turfs |= T
+
+ if(length(clear_turfs))
+ var/obj/shelf = locateUID(shelf_uid)
+ if(!isobj(shelf))
+ // not sure what else we can do here to clean up after ourselves
+ CRASH("received non-obj shelf with UID [shelf_uid]")
+
+ var/shelf_name = shelf ? "flies off [shelf]" : "falls down"
+ O.visible_message("[O] [shelf_name]!")
+ O.throw_at(pick(clear_turfs), 2, 3)
+ qdel(src)
+
+/datum/component/shelved/proc/on_movable_shove_impact(datum/source, atom/movable/target)
+ SIGNAL_HANDLER // COMSIG_MOVABLE_SHOVE_IMPACT
+ if(prob(50))
+ scatter()
+
+/datum/component/shelved/proc/on_atom_hitby(datum/source, mob/living/carbon/human/hitby)
+ SIGNAL_HANDLER // COMSIG_ATOM_HITBY
+ if(!istype(hitby))
+ return
+ if(prob(50))
+ scatter()
+
+#undef MAX_SHELF_ITEMS
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 3f6c50803ec..e6d9a5a3af3 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -661,6 +661,7 @@
/// called when a mob gets shoved into an items turf. false means the mob will be shoved backwards normally, true means the mob will not be moved by the disarm proc.
/atom/movable/proc/shove_impact(mob/living/target, mob/living/attacker)
+ SEND_SIGNAL(src, COMSIG_MOVABLE_SHOVE_IMPACT, target, attacker)
return FALSE
/**
diff --git a/code/game/objects/effects/spawners/random/furniture_spawners.dm b/code/game/objects/effects/spawners/random/furniture_spawners.dm
new file mode 100644
index 00000000000..f5c41a3e050
--- /dev/null
+++ b/code/game/objects/effects/spawners/random/furniture_spawners.dm
@@ -0,0 +1,18 @@
+/obj/effect/spawner/random/storage
+ name = "storage furniture spawner"
+ icon = 'icons/effects/random_spawners.dmi'
+ icon_state = "shelf"
+ layer = BELOW_OBJ_LAYER
+ loot = list(
+ list(
+ /obj/structure/shelf = 10,
+ /obj/structure/shelf/command,
+ /obj/structure/shelf/engineering,
+ /obj/structure/shelf/medbay,
+ /obj/structure/shelf/science,
+ /obj/structure/shelf/security,
+ /obj/structure/shelf/service,
+ /obj/structure/shelf/supply,
+ ),
+ /obj/structure/rack,
+ )
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 107beb35373..13fb3a5cf09 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -359,6 +359,9 @@
attackee.lip_color = colour
attackee.update_body()
+ play_spray_sound(user)
+
+/obj/item/toy/crayon/spraycan/proc/play_spray_sound(mob/user)
playsound(user, 'sound/effects/spray.ogg', 5, TRUE, 5)
/obj/item/toy/crayon/spraycan/update_icon_state()
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index def83cd1a56..fe49e58b540 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -81,6 +81,8 @@ GLOBAL_LIST_INIT(metal_recipes, list(
new /datum/stack_recipe("firelock frame", /obj/structure/firelock_frame, 3, time = 5 SECONDS, one_per_turf = TRUE, on_floor = TRUE),
new /datum/stack_recipe("meatspike frame", /obj/structure/kitchenspike_frame, 5, time = 5 SECONDS, one_per_turf = TRUE, on_floor = TRUE),
new /datum/stack_recipe("reflector frame", /obj/structure/reflector, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_floor = TRUE),
+ new /datum/stack_recipe("storage shelf", /obj/structure/shelf, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_floor = TRUE),
+ new /datum/stack_recipe("gun rack", /obj/structure/gunrack, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_floor = TRUE),
null,
new /datum/stack_recipe_list("airlock assemblies", list(
new /datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 5 SECONDS, one_per_turf = TRUE, on_floor = TRUE),
diff --git a/code/game/objects/structures/shelves.dm b/code/game/objects/structures/shelves.dm
new file mode 100644
index 00000000000..602ba57fe2d
--- /dev/null
+++ b/code/game/objects/structures/shelves.dm
@@ -0,0 +1,139 @@
+GLOBAL_LIST_INIT(shelf_colors, list("basic", "sci", "sup", "serv", "med", "sec", "cmd", "engi"))
+
+/obj/structure/shelf
+ name = "shelf"
+ desc = "A piece of furniture used for vertical storage."
+ icon = 'icons/obj/structures/shelves.dmi'
+ icon_state = "shelf_basic"
+ layer = TABLE_LAYER
+ density = TRUE
+ anchored = TRUE
+ pass_flags_self = PASSTAKE
+ max_integrity = 80
+ /// The suffix of the icon state used for the shelf. Indexed into `GLOB.shelf_colors`.
+ var/shelf_style = "basic"
+ /// The current overlay of the top shelf. Used for interleaving objects and shelf layers for the illusion of depth.
+ var/image/shelf_overlay
+ COOLDOWN_DECLARE(spraypaint_cd)
+
+/obj/structure/shelf/Initialize(mapload)
+ . = ..()
+ var/area/A = get_area(src)
+ AddComponent(/datum/component/shelver/basic_shelf, random_pickup_locations_ = istype(A, /area/station/maintenance))
+ update_icon()
+ set_style(shelf_style)
+
+ if(mapload)
+ SEND_SIGNAL(src, COMSIG_SHELF_ADDED_ON_MAPLOAD)
+
+/obj/structure/shelf/attackby(obj/item/I, mob/living/user, params)
+ var/obj/item/toy/crayon/spraycan/spraycan = I
+ if(!istype(spraycan))
+ return ..()
+ if(spraycan.capped)
+ return ..()
+
+ if(!COOLDOWN_FINISHED(src, spraypaint_cd))
+ to_chat(user, "The paint on [src] is still drying!")
+ return
+
+ var/cur_idx = GLOB.shelf_colors.Find(shelf_style)
+ if(!cur_idx)
+ cur_idx = 1
+ cur_idx++
+ if(cur_idx > length(GLOB.shelf_colors))
+ cur_idx = 1
+ set_style(GLOB.shelf_colors[cur_idx])
+ spraycan.play_spray_sound(user)
+
+ // Tiny cooldown to prevent constant spamming of the action
+ COOLDOWN_START(src, spraypaint_cd, 1 SECONDS)
+
+/obj/structure/shelf/proc/set_style(new_style)
+ if(shelf_style == new_style && !isnull(shelf_overlay))
+ return
+ shelf_style = new_style
+ icon_state = "shelf_[shelf_style]"
+ // Don't think I can get away with both icon smoothing across tiles
+ // and dealing with this overlay shit
+ shelf_overlay = mutable_appearance('icons/obj/structures/shelves.dmi', "shelf_[shelf_style]-top")
+ shelf_overlay.layer = LOW_ITEM_LAYER
+ update_appearance(UPDATE_OVERLAYS)
+
+/obj/structure/shelf/update_overlays()
+ return list(shelf_overlay)
+
+/obj/structure/shelf/wrench_act(mob/living/user, obj/item/I)
+ . = TRUE
+ if(user.a_intent == INTENT_HELP)
+ return FALSE
+ if(!I.use_tool(src, user, 2.5 SECONDS, volume = I.tool_volume))
+ return
+
+ to_chat(user, "You disassemble [src].")
+ deconstruct()
+
+/obj/structure/shelf/deconstruct(disassembled)
+ new /obj/item/stack/sheet/metal(get_turf(src), 5)
+ return ..()
+
+/obj/structure/shelf/engineering
+ icon_state = "shelf_engi"
+ shelf_style = "engi"
+
+/obj/structure/shelf/medbay
+ icon_state = "shelf_med"
+ shelf_style = "med"
+
+/obj/structure/shelf/security
+ icon_state = "shelf_sec"
+ shelf_style = "sec"
+
+/obj/structure/shelf/service
+ icon_state = "shelf_serv"
+ shelf_style = "serv"
+
+/obj/structure/shelf/science
+ icon_state = "shelf_sci"
+ shelf_style = "sci"
+
+/obj/structure/shelf/command
+ icon_state = "shelf_cmd"
+ shelf_style = "cmd"
+
+/obj/structure/shelf/supply
+ icon_state = "shelf_sup"
+ shelf_style = "sup"
+
+/obj/structure/gunrack
+ name = "gun rack"
+ desc = "A rack for stowing firearms."
+ icon = 'icons/obj/structures.dmi'
+ icon_state = "gunrack"
+ layer = TABLE_LAYER
+ density = TRUE
+ anchored = TRUE
+ pass_flags_self = PASSTAKE
+ max_integrity = 80
+
+/obj/structure/gunrack/Initialize(mapload)
+ . = ..()
+ var/static/list/gun_subtypes = subtypesof(/obj/item/gun)
+ AddComponent(/datum/component/shelver/gun_rack, allowed_types_ = gun_subtypes)
+
+ if(mapload)
+ SEND_SIGNAL(src, COMSIG_SHELF_ADDED_ON_MAPLOAD)
+
+/obj/structure/gunrack/wrench_act(mob/living/user, obj/item/I)
+ . = TRUE
+ if(user.a_intent == INTENT_HELP)
+ return FALSE
+ if(!I.use_tool(src, user, 2.5 SECONDS, volume = I.tool_volume))
+ return
+
+ to_chat(user, "You disassemble [src].")
+ deconstruct()
+
+/obj/structure/shelf/deconstruct(disassembled)
+ new /obj/item/stack/sheet/metal(get_turf(src), 5)
+ return ..()
diff --git a/icons/effects/random_spawners.dmi b/icons/effects/random_spawners.dmi
index 325fb1ae5e0..fbf0d77c86e 100644
Binary files a/icons/effects/random_spawners.dmi and b/icons/effects/random_spawners.dmi differ
diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi
index 56837b40a89..8a21b505ce4 100644
Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ
diff --git a/icons/obj/structures/shelves.dmi b/icons/obj/structures/shelves.dmi
new file mode 100644
index 00000000000..fd3991998c4
Binary files /dev/null and b/icons/obj/structures/shelves.dmi differ
diff --git a/paradise.dme b/paradise.dme
index d8a427de2c0..378f9525bc6 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -447,6 +447,7 @@
#include "code\datums\components\proximity_monitor.dm"
#include "code\datums\components\radioactive.dm"
#include "code\datums\components\scope.dm"
+#include "code\datums\components\shelved.dm"
#include "code\datums\components\shielded.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\spawner.dm"
@@ -1030,6 +1031,7 @@
#include "code\game\objects\effects\spawners\windowspawner.dm"
#include "code\game\objects\effects\spawners\random\engineering_spawners.dm"
#include "code\game\objects\effects\spawners\random\food_spawners.dm"
+#include "code\game\objects\effects\spawners\random\furniture_spawners.dm"
#include "code\game\objects\effects\spawners\random\maint_loot_spawners.dm"
#include "code\game\objects\effects\spawners\random\misc_spawners.dm"
#include "code\game\objects\effects\spawners\random\random_spawner.dm"
@@ -1318,6 +1320,7 @@
#include "code\game\objects\structures\railings.dm"
#include "code\game\objects\structures\reflector.dm"
#include "code\game\objects\structures\safe.dm"
+#include "code\game\objects\structures\shelves.dm"
#include "code\game\objects\structures\signs.dm"
#include "code\game\objects\structures\snow.dm"
#include "code\game\objects\structures\spirit_board.dm"