From 45f751989af58a7f49db6cc66b143f2bf94db3a1 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 3 Jun 2025 22:13:22 -0700 Subject: [PATCH] fix #K4331 - sticking from distance Stop attacking if target isn't there anymore. Already handled for two-weapon in normal form, not for multi-attacks in poly'd form and for multi-attack monster vs hero or monster vs other monster. I didn't attempt to reproduce the reported problem. This fix is based on code inspection. Also prevent monsters that have hug or engulf attacks from knocking target back with other attacks since that prohibits the grab/engulf from being able to hit. --- src/mhitm.c | 11 ++++++++++- src/mhitu.c | 2 ++ src/uhitm.c | 32 +++++++++++++++++++++++--------- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/mhitm.c b/src/mhitm.c index 8892c0f59..39fe251a7 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -284,6 +284,9 @@ mdisplacem( * Each successive attack has a lower probability of hitting. Some rely on * success of previous attacks. ** this doesn't seem to be implemented -dl ** * + * Attacker has targeted rather than + * mx,mdef->my>; matters for long worms. + * * In the case of exploding monsters, the monster dies as well. */ int @@ -353,7 +356,7 @@ mattackm( /* Set up the visibility of action */ gv.vis = ((cansee(magr->mx, magr->my) && canspotmon(magr)) - || (cansee(mdef->mx, mdef->my) && canspotmon(mdef))); + || (cansee(mdef->mx, mdef->my) && canspotmon(mdef))); /* Set flag indicating monster has moved this turn. Necessary since a * monster might get an attack out of sequence (i.e. before its move) in @@ -371,6 +374,12 @@ mattackm( /* Now perform all attacks for the monster. */ for (i = 0; i < NATTK; i++) { res[i] = M_ATTK_MISS; + + /* target might no longer be there */ + if (i > 0 && (m_at(gb.bhitpos.x, gb.bhitpos.y) != mdef + || DEADMONSTER(magr) || DEADMONSTER(mdef))) + continue; + mattk = getmattk(magr, mdef, i, res, &alt_attk); /* reduce verbosity for mind flayer attacking creature without a head (or worm's tail); this is similar to monster with multiple diff --git a/src/mhitu.c b/src/mhitu.c index ed0b6e098..0357915e8 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -754,6 +754,8 @@ mattacku(struct monst *mtmp) /* if hero was found but isn't anymore, avoid wildmiss now */ if (firstfoundyou && !foundyou) continue; /* set sum[i] to 'miss' but skip other actions */ + if (!u_at(gb.bhitpos.x, gb.bhitpos.y)) + continue; } mon_currwep = (struct obj *) 0; mattk = getmattk(mtmp, &gy.youmonst, i, sum, &alt_attk); diff --git a/src/uhitm.c b/src/uhitm.c index 56a4079ce..90014bcd6 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -5203,7 +5203,7 @@ mhitm_knockback( boolean u_def = (mdef == &gy.youmonst); boolean was_u = FALSE, dismount = FALSE; struct obj *wep = weapon_used ? (u_agr ? uwep : MON_WEP(magr)) - : (struct obj *)0; + : (struct obj *) 0; if (wep && is_art(wep, ART_OGRESMASHER)) chance = 2; @@ -5211,6 +5211,20 @@ mhitm_knockback( if (rn2(chance)) return FALSE; + /* only certain attacks qualify for knockback */ + if (!((mattk->adtyp == AD_PHYS) + && (mattk->aatyp == AT_CLAW + || mattk->aatyp == AT_KICK + || mattk->aatyp == AT_BUTT + || mattk->aatyp == AT_WEAP))) + return FALSE; + + /* don't knockback if attacker also wants to grab or engulf */ + if (attacktype(magr->data, AT_ENGL) + || attacktype(magr->data, AT_HUGS) + || sticks(magr->data)) + return FALSE; + /* decide where the first step will place the target; not accurate for being knocked out of saddle but doesn't need to be; used for test_move() and for message before actual hurtle */ @@ -5257,14 +5271,6 @@ mhitm_knockback( if (wep && (is_flimsy(wep) || !is_blunt_weapon(wep))) return FALSE; - /* only certain attacks qualify for knockback */ - if (!((mattk->adtyp == AD_PHYS) - && (mattk->aatyp == AT_CLAW - || mattk->aatyp == AT_KICK - || mattk->aatyp == AT_BUTT - || mattk->aatyp == AT_WEAP))) - return FALSE; - /* needs a solid physical hit */ if (unsolid(magr->data)) return FALSE; @@ -5388,6 +5394,14 @@ hmonas(struct monst *mon) for (i = 0; i < NATTK; i++) { /* sum[i] = M_ATTK_MISS; -- now done above */ + + /* target might have been knocked back so no longer in range, or an + engulfing vampshifted fog cloud killed and reverted to vampire + that's placed at another spot (hero occupies mon's first spot) */ + if (i > 0 && (m_at(gb.bhitpos.x, gb.bhitpos.y) != mon + || DEADMONSTER(mon))) + continue; + mattk = getmattk(&gy.youmonst, mon, i, sum, &alt_attk); if (gs.skipdrin && mattk->aatyp == AT_TENT && mattk->adtyp == AD_DRIN) continue;