knockback feedback

Adjust the message given when an attack knocks its target back.  Say
|<defender> is knocked backward by <attacker>
if target will actually move or
|<defender> is knocked back by <attacker>
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.
This commit is contained in:
PatR
2023-03-11 11:21:09 -08:00
parent 754e9333f5
commit 74ed2999de
3 changed files with 58 additions and 34 deletions
+3 -2
View File
@@ -644,6 +644,9 @@ extern int dothrow(void);
extern int dofire(void); extern int dofire(void);
extern void endmultishot(boolean); extern void endmultishot(boolean);
extern void hitfloor(struct obj *, 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 hurtle(int, int, int, boolean);
extern void mhurtle(struct monst *, int, int, int); extern void mhurtle(struct monst *, int, int, int);
extern boolean harmless_missile(struct obj *); 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 breaktest(struct obj *);
extern boolean walk_path(coord *, coord *, extern boolean walk_path(coord *, coord *,
boolean(*)(void *, coordxy, coordxy), genericptr_t); boolean(*)(void *, coordxy, coordxy), genericptr_t);
extern boolean hurtle_jump(genericptr_t, coordxy, coordxy);
extern boolean hurtle_step(genericptr_t, coordxy, coordxy);
/* ### drawing.c ### */ /* ### drawing.c ### */
+15 -5
View File
@@ -975,20 +975,30 @@ hurtle_step(genericptr_t arg, coordxy x, coordxy y)
return TRUE; 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 static boolean
mhurtle_step(genericptr_t arg, coordxy x, coordxy y) mhurtle_step(genericptr_t arg, coordxy x, coordxy y)
{ {
struct monst *mon = (struct monst *) arg; struct monst *mon = (struct monst *) arg;
struct monst *mtmp; struct monst *mtmp;
/* TODO: Treat walls, doors, iron bars, etc. specially
* rather than just stopping before.
*/
if (!isok(x, y)) if (!isok(x, y))
return FALSE; return FALSE;
if (goodpos(x, y, mon, MM_IGNOREWATER | MM_IGNORELAVA) if (will_hurtle(mon, x, y) && m_in_out_region(mon, x, y)) {
&& m_in_out_region(mon, x, y)) {
int res; int res;
if (mon != u.usteed) { if (mon != u.usteed) {
+40 -27
View File
@@ -4843,20 +4843,26 @@ mhitm_knockback(
{ {
char magrbuf[BUFSZ], mdefbuf[BUFSZ]; char magrbuf[BUFSZ], mdefbuf[BUFSZ];
struct obj *otmp; 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_agr = (magr == &gy.youmonst);
boolean u_def = (mdef == &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 */ /* 1/6 chance of attack knocking back a monster */
if (rn2(6)) if (rn2(6))
return FALSE; return FALSE;
/* if hero is stuck to a cursed saddle, knock the steed back */ /* if hero is stuck to a cursed saddle, knock the steed back */
if (u_def && u.usteed if (u_def && u.usteed) {
&& (otmp = which_armor(u.usteed, W_SADDLE)) != 0 && otmp->cursed) { if ((otmp = which_armor(u.usteed, W_SADDLE)) != 0 && otmp->cursed) {
mdef = u.usteed; mdef = u.usteed;
was_u = TRUE; was_u = TRUE;
u_def = FALSE; u_def = FALSE;
} else {
dismount = TRUE; /* saddle is not cursed; knock hero out of it */
}
} }
/* monsters must be alive */ /* monsters must be alive */
@@ -4899,10 +4905,20 @@ mhitm_knockback(
return FALSE; 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 */ /* give the message */
if (u_def || canseemon(mdef)) { if (u_def || canseemon(mdef)) {
boolean dosteed = u_def && u.usteed;
Strcpy(magrbuf, u_agr ? "You" : Monnam(magr)); Strcpy(magrbuf, u_agr ? "You" : Monnam(magr));
Strcpy(mdefbuf, (u_def || was_u) ? "you" : y_monnam(mdef)); Strcpy(mdefbuf, (u_def || was_u) ? "you" : y_monnam(mdef));
if (was_u) if (was_u)
@@ -4914,36 +4930,33 @@ mhitm_knockback(
* mhitm: The fire giant knocks the gnome back with a forceful strike! * mhitm: The fire giant knocks the gnome back with a forceful strike!
*/ */
pline("%s %s %s %s with a %s %s!", pline("%s %s %s %s with a %s %s!",
magrbuf, vtense(magrbuf, "knock"), mdefbuf, magrbuf, vtense(magrbuf, "knock"), mdefbuf, knockedhow,
dosteed ? "out of your saddle" : "back",
rn2(2) ? "forceful" : "powerful", rn2(2) ? "blow" : "strike"); rn2(2) ? "forceful" : "powerful", rn2(2) ? "blow" : "strike");
} else if (u_agr) { } else if (u_agr) {
/* hero knocks unseen foe back; noticed by touch */ /* 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 */ /* do the actual knockback effect */
if (u_def) { if (u_def) {
/* normally dx,dy indicates direction hero is throwing, zapping, &c if (dismount) {
but here it is used to pass the preferred direction for dismount /* normally u.dx,u.dy indicates the direction hero is throwing,
to dismount_steed (used for DISMOUNT_KNOCKED only) */ zapping, &c but here it is used to pass preferred direction
u.dx = sgn(u.ux - magr->mx); /* [sgn() is superfluous here] */ for dismount to dismount_steed (for DISMOUNT_KNOCKED only) */
u.dy = sgn(u.uy - magr->my); /* [ditto] */ u.dx = dx;
if (u.usteed) u.dy = dy;
dismount_steed(DISMOUNT_KNOCKED); dismount_steed(DISMOUNT_KNOCKED);
else } else {
hurtle(u.dx, u.dy, rnd(2), FALSE); hurtle(dx, dy, knockdistance, FALSE);
}
set_apparxy(magr); /* update magr's idea of where you are */ set_apparxy(magr); /* update magr's idea of where you are */
if (!Stunned && !rn2(4)) 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 { } else {
coordxy x = u_agr ? u.ux : magr->mx; mhurtle(mdef, dx, dy, knockdistance);
coordxy y = u_agr ? u.uy : magr->my; if (DEADMONSTER(mdef)) {
if (!was_u)
mhurtle(mdef, mdef->mx - x, mdef->my - y, rnd(2)); *hitflags |= MM_DEF_DIED;
if (DEADMONSTER(mdef) && !was_u) {
*hitflags |= MM_DEF_DIED;
} else if (!rn2(4)) { } else if (!rn2(4)) {
mdef->mstun = 1; mdef->mstun = 1;
/* if steed and hero were knocked back, update attacker's idea /* if steed and hero were knocked back, update attacker's idea