From 74ed2999de09524605a83577b50ea1287e3ecb29 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 11 Mar 2023 11:21:09 -0800 Subject: [PATCH] knockback feedback Adjust the message given when an attack knocks its target back. Say | is knocked backward by if target will actually move or | is knocked back by if there's something preventing the move. Most players probably won't even notice the difference. (Possibly "rocked back" would be better when not changing location but this hasn't gone that far.) Also make the knock back distance be 1 step 2/3 of the time or 2 steps 1/3 instead of 50:50 chance for 1 or 2 steps. --- include/extern.h | 5 ++-- src/dothrow.c | 20 +++++++++++---- src/uhitm.c | 67 +++++++++++++++++++++++++++++------------------- 3 files changed, 58 insertions(+), 34 deletions(-) diff --git a/include/extern.h b/include/extern.h index 2c7afdc18..9379dccef 100644 --- a/include/extern.h +++ b/include/extern.h @@ -644,6 +644,9 @@ extern int dothrow(void); extern int dofire(void); extern void endmultishot(boolean); extern void hitfloor(struct obj *, boolean); +extern boolean hurtle_jump(genericptr_t, coordxy, coordxy); +extern boolean hurtle_step(genericptr_t, coordxy, coordxy); +extern boolean will_hurtle(struct monst *, coordxy, coordxy); extern void hurtle(int, int, int, boolean); extern void mhurtle(struct monst *, int, int, int); extern boolean harmless_missile(struct obj *); @@ -658,8 +661,6 @@ extern void breakobj(struct obj *, coordxy, coordxy, boolean, boolean); extern boolean breaktest(struct obj *); extern boolean walk_path(coord *, coord *, boolean(*)(void *, coordxy, coordxy), genericptr_t); -extern boolean hurtle_jump(genericptr_t, coordxy, coordxy); -extern boolean hurtle_step(genericptr_t, coordxy, coordxy); /* ### drawing.c ### */ diff --git a/src/dothrow.c b/src/dothrow.c index 528db9039..a4d061cbd 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -975,20 +975,30 @@ hurtle_step(genericptr_t arg, coordxy x, coordxy y) return TRUE; } +/* used by mhurtle_step() for actual hurtling and also to vary message + if target will/won't change location when knocked back */ +boolean +will_hurtle(struct monst *mon, coordxy x, coordxy y) +{ + if (!isok(x, y)) + return FALSE; + /* + * TODO: Treat walls, doors, iron bars, etc. specially + * rather than just stopping before. + */ + return goodpos(x, y, mon, MM_IGNOREWATER | MM_IGNORELAVA); +} + static boolean mhurtle_step(genericptr_t arg, coordxy x, coordxy y) { struct monst *mon = (struct monst *) arg; struct monst *mtmp; - /* TODO: Treat walls, doors, iron bars, etc. specially - * rather than just stopping before. - */ if (!isok(x, y)) return FALSE; - if (goodpos(x, y, mon, MM_IGNOREWATER | MM_IGNORELAVA) - && m_in_out_region(mon, x, y)) { + if (will_hurtle(mon, x, y) && m_in_out_region(mon, x, y)) { int res; if (mon != u.usteed) { diff --git a/src/uhitm.c b/src/uhitm.c index 35a54dc56..5e0f74267 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -4843,20 +4843,26 @@ mhitm_knockback( { char magrbuf[BUFSZ], mdefbuf[BUFSZ]; struct obj *otmp; + const char *knockedhow; + coordxy dx, dy, defx, defy; + int knockdistance = rn2(3) ? 1 : 2; /* 67%: 1 step, 33%: 2 steps */ boolean u_agr = (magr == &gy.youmonst); boolean u_def = (mdef == &gy.youmonst); - boolean was_u = FALSE; + boolean was_u = FALSE, dismount = FALSE; /* 1/6 chance of attack knocking back a monster */ if (rn2(6)) return FALSE; /* if hero is stuck to a cursed saddle, knock the steed back */ - if (u_def && u.usteed - && (otmp = which_armor(u.usteed, W_SADDLE)) != 0 && otmp->cursed) { - mdef = u.usteed; - was_u = TRUE; - u_def = FALSE; + if (u_def && u.usteed) { + if ((otmp = which_armor(u.usteed, W_SADDLE)) != 0 && otmp->cursed) { + mdef = u.usteed; + was_u = TRUE; + u_def = FALSE; + } else { + dismount = TRUE; /* saddle is not cursed; knock hero out of it */ + } } /* monsters must be alive */ @@ -4899,10 +4905,20 @@ mhitm_knockback( 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 + message before actual hurtle */ + defx = u_def ? u.ux : mdef->mx; + defy = u_def ? u.uy : mdef->my; + dx = sgn(defx - (u_agr ? u.ux : magr->mx)); + dy = sgn(defy - (u_agr ? u.uy : magr->my)); + /* subtly vary the message text if monster won't actually move */ + knockedhow = dismount ? "out of your saddle" + : will_hurtle(mdef, defx + dx, defy + dy) ? "backward" + : "back"; + /* give the message */ if (u_def || canseemon(mdef)) { - boolean dosteed = u_def && u.usteed; - Strcpy(magrbuf, u_agr ? "You" : Monnam(magr)); Strcpy(mdefbuf, (u_def || was_u) ? "you" : y_monnam(mdef)); if (was_u) @@ -4914,36 +4930,33 @@ mhitm_knockback( * mhitm: The fire giant knocks the gnome back with a forceful strike! */ pline("%s %s %s %s with a %s %s!", - magrbuf, vtense(magrbuf, "knock"), mdefbuf, - dosteed ? "out of your saddle" : "back", + magrbuf, vtense(magrbuf, "knock"), mdefbuf, knockedhow, rn2(2) ? "forceful" : "powerful", rn2(2) ? "blow" : "strike"); } else if (u_agr) { /* hero knocks unseen foe back; noticed by touch */ - You("knock %s back!", some_mon_nam(mdef)); + You_feel("%s be knocked %s!", some_mon_nam(mdef), knockedhow); } /* do the actual knockback effect */ if (u_def) { - /* normally dx,dy indicates direction hero is throwing, zapping, &c - but here it is used to pass the preferred direction for dismount - to dismount_steed (used for DISMOUNT_KNOCKED only) */ - u.dx = sgn(u.ux - magr->mx); /* [sgn() is superfluous here] */ - u.dy = sgn(u.uy - magr->my); /* [ditto] */ - if (u.usteed) + if (dismount) { + /* normally u.dx,u.dy indicates the direction hero is throwing, + zapping, &c but here it is used to pass preferred direction + for dismount to dismount_steed (for DISMOUNT_KNOCKED only) */ + u.dx = dx; + u.dy = dy; dismount_steed(DISMOUNT_KNOCKED); - else - hurtle(u.dx, u.dy, rnd(2), FALSE); - + } else { + hurtle(dx, dy, knockdistance, FALSE); + } set_apparxy(magr); /* update magr's idea of where you are */ if (!Stunned && !rn2(4)) - make_stunned((long) rn1(2, 2), TRUE); /* 0..1 + 2 => 2..3 */ + make_stunned((long) (knockdistance + 1), TRUE); /* 2 or 3 */ } else { - coordxy x = u_agr ? u.ux : magr->mx; - coordxy y = u_agr ? u.uy : magr->my; - - mhurtle(mdef, mdef->mx - x, mdef->my - y, rnd(2)); - if (DEADMONSTER(mdef) && !was_u) { - *hitflags |= MM_DEF_DIED; + mhurtle(mdef, dx, dy, knockdistance); + if (DEADMONSTER(mdef)) { + if (!was_u) + *hitflags |= MM_DEF_DIED; } else if (!rn2(4)) { mdef->mstun = 1; /* if steed and hero were knocked back, update attacker's idea