Skip to content

Commit

Permalink
grab fixes (#868)
Browse files Browse the repository at this point in the history
* grab fixes

* fixes

* code cleanup

* unit test grabbing

* fixes unit tests 1

* fix struggle grab test

* maybe fix struggle grab test?

* maybe?

* fuck

* fixes

* fix downgrab test

* forgot how my own code worked

* maybe?

* fuck it

* uhh maybe?
  • Loading branch information
Kapu1178 authored Mar 11, 2024
1 parent 91d1151 commit 8754709
Show file tree
Hide file tree
Showing 15 changed files with 212 additions and 49 deletions.
1 change: 1 addition & 0 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Is a medbot healing you
#define TRAIT_MEDIBOTCOMINGTHROUGH "medbot"
#define TRAIT_PASSTABLE "passtable"
#define TRAIT_PASSMOB "passmob"
/// Makes you immune to flashes
#define TRAIT_NOFLASH "noflash"
/// prevents xeno huggies implanting skeletons
Expand Down
19 changes: 16 additions & 3 deletions code/game/atoms_movable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -400,12 +400,12 @@
if(QDELING(src))
CRASH("Illegal Move()! on [type]")

if(!moving_from_pull)
recheck_grabs(z_allowed = TRUE)

if(!loc || !newloc)
return FALSE

if(!moving_from_pull)
recheck_grabs(z_allowed = TRUE)

if(direct & (UP|DOWN))
if(!can_z_move(direct, null, z_movement_flags))
return FALSE
Expand Down Expand Up @@ -509,6 +509,8 @@
moving_from_pull = FALSE
forcemove_should_maintain_grab = FALSE

update_offsets()

/**
* Called after a successful Move(). By this point, we've already moved.
* Arguments:
Expand Down Expand Up @@ -1336,3 +1338,14 @@
/atom/movable/wash(clean_types)
. = ..()
germ_level = 0

/atom/movable/proc/add_passmob(source)
if(!source)
return
ADD_TRAIT(src, TRAIT_PASSMOB, source)
pass_flags |= PASSMOB

/atom/movable/proc/remove_passmob(source)
REMOVE_TRAIT(src, TRAIT_PASSMOB, source)
if(!HAS_TRAIT(src, TRAIT_PASSMOB))
pass_flags &= ~PASSMOB
9 changes: 9 additions & 0 deletions code/game/objects/buckling.dm
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,10 @@

if(anchored)
ADD_TRAIT(M, TRAIT_NO_FLOATING_ANIM, BUCKLED_TRAIT)

if(!length(buckled_mobs))
RegisterSignal(src, COMSIG_MOVABLE_SET_ANCHORED, PROC_REF(on_set_anchored))

M.set_buckled(src)
buckled_mobs |= M
M.throw_alert(ALERT_BUCKLED, /atom/movable/screen/alert/buckled)
Expand All @@ -123,6 +125,7 @@
M.setDir(dir)

post_buckle_mob(M)
M.update_offsets()

SEND_SIGNAL(src, COMSIG_MOVABLE_BUCKLE, M, force)
return TRUE
Expand All @@ -149,23 +152,29 @@
CRASH("[buckled_mob] called unbuckle_mob() for source while having buckled as [buckled_mob.buckled].")
if(!force && !buckled_mob.can_buckle_to)
return

. = buckled_mob

buckled_mob.set_buckled(null)
buckled_mob.set_anchored(initial(buckled_mob.anchored))
buckled_mob.clear_alert(ALERT_BUCKLED)
buckled_mob.set_glide_size(DELAY_TO_GLIDE_SIZE(buckled_mob.total_multiplicative_slowdown()))
buckled_mobs -= buckled_mob

if(anchored)
REMOVE_TRAIT(buckled_mob, TRAIT_NO_FLOATING_ANIM, BUCKLED_TRAIT)

if(!length(buckled_mobs))
UnregisterSignal(src, COMSIG_MOVABLE_SET_ANCHORED)

SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force)

if(can_fall)
if(!buckled_mob.currently_z_moving)
buckled_mob.zFall()

post_unbuckle_mob(.)
buckled_mob.update_offsets()

if(!QDELETED(buckled_mob) && !buckled_mob.currently_z_moving && isturf(buckled_mob.loc)) // In the case they unbuckled to a flying movable midflight.
buckled_mob.zFall()
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/structures/railings.dm
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
return ..()

if(!Adjacent(L))
user.move_grabbed_atoms_towards(get_turf(src))
grab.move_victim_towards(get_turf(src))
return ..()

if(user.combat_mode)
Expand Down
5 changes: 4 additions & 1 deletion code/game/turfs/turf.dm
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,10 @@ GLOBAL_LIST_EMPTY(station_turfs)
return
if(user == victim)
return
user.move_grabbed_atoms_towards(src)
if(grab.current_grab.same_tile)
return

grab.move_victim_towards(src)


/**
Expand Down
31 changes: 29 additions & 2 deletions code/modules/grab/grab_datum.dm
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ GLOBAL_LIST_EMPTY(all_grabstates)

// What happens when you upgrade from one grab state to the next.
/datum/grab/proc/upgrade_effect(obj/item/hand_item/grab/G, datum/grab/old_grab)
SHOULD_CALL_PARENT(TRUE)

G.remove_competing_grabs()
update_stage_effects(G, old_grab)

// Conditions to see if upgrading is possible
Expand All @@ -199,6 +202,11 @@ GLOBAL_LIST_EMPTY(all_grabstates)
if(upgrab.damage_stage >= GRAB_AGGRESSIVE && HAS_TRAIT(G.assailant, TRAIT_PACIFISM))
to_chat(G.assailant, span_warning("You don't want to risk hurting [src]!"))
return FALSE

for(var/obj/item/hand_item/grab/other_grab in L.grabbed_by - G)
if(other_grab.assailant.move_force > G.assailant.move_force)
to_chat(G.assailant, span_warning("[G.assailant]'s grip is too strong."))
return FALSE
return TRUE

// What happens when you downgrade from one grab state to the next.
Expand Down Expand Up @@ -254,12 +262,14 @@ GLOBAL_LIST_EMPTY(all_grabstates)
/// Apply effects that should only be applied when a grab type is first used on a mob.
/datum/grab/proc/apply_unique_grab_effects(obj/item/hand_item/grab/G)
SHOULD_CALL_PARENT(TRUE)
if(G.loc != G.assailant.loc && same_tile)
G.affecting.move_from_pull(G.assailant, get_turf(G.assailant))
if(same_tile && ismob(G.affecting))
G.affecting.add_passmob(REF(G))

/// Remove effects added by apply_unique_grab_effects()
/datum/grab/proc/remove_unique_grab_effects(obj/item/hand_item/grab/G)
SHOULD_CALL_PARENT(TRUE)
if(same_tile && ismob(G.affecting))
G.affecting.remove_passmob(REF(G))

/// Handles special targeting like eyes and mouth being covered.
/// CLEAR OUT ANY EFFECTS USING remove_bodyzone_effects()
Expand Down Expand Up @@ -415,3 +425,20 @@ GLOBAL_LIST_EMPTY(all_grabstates)

else if(help_action)
context[SCREENTIP_CONTEXT_LMB] = capitalize(help_action)

/datum/grab/proc/get_grab_offsets(obj/item/hand_item/grab/G, grab_direction, pixel_x_pointer, pixel_y_pointer)
if(!grab_direction || !G.current_grab.shift)
return

if(grab_direction & WEST)
*pixel_x_pointer = min(*pixel_x_pointer + shift, G.affecting.base_pixel_x + shift)

else if(grab_direction & EAST)
*pixel_x_pointer = max(*pixel_x_pointer - shift, G.affecting.base_pixel_x - shift)

if(grab_direction & NORTH)
*pixel_y_pointer = max(*pixel_y_pointer - shift, G.affecting.base_pixel_y - shift)

else if(grab_direction & SOUTH)
*pixel_y_pointer = min(*pixel_y_pointer + shift, G.affecting.base_pixel_y + shift)

12 changes: 12 additions & 0 deletions code/modules/grab/grab_living.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/mob/living/proc/can_grab(atom/movable/target, target_zone, use_offhand)
if(throwing || !(mobility_flags & MOBILITY_PULL))
return FALSE

if(!ismob(target) && target.anchored)
to_chat(src, span_warning("\The [target] won't budge!"))
return FALSE
Expand All @@ -20,10 +21,16 @@

for(var/obj/item/hand_item/grab/G in target.grabbed_by)
if(G.assailant != src)
if(G.assailant.pull_force > pull_force || (G.assailant.pull_force == pull_force && G.current_grab.damage_stage > GRAB_PASSIVE))
to_chat(src, span_warning("[G.assailant]'s grip is too strong."))
return FALSE

continue

if(!target_zone || !ismob(target))
to_chat(src, span_warning("You already have a grip on \the [target]!"))
return FALSE

if(G.target_zone == target_zone)
var/obj/item/bodypart/BP = G.get_targeted_bodypart()
if(BP)
Expand Down Expand Up @@ -73,6 +80,11 @@
to_chat(original_target, span_warning("\The [src] tries to grab you, but fails!"))
return null

for(var/obj/item/hand_item/grab/competing_grab in target.grabbed_by)
if(competing_grab.assailant.pull_force < pull_force)
to_chat(competing_grab.assailant, span_alert("[target] is ripped from your grip by [src]."))
qdel(competing_grab)

SEND_SIGNAL(src, COMSIG_LIVING_START_GRAB, target, grab)
SEND_SIGNAL(target, COMSIG_ATOM_GET_GRABBED, src, grab)

Expand Down
45 changes: 9 additions & 36 deletions code/modules/grab/grab_movable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,7 @@
/// Move grabbed atoms towards a destination
/mob/living/proc/move_grabbed_atoms_towards(atom/destination)
for(var/obj/item/hand_item/grab/G in active_grabs)
var/atom/movable/pulling = G.affecting
if(pulling.anchored || pulling.move_resist > move_force || !pulling.Adjacent(src, src, pulling))
qdel(G)
continue

if(isliving(pulling))
var/mob/living/pulling_mob = pulling
if(pulling_mob.buckled && pulling_mob.buckled.buckle_prevents_pull) //if they're buckled to something that disallows pulling, prevent it
qdel(G)
continue

if(destination == loc && pulling.density)
continue

var/move_dir = get_dir(pulling.loc, destination)
if(!Process_Spacemove(move_dir))
continue

// At this point the move was successful
pulling.Move(get_step(pulling.loc, move_dir), move_dir, glide_size)

pulling.update_offsets()

G.move_victim_towards(destination)

/atom/movable/proc/update_offsets()
var/last_pixel_x = pixel_x
Expand All @@ -74,24 +52,19 @@
var/list/grabbed_by = list()

grabbed_by += src.grabbed_by

if(length(buckled_mobs))
for(var/mob/M as anything in buckled_mobs)
M.update_offsets()

if(isliving(src))
var/mob/living/L = src
if(L.buckled)
grabbed_by += L.buckled.grabbed_by

if(isturf(loc))
if(length(grabbed_by))
for(var/obj/item/hand_item/grab/G in grabbed_by)
var/grab_dir = get_dir(G.assailant, src)
if(grab_dir && G.current_grab.shift != 0)
if(grab_dir & WEST)
new_pixel_x = min(new_pixel_x+G.current_grab.shift, base_pixel_x+G.current_grab.shift)
else if(grab_dir & EAST)
new_pixel_x = max(new_pixel_x-G.current_grab.shift, base_pixel_x-G.current_grab.shift)
if(grab_dir & NORTH)
new_pixel_y = max(new_pixel_y-G.current_grab.shift, base_pixel_y-G.current_grab.shift)
else if(grab_dir & SOUTH)
new_pixel_y = min(new_pixel_y+G.current_grab.shift, base_pixel_y+G.current_grab.shift)
if(isturf(loc) && length(grabbed_by))
for(var/obj/item/hand_item/grab/G in grabbed_by)
G.current_grab.get_grab_offsets(G, get_dir(G.assailant, G.affecting), &new_pixel_x, &new_pixel_y)

if(last_pixel_x != new_pixel_x || last_pixel_y != new_pixel_y)
animate(src, pixel_x = new_pixel_x, pixel_y = new_pixel_y, 3, 1, (LINEAR_EASING|EASE_IN))
Expand Down
40 changes: 38 additions & 2 deletions code/modules/grab/grab_object.dm
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,14 @@
if(affecting)
LAZYREMOVE(affecting.grabbed_by, src)
affecting.update_offsets()

if(affecting && assailant && current_grab)
current_grab.let_go(src)

if(assailant)
LAZYREMOVE(assailant.active_grabs, src)
assailant.after_grab_release(affecting)

affecting = null
assailant = null
return ..()
Expand Down Expand Up @@ -251,8 +254,6 @@

COOLDOWN_START(src, upgrade_cd, current_grab.upgrade_cooldown)

adjust_position()
update_appearance()
leave_forensic_traces()

if(QDELETED(src))
Expand All @@ -264,10 +265,14 @@
if(is_grab_unique(current_grab))
current_grab.apply_unique_grab_effects(src)

adjust_position()
update_appearance()

/obj/item/hand_item/grab/proc/downgrade(silent)
var/datum/grab/downgrab = current_grab.downgrade(src)
if(!downgrab)
return

if(is_grab_unique(current_grab))
current_grab.remove_unique_grab_effects(src)

Expand Down Expand Up @@ -368,3 +373,34 @@

affecting.update_offsets()
affecting.reset_plane_and_layer()

/obj/item/hand_item/grab/proc/move_victim_towards(atom/destination)
if(current_grab.same_tile)
return

if(affecting.anchored || affecting.move_resist > assailant.move_force || !affecting.Adjacent(assailant, assailant, affecting))
qdel(src)
return

if(isliving(assailant))
var/mob/living/pulling_mob = assailant
if(pulling_mob.buckled && pulling_mob.buckled.buckle_prevents_pull) //if they're buckled to something that disallows pulling, prevent it
qdel(src)
return

var/move_dir = get_dir(affecting.loc, destination)

// Don't move people in space, that's fucking cheating
if(!Process_Spacemove(move_dir))
return

// Okay, now actually try to move
. = affecting.Move(get_step(affecting.loc, move_dir), move_dir, glide_size)
if(.)
affecting.update_offsets()

/// Removes any grabs applied to the affected movable that aren't src
/obj/item/hand_item/grab/proc/remove_competing_grabs()
for(var/obj/item/hand_item/grab/other_grab in affecting.grabbed_by - src)
to_chat(other_grab.assailant, span_alert("[affecting] is ripped from your grip by [assailant]."))
qdel(other_grab)
3 changes: 2 additions & 1 deletion code/modules/grab/grabs/grab_normal.dm
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
if(do_after(assailant, affecting, action_cooldown - 1, DO_PUBLIC, display = image('icons/hud/do_after.dmi', "harm")))
G.action_used()
affecting.visible_message(span_danger("\The [assailant] pins \the [affecting] to the ground!"))
affecting.Knockdown(1 SECOND) // This can only be performed with an aggressive grab, which ensures that once someone is knocked down, they stay down/
affecting.Paralyze(1 SECOND) // This can only be performed with an aggressive grab, which ensures that once someone is knocked down, they stay down.
affecting.move_from_pull(G.assailant, get_turf(G.assailant))
return TRUE

affecting.visible_message(span_warning("\The [assailant] fails to pin \the [affecting] to the ground."))
Expand Down
5 changes: 5 additions & 0 deletions code/modules/grab/grabs/grab_struggle.dm
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@
/datum/grab/normal/struggle/proc/resolve_struggle(obj/item/hand_item/grab/G)
set waitfor = FALSE

#ifdef UNIT_TESTS
var/upgrade_cooldown = 0
sleep(world.tick_lag)
#endif

var/datum/callback/user_incapacitated_callback = CALLBACK(src, PROC_REF(resolve_struggle_check), G)
if(do_after(G.assailant, G.affecting, upgrade_cooldown, DO_PUBLIC|IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE, extra_checks = user_incapacitated_callback))
G.done_struggle = TRUE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@
return
hopping = TRUE
set_density(FALSE)
pass_flags |= PASSMOB
add_passmob(REF(src))
notransform = TRUE
var/turf/new_turf = locate((target.x + rand(-3,3)),(target.y + rand(-3,3)),target.z)
if(player_hop)
Expand All @@ -222,7 +222,7 @@
/mob/living/simple_animal/hostile/jungle/leaper/proc/FinishHop()
set_density(TRUE)
notransform = FALSE
pass_flags &= ~PASSMOB
remove_passmob(REF(src))
hopping = FALSE
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 100, TRUE)
if(target && AIStatus == AI_ON && projectile_ready && !ckey)
Expand Down
Loading

0 comments on commit 8754709

Please sign in to comment.