diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index 1b8f8fe87be..1a4d34f0828 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -324,14 +324,23 @@ . = buckle_mob(M, check_loc = check_loc) if(.) - if(M == user) - M.visible_message(span_notice("[M] buckles [M.p_them()]self to [src]."),\ - span_notice("You buckle yourself to [src]."),\ - span_hear("You hear metal clanking.")) - else - M.visible_message(span_warning("[user] buckles [M] to [src]!"),\ - span_warning("[user] buckles you to [src]!"),\ - span_hear("You hear metal clanking.")) + buckle_feedback(M, user) + +/// Feedback displayed to nearby players after a mob is buckled to src. +/atom/movable/proc/buckle_feedback(mob/living/being_buckled, mob/buckler) + if(being_buckled == buckler) + buckler.visible_message( + span_notice("[buckler] buckles [buckler.p_them()]self to [src]."), + span_notice("You buckle yourself to [src]."), + span_hear("You hear metal clanking."), + ) + else + buckler.visible_message( + span_warning("[buckler] buckles [being_buckled] to [src]!"), + span_warning("[buckler] buckles you to [src]!"), + span_hear("You hear metal clanking."), + ) + /** * Handles a user unbuckling a mob from src and sends a visible_message * @@ -346,16 +355,24 @@ return var/mob/living/M = unbuckle_mob(buckled_mob) if(M) - if(M != user) - M.visible_message(span_notice("[user] unbuckles [M] from [src]."),\ - span_notice("[user] unbuckles you from [src]."),\ - span_hear("You hear metal clanking.")) - else - M.visible_message(span_notice("[M] unbuckles [M.p_them()]self from [src]."),\ - span_notice("You unbuckle yourself from [src]."),\ - span_hear("You hear metal clanking.")) + unbuckle_feedback(M, user) add_fingerprint(user) if(isliving(M.pulledby)) var/mob/living/L = M.pulledby L.set_pull_offsets(M, L.grab_state) return M + +/// Feedback displayed to nearby players after a mob is unbuckled from src. +/atom/movable/proc/unbuckle_feedback(mob/living/unbuckled_mob, mob/unbuckler) + if(unbuckled_mob == unbuckler) + unbuckler.visible_message( + span_notice("[unbuckler] unbuckles [unbuckler.p_them()]self from [src]."), + span_notice("You unbuckle yourself from [src]."), + span_hear("You hear metal clanking."), + ) + else + unbuckler.visible_message( + span_notice("[unbuckler] unbuckles [unbuckled_mob] from [src]."), + span_notice("[unbuckler] unbuckles you from [src]."), + span_hear("You hear metal clanking."), + ) diff --git a/code/game/objects/structures/beds_chairs/alien_nest.dm b/code/game/objects/structures/beds_chairs/alien_nest.dm index 47b1ab530d9..1f77227a8be 100644 --- a/code/game/objects/structures/beds_chairs/alien_nest.dm +++ b/code/game/objects/structures/beds_chairs/alien_nest.dm @@ -21,6 +21,34 @@ return ..() +/obj/structure/bed/nest/buckle_feedback(mob/living/being_buckled, mob/buckler) + if(being_buckled == buckler) + being_buckled.visible_message( + span_notice("[buckler] lays down on [src], wrapping [buckler.p_them()]self in a thick, sticky resin."), + span_notice("You lay down on [src], wrapping yourself in a thick, sticky resin."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_buckled.visible_message( + span_notice("[buckler] lays [being_buckled] down on [src], wrapping [being_buckled.p_them()] in a thick, sticky resin."), + span_notice("[buckler] lays you down on [src], wrapping you in a thick, sticky resin."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + +/obj/structure/bed/nest/unbuckle_feedback(mob/living/being_unbuckled, mob/unbuckler) + if(being_unbuckled == unbuckler) + being_unbuckled.visible_message( + span_notice("[unbuckler] pulls [unbuckler.p_them()]self free from the sticky nest!"), + span_notice("You pull yourself free from the sticky nest!"), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_unbuckled.visible_message( + span_notice("[unbuckler] pulls [being_unbuckled] free from the sticky nest!"), + span_notice("[unbuckler] pulls you free from the sticky nest!"), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + /obj/structure/bed/nest/user_unbuckle_mob(mob/living/captive, mob/living/hero) if(!length(buckled_mobs)) return diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm index 68833f91c0d..6b687c8a4b0 100644 --- a/code/game/objects/structures/beds_chairs/bed.dm +++ b/code/game/objects/structures/beds_chairs/bed.dm @@ -38,6 +38,40 @@ update_buckle_vars(dir) register_context() +/obj/structure/bed/buckle_feedback(mob/living/being_buckled, mob/buckler) + if(HAS_TRAIT(being_buckled, TRAIT_RESTRAINED)) + return ..() + + if(being_buckled == buckler) + being_buckled.visible_message( + span_notice("[buckler] lays down on [src]."), + span_notice("You lay down on [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_buckled.visible_message( + span_notice("[buckler] lays [being_buckled] down on [src]."), + span_notice("[buckler] lays you down on [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + +/obj/structure/bed/unbuckle_feedback(mob/living/being_unbuckled, mob/unbuckler) + if(HAS_TRAIT(being_unbuckled, TRAIT_RESTRAINED)) + return ..() + + if(being_unbuckled == unbuckler) + being_unbuckled.visible_message( + span_notice("[unbuckler] gets up from [src]."), + span_notice("You get up from [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_unbuckled.visible_message( + span_notice("[unbuckler] pulls [being_unbuckled] up from [src]."), + span_notice("[unbuckler] pulls you up from [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + /obj/structure/bed/examine(mob/user) . = ..() if (can_deconstruct) diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 6c377582555..f01698e6bb8 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -33,6 +33,40 @@ if(can_buckle && fishing_modifier) AddComponent(/datum/component/adjust_fishing_difficulty, fishing_modifier) +/obj/structure/chair/buckle_feedback(mob/living/being_buckled, mob/buckler) + if(HAS_TRAIT(being_buckled, TRAIT_RESTRAINED)) + return ..() + + if(being_buckled == buckler) + being_buckled.visible_message( + span_notice("[buckler] sits down on [src]."), + span_notice("You sit down on [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_buckled.visible_message( + span_notice("[buckler] sits [being_buckled] down on [src]."), + span_notice("[buckler] sits you down on [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + +/obj/structure/chair/unbuckle_feedback(mob/living/being_unbuckled, mob/unbuckler) + if(HAS_TRAIT(being_unbuckled, TRAIT_RESTRAINED)) + return ..() + + if(being_unbuckled == unbuckler) + being_unbuckled.visible_message( + span_notice("[unbuckler] stands up from [src]."), + span_notice("You stand up from [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_unbuckled.visible_message( + span_notice("[unbuckler] stands [being_unbuckled] up from [src]."), + span_notice("[unbuckler] stands you up from [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + /obj/structure/chair/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents) if(same_z_layer || !has_armrest) return ..() @@ -222,6 +256,9 @@ buildstacktype = /obj/item/stack/sheet/mineral/titanium buckle_sound = SFX_SEATBELT_BUCKLE unbuckle_sound = SFX_SEATBELT_UNBUCKLE + resistance_flags = FIRE_PROOF + max_integrity = 120 + custom_materials = list(/datum/material/titanium = SHEET_MATERIAL_AMOUNT) /obj/structure/chair/comfy/shuttle/electrify_self(obj/item/assembly/shock_kit/input_shock_kit, mob/user, list/overlays_from_child_procs) if(!overlays_from_child_procs) @@ -230,6 +267,42 @@ overlays_from_child_procs = list(echair_overlay) . = ..() +/obj/structure/chair/comfy/shuttle/buckle_feedback(mob/living/being_buckled, mob/buckler) + if(being_buckled == buckler) + being_buckled.visible_message( + span_notice("[buckler] sits down on [src], pulling the overhead restraint down to secure [buckler.p_them()]self."), + span_notice("You sit down on [src], pulling the overhead restraint down to secure yourself."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_buckled.visible_message( + span_notice("[buckler] sits [being_buckled] down on [src], pulling the overhead restraint down to secure [buckler.p_them()]."), + span_notice("[buckler] sits you down on [src], pulling the overhead restraint down to secure you."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + +/obj/structure/chair/comfy/shuttle/unbuckle_feedback(mob/living/being_unbuckled, mob/unbuckler) + if(being_unbuckled == unbuckler) + being_unbuckled.visible_message( + span_notice("[unbuckler] flips the overhead restraint up, standing up from [src]."), + span_notice("You flip the overhead restraint up, standing up from [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_unbuckled.visible_message( + span_notice("[unbuckler] flips the overhead restraint up, standing [being_unbuckled] up from [src]."), + span_notice("[unbuckler] flips the overhead restraint up, standing you up from [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + +/obj/structure/chair/comfy/shuttle/update_overlays() + . = ..() + if(has_buckled_mobs()) + . += mutable_appearance(icon, "[icon_state]_down_front", ABOVE_MOB_LAYER + 0.01) + . += mutable_appearance(icon, "[icon_state]_down_behind", src.layer + 0.01) + else + . += mutable_appearance(icon, "[icon_state]_up", src.layer + 0.01) + /obj/structure/chair/comfy/shuttle/tactical name = "tactical chair" @@ -618,3 +691,76 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) desc = "Oh, so this is like the fucked up Monopoly rules where there are no rules and you can pick up and place the musical chairs as you please." particles = new /particles/musical_notes origin_type = /obj/structure/chair/musical + +/obj/structure/handrail + name = "handrail" + desc = "Hold on tight!" + icon = 'icons/obj/handrail.dmi' + icon_state = "handrail" + anchored = TRUE + can_buckle = TRUE + buckle_lying = NO_BUCKLE_LYING + resistance_flags = FIRE_PROOF + max_integrity = 50 + custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT) + layer = OBJ_LAYER + +/obj/structure/handrail/attack_hand(mob/living/user, list/modifiers) + return ..() || mouse_buckle_handling(user, user) + +/obj/structure/handrail/is_user_buckle_possible(mob/living/target, mob/user, check_loc = TRUE) + return ..() && user == target && !HAS_TRAIT(target, TRAIT_HANDS_BLOCKED) + +/obj/structure/handrail/post_buckle_mob(mob/living/buckled_mob) + RegisterSignal(buckled_mob, SIGNAL_ADDTRAIT(TRAIT_HANDS_BLOCKED), PROC_REF(stop_buckle)) + + var/z_offset = 0 + var/w_offset = 0 + if(dir & NORTH) + z_offset = -4 + else if(dir & SOUTH) + z_offset = 8 + if(dir & EAST) + w_offset = -8 + else if(dir & WEST) + w_offset = 8 + + buckled_mob.add_offsets(type, z_add = z_offset, w_add = w_offset) + +/obj/structure/handrail/post_unbuckle_mob(mob/living/unbuckled_mob) + UnregisterSignal(unbuckled_mob, SIGNAL_ADDTRAIT(TRAIT_HANDS_BLOCKED)) + unbuckled_mob.remove_offsets(type) + +/obj/structure/handrail/proc/stop_buckle(mob/living/source, ...) + SIGNAL_HANDLER + source.visible_message( + span_warning("[source] loses [source.p_their()] grip on [src]!"), + span_warning("You lose your grip on [src]!"), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + vision_distance = COMBAT_MESSAGE_RANGE, + ) + unbuckle_mob(source, TRUE, TRUE) + +/obj/structure/handrail/buckle_feedback(mob/living/being_buckled, mob/buckler) + buckler.visible_message( + span_notice("[buckler] grabs [src] tight, keeping [buckler.p_them()]self upright."), + span_notice("You grab [src] tight, keeping yourself upright."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + vision_distance = COMBAT_MESSAGE_RANGE, + ) + +/obj/structure/handrail/unbuckle_feedback(mob/living/being_unbuckled, mob/unbuckler) + if(being_unbuckled == unbuckler) + being_unbuckled.visible_message( + span_notice("[unbuckler] lets go of [src]."), + span_notice("You let go of [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + vision_distance = COMBAT_MESSAGE_RANGE, + ) + else + being_unbuckled.visible_message( + span_warning("[unbuckler] forces [being_unbuckled] to let go of [src]!"), + span_warning("[unbuckler] forces you to let go of [src]!"), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + vision_distance = COMBAT_MESSAGE_RANGE, + ) diff --git a/code/game/objects/structures/gym/weight_machine.dm b/code/game/objects/structures/gym/weight_machine.dm index 438196e9b60..c9b59efd89f 100644 --- a/code/game/objects/structures/gym/weight_machine.dm +++ b/code/game/objects/structures/gym/weight_machine.dm @@ -71,6 +71,40 @@ QDEL_NULL(weight_action) return ..() +/obj/structure/weightmachine/buckle_feedback(mob/living/being_buckled, mob/buckler) + if(HAS_TRAIT(being_buckled, TRAIT_RESTRAINED)) + return ..() + + if(being_buckled == buckler) + being_buckled.visible_message( + span_notice("[buckler] lays down on [src]."), + span_notice("You lay down on [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_buckled.visible_message( + span_notice("[buckler] lays [being_buckled] down on [src]."), + span_notice("[buckler] lays you down on [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + +/obj/structure/weightmachine/unbuckle_feedback(mob/living/being_unbuckled, mob/unbuckler) + if(HAS_TRAIT(being_unbuckled, TRAIT_RESTRAINED)) + return ..() + + if(being_unbuckled == unbuckler) + being_unbuckled.visible_message( + span_notice("[unbuckler] gets up from [src]."), + span_notice("You get up from [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_unbuckled.visible_message( + span_notice("[unbuckler] pulls [being_unbuckled] up from [src]."), + span_notice("[unbuckler] pulls you up from [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + /obj/structure/weightmachine/buckle_mob(mob/living/buckled, force, check_loc) . = ..() weight_action.Grant(buckled) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 553fafe60ce..c07c5c35273 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -1077,6 +1077,40 @@ breath_mask = null return ..() +/obj/structure/table/optable/buckle_feedback(mob/living/being_buckled, mob/buckler) + if(HAS_TRAIT(being_buckled, TRAIT_RESTRAINED)) + return ..() + + if(being_buckled == buckler) + being_buckled.visible_message( + span_notice("[buckler] lays down on [src]."), + span_notice("You lay down on [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_buckled.visible_message( + span_notice("[buckler] lays [being_buckled] down on [src]."), + span_notice("[buckler] lays you down on [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + +/obj/structure/table/optable/unbuckle_feedback(mob/living/being_unbuckled, mob/unbuckler) + if(HAS_TRAIT(being_unbuckled, TRAIT_RESTRAINED)) + return ..() + + if(being_unbuckled == unbuckler) + being_unbuckled.visible_message( + span_notice("[unbuckler] gets up from [src]."), + span_notice("You get up from [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + else + being_unbuckled.visible_message( + span_notice("[unbuckler] pulls [being_unbuckled] up from [src]."), + span_notice("[unbuckler] pulls you up from [src]."), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + /obj/structure/table/optable/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) . = ..() if(isnull(held_item)) diff --git a/code/modules/shuttle/mobile_port/shuttle_move_callbacks.dm b/code/modules/shuttle/mobile_port/shuttle_move_callbacks.dm index 5c812157c9a..9f15cc0dfb8 100644 --- a/code/modules/shuttle/mobile_port/shuttle_move_callbacks.dm +++ b/code/modules/shuttle/mobile_port/shuttle_move_callbacks.dm @@ -325,8 +325,13 @@ All ShuttleMove procs go here . = ..() var/knockdown = movement_force["KNOCKDOWN"] - if(knockdown) - Paralyze(knockdown) + if(knockdown > 0) + if(buckled) + // If we're buckled, no stun but we'll still be floored and frozen + Knockdown(knockdown) + Immobilize(knockdown * 0.5) + else + Paralyze(knockdown) /mob/living/simple_animal/hostile/megafauna/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock) diff --git a/icons/obj/chairs.dmi b/icons/obj/chairs.dmi index 174a6a3e7bb..b1432f16701 100644 Binary files a/icons/obj/chairs.dmi and b/icons/obj/chairs.dmi differ diff --git a/icons/obj/handrail.dmi b/icons/obj/handrail.dmi new file mode 100644 index 00000000000..b2fb153e07d Binary files /dev/null and b/icons/obj/handrail.dmi differ