From 8b9c6dc5f044fcb1c564d758d46665d80e21fbc8 Mon Sep 17 00:00:00 2001 From: moxian Date: Tue, 7 Jun 2022 15:26:23 +0000 Subject: [PATCH] Some grab fixes.. (#17895) * Some grab fixes.. * A tradeoff in jank * Address review comments * .. and a small comment --- code/modules/mob/living/living.dm | 80 ++++++++++++++++++++++++------- code/modules/mob/mob_defines.dm | 2 +- code/modules/mob/mob_movement.dm | 66 +++++++------------------ 3 files changed, 81 insertions(+), 67 deletions(-) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index afc69df2991..aee8c398d99 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -540,25 +540,12 @@ if(restrained()) stop_pulling() - var/turf/T = loc + var/turf/old_loc = loc . = ..() if(.) step_count++ - - if(pulling && pulling == pullee) // we were pulling a thing and didn't lose it during our move. - if(pulling.anchored) - stop_pulling() - return - - var/pull_dir = get_dir(src, pulling) - if(get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir))) // puller and pullee more than one tile away or in diagonal position - if(isliving(pulling)) - var/mob/living/M = pulling - if(M.lying && !M.buckled && (prob(M.getBruteLoss() * 200 / M.maxHealth))) - M.makeTrail(T) - pulling.Move(T, get_dir(pulling, T), movetime) // the pullee tries to reach our previous position - if(pulling && get_dist(src, pulling) > 1) // the pullee couldn't keep up - stop_pulling() + pull_pulled(old_loc, pullee, movetime) + pull_grabbed(old_loc, direct, movetime) if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //seperated from our puller and not in the middle of a diagonal move pulledby.stop_pulling() @@ -566,6 +553,67 @@ if(s_active && !(s_active in contents) && get_turf(s_active) != get_turf(src)) //check !( s_active in contents ) first so we hopefully don't have to call get_turf() so much. s_active.close(src) +/mob/living/proc/pull_pulled(turf/dest, atom/movable/pullee, movetime) + if(pulling && pulling == pullee) // we were pulling a thing and didn't lose it during our move. + if(pulling.anchored) + stop_pulling() + return + + var/pull_dir = get_dir(src, pulling) + if(get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir))) // puller and pullee more than one tile away or in diagonal position + if(isliving(pulling)) + var/mob/living/M = pulling + if(M.lying && !M.buckled && (prob(M.getBruteLoss() * 200 / M.maxHealth))) + M.makeTrail(dest) + pulling.Move(dest, get_dir(pulling, dest), movetime) // the pullee tries to reach our previous position + if(pulling && get_dist(src, pulling) > 1) // the pullee couldn't keep up + stop_pulling() + +/mob/living/proc/pull_grabbed(turf/old_turf, direct, movetime) + if(!Adjacent(old_turf)) + return + // yes, this is four distinct `for` loops. No, they can't be merged. + var/list/grabbing = list() + for(var/mob/M in ret_grab()) + if(src != M) + grabbing |= M + for(var/mob/M in grabbing) + M.currently_grab_pulled = TRUE + M.animate_movement = SYNC_STEPS + for(var/i in 1 to length(grabbing)) + var/mob/M = grabbing[i] + if(QDELETED(M)) // old code warned me that M could go missing during a move, so I'm cargo-culting it here + continue + // compile a list of turfs we can maybe move them towards + // importantly, this should happen before actually trying to move them to either of those + // otherwise they can be moved twice (since `Move` returns TRUE only if it managed to + // *fully* move where you wanted it to; it can still move partially and return FALSE) + var/possible_dest = list() + for(var/turf/dest in orange(src, 1)) + if(dest.Adjacent(M)) + possible_dest |= dest + if(i == 1) // at least one of them should try to trail behind us, for aesthetics purposes + if(M.Move(old_turf, get_dir(M, old_turf), movetime)) + continue + // By this time the `old_turf` is definitely occupied by something immovable. + // So try to move them into some other adjacent turf, in a believable way + if(Adjacent(M)) + continue // they are already adjacent + for(var/turf/dest in possible_dest) + if(M.Move(dest, get_dir(M, dest), movetime)) + break + for(var/mob/M in grabbing) + M.currently_grab_pulled = null + M.animate_movement = SLIDE_STEPS + + for(var/obj/item/grab/G in src) + if(G.state == GRAB_NECK) + setDir(angle2dir((dir2angle(direct) + 202.5) % 365)) + G.adjust_position() + for(var/obj/item/grab/G in grabbed_by) + G.adjust_position() + + /mob/living/proc/makeTrail(turf/T) if(!has_gravity(src)) return diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 06134a3b3a8..731f504c085 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -40,7 +40,7 @@ var/last_log = 0 var/obj/machinery/machine = null - var/other_mobs = null + var/currently_grab_pulled = null /// only set while the move is ongoing, to prevent shuffling between pullees var/memory = "" var/next_move = null var/notransform = null //Carbon diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 76cb23938e3..70686edc941 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -11,8 +11,8 @@ return TRUE if(ismob(mover)) var/mob/moving_mob = mover - if((other_mobs && moving_mob.other_mobs)) - return TRUE + if((currently_grab_pulled && moving_mob.currently_grab_pulled)) + return FALSE if(mover in buckled_mobs) return TRUE return (!mover.density || !density || lying) @@ -131,50 +131,23 @@ delay = TICKS2DS(-round(-(DS2TICKS(delay)))) //Rounded to the next tick in equivalent ds + if(locate(/obj/item/grab, mob)) delay += 7 - var/list/L = mob.ret_grab() - if(istype(L, /list)) - if(L.len == 2) - L -= mob - var/mob/M = L[1] - if(M) - if((get_dist(mob, M) <= 1 || M.loc == mob.loc)) - var/turf/prev_loc = mob.loc - . = mob.SelfMove(n, direct, delay) - if(M && isturf(M.loc)) // Mob may get deleted during parent call - var/diag = get_dir(mob, M) - if((diag - 1) & diag) - else - diag = null - if((get_dist(mob, M) > 1 || diag)) - M.Move(prev_loc, get_dir(M.loc, prev_loc), delay) - else - for(var/mob/M in L) - M.other_mobs = 1 - if(mob != M) - M.animate_movement = 3 - for(var/mob/M in L) - spawn(0) - M.Move(get_step(M,direct), direct, delay) - spawn(1) - M.other_mobs = null - M.animate_movement = 2 - else - var/mob/living/L = mob - if(L) - var/newdir = NONE - var/confusion = L.get_confusion() - if(confusion > CONFUSION_MAX) - newdir = pick(GLOB.alldirs) - else if(prob(confusion * CONFUSION_HEAVY_COEFFICIENT)) - newdir = angle2dir(dir2angle(direct) + pick(90, -90)) - else if(prob(confusion * CONFUSION_LIGHT_COEFFICIENT)) - newdir = angle2dir(dir2angle(direct) + pick(45, -45)) - if(newdir) - direct = newdir - n = get_step(mob, direct) + var/mob/living/living_mob = mob + if(istype(living_mob)) + var/newdir = NONE + var/confusion = living_mob.get_confusion() + if(confusion > CONFUSION_MAX) + newdir = pick(GLOB.alldirs) + else if(prob(confusion * CONFUSION_HEAVY_COEFFICIENT)) + newdir = angle2dir(dir2angle(direct) + pick(90, -90)) + else if(prob(confusion * CONFUSION_LIGHT_COEFFICIENT)) + newdir = angle2dir(dir2angle(direct) + pick(45, -45)) + if(newdir) + direct = newdir + n = get_step(mob, direct) var/prev_pulling_loc = null if(mob.pulling) @@ -198,13 +171,6 @@ else mob.setDir(direct) - for(var/obj/item/grab/G in mob) - if(G.state == GRAB_NECK) - mob.setDir(angle2dir((dir2angle(direct) + 202.5) % 365)) - G.adjust_position() - for(var/obj/item/grab/G in mob.grabbed_by) - G.adjust_position() - moving = 0 if(mob && .) if(mob.throwing)