diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index db3e273c46293..bde20b4ddb8b8 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -1,11 +1,15 @@ /atom/movable + /// Whether the atom allows mobs to be buckled to it. Can be ignored in [/atom/movable/proc/buckle_mob()] if force = TRUE var/can_buckle = FALSE /// Bed-like behaviour, forces mob.lying = buckle_lying if not set to [NO_BUCKLE_LYING]. var/buckle_lying = NO_BUCKLE_LYING /// Require people to be handcuffed before being able to buckle. eg: pipes var/buckle_requires_restraints = FALSE + // The mobs currently buckled to this atom var/list/mob/living/buckled_mobs = null //list() + /// The maximum number of mob/livings allowed to be buckled to this atom at once var/max_buckled_mobs = 1 + /// Whether things buckled to this atom can be pulled while they're buckled var/buckle_prevents_pull = FALSE var/can_be_unanchored = FALSE @@ -15,7 +19,7 @@ if(.) return if(can_buckle && has_buckled_mobs()) - if(buckled_mobs.len > 1) + if(length(buckled_mobs) > 1) var/mob/living/unbuckled = tgui_input_list(user, "Who do you wish to unbuckle?", "Unbuckle", sort_names(buckled_mobs)) if(isnull(unbuckled)) return @@ -25,11 +29,11 @@ if(user_unbuckle_mob(buckled_mobs[1],user)) return TRUE -/atom/movable/attackby(obj/item/W, mob/user, params) - if(!can_buckle || !istype(W, /obj/item/riding_offhand) || !user.Adjacent(src)) +/atom/movable/attackby(obj/item/attacking_item, mob/user, params) + if(!can_buckle || !istype(attacking_item, /obj/item/riding_offhand) || !user.Adjacent(src)) return ..() - var/obj/item/riding_offhand/riding_item = W + var/obj/item/riding_offhand/riding_item = attacking_item var/mob/living/carried_mob = riding_item.rider if(carried_mob == user) //Piggyback user. return @@ -43,32 +47,47 @@ if(.) return if(Adjacent(user) && can_buckle && has_buckled_mobs()) - if(buckled_mobs.len > 1) + if(length(buckled_mobs) > 1) var/mob/living/unbuckled = tgui_input_list(user, "Who do you wish to unbuckle?", "Unbuckle", sort_names(buckled_mobs)) if(isnull(unbuckled)) return - if(user_unbuckle_mob(unbuckled,user)) - return TRUE + return user_unbuckle_mob(unbuckled,user) else - if(user_unbuckle_mob(buckled_mobs[1],user)) - return TRUE + return user_unbuckle_mob(buckled_mobs[1], user) /atom/movable/MouseDrop_T(mob/living/M, mob/living/user) . = ..() return mouse_buckle_handling(M, user) +/** + * Does some typechecks and then calls user_buckle_mob + * + * Arguments: + * M - The mob being buckled to src + * user - The mob buckling M to src + */ /atom/movable/proc/mouse_buckle_handling(mob/living/M, mob/living/user) if(can_buckle && istype(M) && istype(user)) - if(user_buckle_mob(M, user, check_loc = FALSE)) - return TRUE + return user_buckle_mob(M, user) +/** + * Returns TRUE if there are mobs buckled to this atom and FALSE otherwise + */ /atom/movable/proc/has_buckled_mobs() if(!buckled_mobs) return FALSE if(buckled_mobs.len) return TRUE -//procs that handle the actual buckling and unbuckling +/** + * Set a mob as buckled to src + * + * If you want to have a mob buckling another mob to something, or you want a chat message sent, use user_buckle_mob instead. + * Arguments: + * M - The mob to be buckled to src + * force - Set to TRUE to ignore src's can_buckle and M's can_buckle_to + * check_loc - Set to FALSE to allow buckling from adjacent turfs, or TRUE if buckling is only allowed with src and M on the same turf. + */ /atom/movable/proc/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) if(!buckled_mobs) buckled_mobs = list() @@ -76,15 +95,6 @@ if(!is_buckle_possible(M, force, check_loc)) return FALSE - M.buckling = src - if(!M.can_buckle() && !force) - if(M == usr) - to_chat(M, "You are unable to buckle yourself to [src]!") - else - to_chat(usr, "You are unable to buckle [M] to [src]!") - M.buckling = null - return FALSE - if(M.pulledby) if(buckle_prevents_pull) M.pulledby.stop_pulling() @@ -98,7 +108,6 @@ if (!check_loc && M.loc != loc) M.forceMove(loc) - M.buckling = null M.set_buckled(src) M.setDir(dir) buckled_mobs |= M @@ -123,13 +132,20 @@ M.adjust_fire_stacks(1) M.IgniteMob() - +/** + * Set a mob as unbuckled from src + * + * The mob must actually be buckled to src or else bad things will happen. + * Arguments: + * buckled_mob - The mob to be unbuckled + * force - TRUE if we should ignore buckled_mob.can_buckle_to + */ /atom/movable/proc/unbuckle_mob(mob/living/buckled_mob, force = FALSE) if(!isliving(buckled_mob)) CRASH("Non-living [buckled_mob] thing called unbuckle_mob() for source.") if(buckled_mob.buckled != src) CRASH("[buckled_mob] called unbuckle_mob() for source while having buckled as [buckled_mob.buckled].") - if(!force && !buckled_mob.can_unbuckle()) + if(!force && !buckled_mob.can_buckle_to) return . = buckled_mob buckled_mob.set_buckled(null) @@ -160,9 +176,11 @@ * Simple helper proc that runs a suite of checks to test whether it is possible or not to buckle the target mob to src. * * Returns FALSE if any conditions that should prevent buckling are satisfied. Returns TRUE otherwise. + * Called from [/atom/movable/proc/buckle_mob] and [/atom/movable/proc/is_user_buckle_possible]. * Arguments: * * target - Target mob to check against buckling to src. - * * force - Whether or not the buckle should be forced. If TRUE, ignores src's can_buckle var. + * * force - Whether or not the buckle should be forced. If TRUE, ignores src's can_buckle var and target's can_buckle_to + * * check_loc - TRUE if target and src have to be on the same tile, FALSE if they are allowed to just be adjacent * * check_loc - Whether to do a proximity check or not. The proximity check looks for target.loc == src.loc. */ /atom/movable/proc/is_buckle_possible(mob/living/target, force = FALSE, check_loc = TRUE) @@ -178,10 +196,6 @@ if(!can_buckle && !force) return FALSE - // Check if this atom can buckle, proc wise. - if(!target.can_buckle() && !force) - return FALSE - // If we're checking the loc, make sure the target is on the thing we're bucking them to. if(check_loc && target.loc != loc) return FALSE @@ -198,16 +212,21 @@ if(buckle_requires_restraints && !HAS_TRAIT(target, TRAIT_RESTRAINED)) return FALSE + //If buckling is forbidden for the target, cancel + if(!target.can_buckle_to && !force) + return FALSE + return TRUE /** * Simple helper proc that runs a suite of checks to test whether it is possible or not for user to buckle target mob to src. * * Returns FALSE if any conditions that should prevent buckling are satisfied. Returns TRUE otherwise. + * Called from [/atom/movable/proc/user_buckle_mob]. * Arguments: * * target - Target mob to check against buckling to src. * * user - The mob who is attempting to buckle the target to src. - * * check_loc - Whether to do a proximity check or not when calling is_buckle_possible(). + * * check_loc - TRUE if target and src have to be on the same tile, FALSE if buckling is allowed from adjacent tiles */ /atom/movable/proc/is_user_buckle_possible(mob/living/target, mob/user, check_loc = TRUE) // Standard adjacency and other checks. @@ -218,15 +237,20 @@ if(!is_buckle_possible(target, FALSE, check_loc)) return FALSE - // If the person attempting to buckle is stood on this atom's turf and they're not buckling themselves, - // buckling shouldn't be possible as they're blocking it. - if((target != user) && (get_turf(user) == get_turf(src))) - to_chat(target, "You are unable to buckle [target] to [src] while it is blocked!") - return FALSE - return TRUE -//Wrapper procs that handle sanity and user feedback +/** + * Handles a mob buckling another mob to src and sends a visible_message + * + * Basically exists to do some checks on the user and then call buckle_mob where the real buckling happens. + * First, checks if the buckle is valid and cancels if it isn't. + * Second, checks if src is on a different turf from the target; if it is, does a do_after and another check for sanity + * Finally, calls [/atom/movable/proc/buckle_mob] to buckle the target to src then gives chat feedback + * Arguments: + * * M - The target mob/living being buckled to src + * * user - The other mob that's buckling M to src + * * check_loc - TRUE if src and M have to be on the same turf, false otherwise + */ /atom/movable/proc/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) // Is buckling even possible? Do a full suite of checks. if(!is_user_buckle_possible(M, user, check_loc)) @@ -254,12 +278,21 @@ M.visible_message(\ "[M] buckles [M.p_them()]self to [src].",\ "You buckle yourself to [src].",\ - "You hear metal clanking.") + "You hear metal clanking.") else M.visible_message("[user] buckles [M] to [src]!",\ "[user] buckles you to [src]!",\ "You hear metal clanking.") +/** + * Handles a user unbuckling a mob from src and sends a visible_message + * + * Basically just calls unbuckle_mob, sets fingerprint, and sends a visible_message + * about the user unbuckling the mob + * Arguments: + * buckled_mob - The mob/living to unbuckle + * user - The mob unbuckling buckled_mob + */ /atom/movable/proc/user_unbuckle_mob(mob/living/buckled_mob, mob/user) var/mob/living/M = unbuckle_mob(buckled_mob) if(M) @@ -267,12 +300,12 @@ M.visible_message(\ "[user] unbuckles [M] from [src].",\ "[user] unbuckles you from [src].",\ - "You hear metal clanking.") + "You hear metal clanking.") else M.visible_message(\ "[M] unbuckles [M.p_them()]self from [src].",\ "You unbuckle yourself from [src].",\ - "You hear metal clanking.") + "You hear metal clanking.") add_fingerprint(user) if(isliving(M.pulledby)) var/mob/living/L = M.pulledby diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm index 78965daaba484..edcc7d6ec0560 100644 --- a/code/game/turfs/open/lava.dm +++ b/code/game/turfs/open/lava.dm @@ -127,9 +127,7 @@ var/mob/living/L = thing if(L.movement_type & FLYING) continue //YOU'RE FLYING OVER IT - var/buckle_check = L.buckling - if(!buckle_check) - buckle_check = L.buckled + var/buckle_check = L.buckled if(isobj(buckle_check)) var/obj/O = buckle_check if(O.resistance_flags & LAVA_PROOF) diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm index 065eb1c286158..0ff32fdc3e236 100644 --- a/code/modules/awaymissions/mission_code/snowdin.dm +++ b/code/modules/awaymissions/mission_code/snowdin.dm @@ -187,9 +187,7 @@ if("snow" in L.weather_immunities) continue - var/buckle_check = L.buckling - if(!buckle_check) - buckle_check = L.buckled + var/buckle_check = L.buckled if(isobj(buckle_check)) var/obj/O = buckle_check if(O.resistance_flags & FREEZE_PROOF) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 82ca66a8cb04d..4f8d8ccc3c804 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -218,7 +218,7 @@ if(HAS_TRAIT(src, TRAIT_RESTRAINED)) changeNext_move(CLICK_CD_BREAKOUT) last_special = world.time + CLICK_CD_BREAKOUT - var/buckle_cd = 600 + var/buckle_cd = 60 SECONDS if(handcuffed) var/obj/item/restraints/O = src.get_item_by_slot(ITEM_SLOT_HANDCUFFED) buckle_cd = O.breakouttime diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 5cbc07f08120c..b8c67e9328cfe 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -157,6 +157,9 @@ var/icon/head_icon = 'icons/mob/pets_held.dmi'//what it looks like on your head var/held_state = ""//icon state for the above + /// Is this mob allowed to be buckled/unbuckled to/from things? + var/can_buckle_to = TRUE + //is mob player controllable var/playable = FALSE var/flavor_text = FLAVOR_TEXT_NONE diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 710b0f1cdea03..5b2a65d116483 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -29,6 +29,7 @@ d_hud = DATA_HUD_DIAGNOSTIC_ADVANCED mob_size = MOB_SIZE_LARGE radio = /obj/item/radio/headset/silicon/ai + can_buckle_to = FALSE var/battery = 200 //emergency power if the AI's APC is off var/list/network = list("ss13") var/list/connected_robots = list() @@ -790,8 +791,6 @@ to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.") to_chat(user, "Transfer successful: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.") -/mob/living/silicon/ai/can_buckle() - return 0 /mob/living/silicon/ai/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE) if(control_disabled || incapacitated()) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 5814bbcc9d661..776db4f3d618a 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -14,6 +14,7 @@ layer = BELOW_MOB_LAYER can_be_held = TRUE radio = /obj/item/radio/headset/silicon/pai + can_buckle_to = FALSE move_force = 0 pull_force = 0 move_resist = 0 @@ -108,12 +109,6 @@ var/atom/movable/screen/ai/modpc/interface_button -/mob/living/silicon/pai/can_unbuckle() - return FALSE - -/mob/living/silicon/pai/can_buckle() - return FALSE - /mob/living/silicon/pai/handle_atom_del(atom/A) if(A == hacking_cable) hacking_cable = null diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 676b9b4add05c..5f2e5e36e95b8 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -1229,9 +1229,9 @@ cell = null /mob/living/silicon/robot/mouse_buckle_handling(mob/living/M, mob/living/user) + //Don't try buckling on INTENT_HARM so that silicons can search people's inventories without loading them if(can_buckle && istype(M) && !(M in buckled_mobs) && ((user!=src)||(a_intent != INTENT_HARM))) - if(buckle_mob(M)) - return TRUE + return user_buckle_mob(M, user, check_loc = FALSE) /mob/living/silicon/robot/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) if(!is_type_in_typecache(M, can_ride_typecache)) diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm index 1573e7404b8c6..628b9a7163c7c 100644 --- a/code/modules/mob/living/simple_animal/slime/slime.dm +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -510,12 +510,6 @@ /mob/living/simple_animal/slime/pet docile = 1 -/mob/living/simple_animal/slime/can_unbuckle() - return 0 - -/mob/living/simple_animal/slime/can_buckle() - return 0 - /mob/living/simple_animal/slime/get_mob_buckling_height(mob/seat) if(..()) return 3 diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 0350d6ee576a1..2fcac5d963f08 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -914,7 +914,7 @@ return src /** - * Buckle to another mob + * Buckle a living mob to this mob * * You can buckle on mobs if you're next to them since most are dense * @@ -952,14 +952,6 @@ return 0 return 9 -///can the mob be buckled to something by default? -/mob/proc/can_buckle() - return TRUE - -///can the mob be unbuckled from something by default? -/mob/proc/can_unbuckle() - return 1 - ///Can the mob interact() with an atom? /mob/proc/can_interact_with(atom/A, treat_mob_as_adjacent) if(IsAdminGhost(src)) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 0a39af6912142..97f9b47330cce 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -122,8 +122,6 @@ /// The atom that this mob is currently buckled to var/atom/movable/buckled = null//Living - /// The movable atom that we are currently in the process of buckling to, but haven't buckled with yet. - var/atom/movable/buckling //Hands ///What hand is the active hand diff --git a/code/modules/surgery/organs/wings.dm b/code/modules/surgery/organs/wings.dm index a7019ce1f0e23..6ce219b437b40 100644 --- a/code/modules/surgery/organs/wings.dm +++ b/code/modules/surgery/organs/wings.dm @@ -186,7 +186,7 @@ var/obj/item/organ/wings/bee/wings = locate(/obj/item/organ/wings/bee) in L.internal_organs var/jumpdistance = wings.jumpdist - if(L.stat != CONSCIOUS || L.buckling) // Has to be conscious and unbuckled + if(L.stat != CONSCIOUS || L.buckled) // Has to be conscious and unbuckled return if(recharging_time > world.time) to_chat(L, "The wings aren't ready to dash yet!")