Skip to content

Commit

Permalink
Buckling check cleanup & documentation. Removes a snowflake buckle wi…
Browse files Browse the repository at this point in the history
…th cyborgs (#9802)

* initial

* .

* sx
  • Loading branch information
Tsar-Salat authored Aug 4, 2024
1 parent 757b0a4 commit 36942fb
Show file tree
Hide file tree
Showing 12 changed files with 85 additions and 75 deletions.
113 changes: 73 additions & 40 deletions code/game/objects/buckling.dm
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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
Expand All @@ -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
Expand All @@ -43,48 +47,54 @@
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()

if(!is_buckle_possible(M, force, check_loc))
return FALSE

M.buckling = src
if(!M.can_buckle() && !force)
if(M == usr)
to_chat(M, "<span class='warning'>You are unable to buckle yourself to [src]!</span>")
else
to_chat(usr, "<span class='warning'>You are unable to buckle [M] to [src]!</span>")
M.buckling = null
return FALSE

if(M.pulledby)
if(buckle_prevents_pull)
M.pulledby.stop_pulling()
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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, "<span class='warning'>You are unable to buckle [target] to [src] while it is blocked!</span>")
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))
Expand Down Expand Up @@ -254,25 +278,34 @@
M.visible_message(\
"<span class='notice'>[M] buckles [M.p_them()]self to [src].</span>",\
"<span class='notice'>You buckle yourself to [src].</span>",\
"<span class='italics'>You hear metal clanking.</span>")
"<span class='hear'>You hear metal clanking.</span>")
else
M.visible_message("<span class='warning'>[user] buckles [M] to [src]!</span>",\
"<span class='warning'>[user] buckles you to [src]!</span>",\
"<span class='hear'>You hear metal clanking.</span>")

/**
* 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)
if(M != user)
M.visible_message(\
"<span class='notice'>[user] unbuckles [M] from [src].</span>",\
"<span class='notice'>[user] unbuckles you from [src].</span>",\
"<span class='italics'>You hear metal clanking.</span>")
"<span class='hear'>You hear metal clanking.</span>")
else
M.visible_message(\
"<span class='notice'>[M] unbuckles [M.p_them()]self from [src].</span>",\
"<span class='notice'>You unbuckle yourself from [src].</span>",\
"<span class='italics'>You hear metal clanking.</span>")
"<span class='hear'>You hear metal clanking.</span>")
add_fingerprint(user)
if(isliving(M.pulledby))
var/mob/living/L = M.pulledby
Expand Down
4 changes: 1 addition & 3 deletions code/game/turfs/open/lava.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 1 addition & 3 deletions code/modules/awaymissions/mission_code/snowdin.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/carbon/carbon.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions code/modules/mob/living/living_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions code/modules/mob/living/silicon/ai/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -790,8 +791,6 @@
to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.")
to_chat(user, "<span class='boldnotice'>Transfer successful</span>: [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())
Expand Down
7 changes: 1 addition & 6 deletions code/modules/mob/living/silicon/pai/pai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions code/modules/mob/living/silicon/robot/robot.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
6 changes: 0 additions & 6 deletions code/modules/mob/living/simple_animal/slime/slime.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 1 addition & 9 deletions code/modules/mob/mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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))
Expand Down
2 changes: 0 additions & 2 deletions code/modules/mob/mob_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 36942fb

Please sign in to comment.