diff --git a/_maps/map_files/Minerva/TGS_Minerva.dmm b/_maps/map_files/Minerva/TGS_Minerva.dmm
index 0e21ee4699242..2d528c6abefc6 100644
--- a/_maps/map_files/Minerva/TGS_Minerva.dmm
+++ b/_maps/map_files/Minerva/TGS_Minerva.dmm
@@ -13706,6 +13706,13 @@
},
/turf/open/floor/mainship/mono,
/area/mainship/hallways/hangar)
+"Oj" = (
+/obj/effect/turf_decal/warning_stripes/thin{
+ dir = 10
+ },
+/obj/structure/benchpress,
+/turf/open/floor/mainship/mono,
+/area/mainship/hallways/hangar)
"Ol" = (
/obj/structure/window/framed/mainship,
/obj/machinery/door/poddoor/mainship/ai/exterior{
@@ -26041,7 +26048,7 @@ OE
oI
dB
mA
-Wr
+Oj
eA
eA
eA
diff --git a/_maps/map_files/Pillar_of_Spring/TGS_Pillar_of_Spring.dmm b/_maps/map_files/Pillar_of_Spring/TGS_Pillar_of_Spring.dmm
index 3af419da4cca6..c7c0e484afc38 100644
--- a/_maps/map_files/Pillar_of_Spring/TGS_Pillar_of_Spring.dmm
+++ b/_maps/map_files/Pillar_of_Spring/TGS_Pillar_of_Spring.dmm
@@ -9500,10 +9500,8 @@
/turf/closed/wall/mainship,
/area/mainship/engineering/upper_engineering)
"mjo" = (
-/obj/effect/turf_decal/warning_stripes/thin{
- dir = 4
- },
-/obj/structure/punching_bag,
+/obj/machinery/camera/autoname/mainship,
+/obj/structure/benchpress,
/turf/open/floor/plating/mainship,
/area/mainship/shipboard/firing_range)
"mka" = (
@@ -12822,6 +12820,11 @@
/obj/machinery/light/mainship/small{
dir = 4
},
+/obj/structure/table/mainship/nometal,
+/obj/item/ammo_magazine/rifle,
+/obj/item/ammo_magazine/rifle,
+/obj/item/ammo_magazine/rifle,
+/obj/item/weapon/gun/rifle/m412,
/turf/open/floor/plating/mainship,
/area/mainship/shipboard/firing_range)
"qAM" = (
@@ -14778,11 +14781,10 @@
},
/area/mainship/squads/general)
"teh" = (
-/obj/structure/table/mainship/nometal,
-/obj/item/weapon/gun/rifle/m412,
-/obj/item/ammo_magazine/rifle,
-/obj/item/ammo_magazine/rifle,
-/obj/item/ammo_magazine/rifle,
+/obj/effect/turf_decal/warning_stripes/thin{
+ dir = 4
+ },
+/obj/structure/punching_bag,
/turf/open/floor/plating/mainship,
/area/mainship/shipboard/firing_range)
"tem" = (
@@ -59282,7 +59284,7 @@ hUz
hUz
imx
nJG
-teh
+bDv
aFl
bDv
uLb
@@ -59539,7 +59541,7 @@ esN
esN
unX
nJG
-pgv
+mjo
bDv
bDv
bDv
@@ -59796,9 +59798,9 @@ nWT
esN
unX
nJG
-mjo
-qAJ
kbW
+qAJ
+teh
kbW
kbW
vSE
diff --git a/_maps/map_files/Sulaco/TGS_Sulaco.dmm b/_maps/map_files/Sulaco/TGS_Sulaco.dmm
index 94729cff00af9..313bbcaf0cc49 100755
--- a/_maps/map_files/Sulaco/TGS_Sulaco.dmm
+++ b/_maps/map_files/Sulaco/TGS_Sulaco.dmm
@@ -15183,6 +15183,11 @@
dir = 9
},
/area/sulaco/research)
+"ifi" = (
+/turf/open/floor/tile/darkgreen/darkgreen2{
+ dir = 1
+ },
+/area/mainship/living/basketball)
"ifF" = (
/obj/effect/soundplayer,
/turf/closed/wall/mainship/gray,
@@ -19760,7 +19765,6 @@
/obj/machinery/light/mainship{
dir = 1
},
-/obj/structure/bed/chair/nometal,
/turf/open/floor/tile/darkgreen/darkgreen2{
dir = 1
},
@@ -21257,7 +21261,7 @@
},
/area/sulaco/hallway/central_hall)
"qoV" = (
-/obj/structure/bed/chair/nometal,
+/obj/structure/benchpress,
/turf/open/floor/tile/darkgreen/darkgreen2{
dir = 1
},
@@ -45529,7 +45533,7 @@ rVm
hMt
xHk
iVT
-qoV
+ifi
vIO
vIO
vIO
diff --git a/_maps/map_files/Theseus/TGS_Theseus.dmm b/_maps/map_files/Theseus/TGS_Theseus.dmm
index cda0e329e0b2f..0a000a5853340 100755
--- a/_maps/map_files/Theseus/TGS_Theseus.dmm
+++ b/_maps/map_files/Theseus/TGS_Theseus.dmm
@@ -352,6 +352,7 @@
"abs" = (
/obj/structure/closet,
/obj/item/toy/plush/lizard,
+/obj/machinery/firealarm,
/turf/open/floor/mainship/mono,
/area/mainship/living/starboard_emb)
"abt" = (
@@ -2510,11 +2511,6 @@
/obj/machinery/power/apc/mainship,
/turf/open/floor/mainship/mono,
/area/mainship/living/starboard_emb)
-"aZl" = (
-/obj/structure/closet,
-/obj/machinery/firealarm,
-/turf/open/floor/mainship/mono,
-/area/mainship/living/starboard_emb)
"aZD" = (
/obj/structure/disposalpipe/segment,
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer1,
@@ -3658,11 +3654,6 @@
dir = 4
},
/area/mainship/command/cic)
-"bkN" = (
-/obj/structure/closet,
-/obj/item/toy/plush/carp,
-/turf/open/floor/mainship/mono,
-/area/mainship/living/starboard_emb)
"bkO" = (
/obj/machinery/door_control/mainship/checkpoint{
dir = 8;
@@ -9430,11 +9421,7 @@
/turf/open/floor/mainship/mono,
/area/mainship/hull/port_hull)
"eWc" = (
-/obj/structure/closet,
-/obj/item/toy/inflatable_duck,
-/obj/structure/sign/poster{
- dir = 1
- },
+/obj/structure/benchpress,
/turf/open/floor/mainship/mono,
/area/mainship/living/starboard_emb)
"eWx" = (
@@ -58983,7 +58970,7 @@ nRj
aam
tDH
aXM
-aZl
+aXJ
cfe
adK
aiO
@@ -59497,7 +59484,7 @@ acz
aam
rbR
aXM
-bkN
+aXJ
aZJ
wKn
aJP
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index a8ca4d23fceb7..26ccdda476938 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -108,6 +108,7 @@
#define SHATTERING_ROAR_ABILITY_TRAIT "shattering_roar_ability_trait"
#define ZERO_FORM_BEAM_ABILITY_TRAIT "zero_form_beam_ability_trait"
#define VALHALLA_TRAIT "valhalla"
+#define WEIGHTBENCH_TRAIT "weightbench"
/// A trait given by any status effect
#define STATUS_EFFECT_TRAIT "status-effect"
@@ -137,6 +138,7 @@
#define TRAIT_TIME_SHIFTED "time_shifted"
#define TRAIT_LEASHED "leashed"
#define TRAIT_CAN_VENTCRAWL "can_ventcrawl"
+#define TRAIT_WORKED_OUT "worked_out" //user has a cqc buff from working out
/// Prevents usage of manipulation appendages (picking, holding or using items, manipulating storage).
#define TRAIT_HANDS_BLOCKED "handsblocked"
@@ -195,6 +197,8 @@
#define TRAIT_TURF_BULLET_MANIPULATION "bullet_manipulation" //This tile is doing something to projectile
// projectile traits
#define TRAIT_PROJ_HIT_SOMETHING "hit_something" //If projectile hit something on its path
+//structure traits
+#define BENCH_BEING_USED "bench_being_used"
// UI traits
/// Inability to access UI hud elements.
diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm
index 64da3bd12fb59..db8ccbac17b8b 100644
--- a/code/datums/looping_sounds/machinery_sounds.dm
+++ b/code/datums/looping_sounds/machinery_sounds.dm
@@ -48,3 +48,8 @@
mid_length = 6
end_sound = 'sound/mecha/overload_stop.ogg'
volume = 40
+
+/datum/looping_sound/benchpress_creak
+ mid_sounds = list('sound/machines/creak.ogg'=1)
+ mid_length = 8
+ volume = 60
diff --git a/code/game/objects/structures/benchpress.dm b/code/game/objects/structures/benchpress.dm
new file mode 100644
index 0000000000000..03912d0a626c9
--- /dev/null
+++ b/code/game/objects/structures/benchpress.dm
@@ -0,0 +1,126 @@
+/obj/structure/benchpress
+ name = "weight training bench"
+ desc = "Just looking at this thing makes you feel tired.
Left click to bench, right click to change weights."
+ icon = 'icons/obj/structures/benchpress.dmi'
+ icon_state = "benchpress_0"
+ base_icon_state = "benchpress"
+ density = FALSE
+ anchored = TRUE
+ pixel_x = -17
+ blocks_emissive = EMISSIVE_BLOCK_UNIQUE
+ var/datum/looping_sound/benchpress_creak/creak_loop
+ ///amount of plates we are using, used to keep track for animations
+ var/plates = 0
+
+/obj/structure/benchpress/Initialize(mapload)
+ . = ..()
+ creak_loop = new
+ update_icon()
+
+/obj/structure/benchpress/wrench_act(mob/living/user, obj/item/tool)
+ tool.play_tool_sound(src)
+ if(anchored)
+ balloon_alert(user, "unsecured")
+ anchored = FALSE
+ else
+ balloon_alert(user, "secured")
+ anchored = TRUE
+ return TRUE
+
+/obj/structure/benchpress/crowbar_act(mob/living/user, obj/item/tool)
+ if(anchored)
+ balloon_alert(user, "unsecure first!")
+ return FALSE
+ tool.play_tool_sound(src)
+ balloon_alert(user, "deconstructing...")
+ if(!do_after(user, 10 SECONDS, target = src))
+ return FALSE
+ new /obj/item/stack/sheet/metal(get_turf(src))
+ new /obj/item/stack/rods(get_turf(src))
+ new /obj/item/stack/rods(get_turf(src))
+ qdel(src)
+ return TRUE
+
+/obj/structure/benchpress/update_icon_state()
+ . = ..()
+ icon_state = HAS_TRAIT(src, BENCH_BEING_USED) ? "[base_icon_state]_u" : "[base_icon_state]_[plates]"
+
+/obj/structure/benchpress/update_overlays()
+ . = ..()
+
+ if(HAS_TRAIT(src, BENCH_BEING_USED))
+ . += mutable_appearance(icon, "[base_icon_state]_[plates]_anim", plane = GAME_PLANE, layer = ABOVE_MOB_LAYER, alpha = src.alpha)
+
+/obj/structure/benchpress/attack_hand_alternate(mob/living/user)
+ . = ..()
+ if(.)
+ return
+ if(HAS_TRAIT(src, BENCH_BEING_USED))
+ return
+ if(plates)
+ var/oldplates = plates
+ plates = 0
+ update_icon()
+ flick("unswap_[oldplates]", src)
+ return
+ var/list/radial_options = list(
+ "1" = image(icon = 'icons/obj/structures/benchpress.dmi', icon_state = "benchpress_1"),
+ "2" = image(icon = 'icons/obj/structures/benchpress.dmi', icon_state = "benchpress_2"),
+ "3" = image(icon = 'icons/obj/structures/benchpress.dmi', icon_state = "benchpress_3"),
+ "4" = image(icon = 'icons/obj/structures/benchpress.dmi', icon_state = "benchpress_4"),
+ "5" = image(icon = 'icons/obj/structures/benchpress.dmi', icon_state = "benchpress_5"),
+ )
+ var/choice = show_radial_menu(user, src, radial_options, null, 64, null, TRUE, TRUE)
+ plates = text2num(choice)
+ update_icon()
+ flick("swap_[plates]", src)
+
+
+
+/obj/structure/benchpress/attack_hand(mob/living/user, list/modifiers)
+ . = ..()
+ if(.)
+ return
+ if(HAS_TRAIT(src, BENCH_BEING_USED))
+ balloon_alert(user, "wait your turn!")
+ return
+ ADD_TRAIT(src, BENCH_BEING_USED, WEIGHTBENCH_TRAIT) // yea this is meh but IN_USE and interact code are a mess rn and too buggy so less sidestep it
+ update_icon()
+ user.setDir(SOUTH)
+ user.flags_atom |= DIRLOCK
+ ADD_TRAIT(user, TRAIT_IMMOBILE, WEIGHTBENCH_TRAIT)
+ user.forceMove(loc)
+ var/bragmessage = pick("pushing it to the limit","going into overdrive","burning with determination","rising up to the challenge", "getting strong now","getting ripped")
+ user.visible_message("[user] is [bragmessage]!")
+ addtimer(CALLBACK(src, PROC_REF(finish_press), user), 50)
+ creak_loop.start(src)
+
+///cleans up releases exerciser
+/obj/structure/benchpress/proc/finish_press(mob/user)
+ creak_loop.stop(src)
+ playsound(user, 'sound/machines/click.ogg', 60, TRUE)
+ REMOVE_TRAIT(src, BENCH_BEING_USED, WEIGHTBENCH_TRAIT)
+ user.flags_atom &= ~DIRLOCK
+ REMOVE_TRAIT(user, TRAIT_IMMOBILE, WEIGHTBENCH_TRAIT)
+ if(plates >= 5 && prob(10))
+ var/mob/living/carbon/human/breaker = user
+ var/datum/limb/broken = breaker.get_limb(pick("l_arm", "r_arm"))
+ broken.fracture()
+ return
+ if(!HAS_TRAIT(user, TRAIT_WORKED_OUT))
+ user.set_skills(user.skills.modifyRating(cqc=1))
+ ADD_TRAIT(user, TRAIT_WORKED_OUT, WEIGHTBENCH_TRAIT)
+ addtimer(CALLBACK(src, PROC_REF(undo_buff), WEAKREF(user)), 15 MINUTES)
+ update_icon()
+ var/finishmessage = pick("You feel stronger!","You feel like you're the boss of this gym!","You feel robust!","The challenge is real!")
+ to_chat(user, finishmessage)
+
+///proc to undo the cqc buff granted by the bench
+/obj/structure/benchpress/proc/undo_buff(datum/weakref/user_ref)
+ var/mob/user = user_ref.resolve()
+ if(!user)
+ return
+ REMOVE_TRAIT(user, TRAIT_WORKED_OUT, WEIGHTBENCH_TRAIT)
+ user.set_skills(user.skills.modifyRating(cqc=-1))
+ to_chat(user, span_boldnotice("You no longer feel as fit as you used to!"))
+
diff --git a/icons/obj/structures/benchpress.dmi b/icons/obj/structures/benchpress.dmi
new file mode 100644
index 0000000000000..9758a86709847
Binary files /dev/null and b/icons/obj/structures/benchpress.dmi differ
diff --git a/sound/machines/creak.ogg b/sound/machines/creak.ogg
new file mode 100644
index 0000000000000..edb9802b0888c
Binary files /dev/null and b/sound/machines/creak.ogg differ
diff --git a/tgmc.dme b/tgmc.dme
index 9add6f2c9d750..470479a66c8d3 100755
--- a/tgmc.dme
+++ b/tgmc.dme
@@ -933,6 +933,7 @@
#include "code\game\objects\structures\barricade.dm"
#include "code\game\objects\structures\barsign.dm"
#include "code\game\objects\structures\bedsheet_bin.dm"
+#include "code\game\objects\structures\benchpress.dm"
#include "code\game\objects\structures\bookcase.dm"
#include "code\game\objects\structures\cargo_container.dm"
#include "code\game\objects\structures\cas_plane_parts.dm"