getting knocked off flying steed

I was trying to reproduce the reported "no monster to remove" warning
from remove_monster() when a mounted hero was knocked off jabberwocky
steed but so far haven't been able to.

While trying, I came across a more minor bug.  The hero got knocked
off a flying steed and got feedback of "you fly off" rather than
"you fall off".  Flying capability came from the steed and dismount
feedback is aware of that but calls u_locomotion() which isn't.  This
commit fixes that.

This adds some groundwork (DISMOUNT_KNOCKED) for better dismount
control.  With a map fragment of
|....
|.Du.
|....
I got knocked off my steed by the attacking dragon and ended up with
|..@.
|.Du.
|....
It would be better to prefer spot 1, then the 2s, then 3s, then 4s
(not sure about farther spots if none of those are available)
|.432
|.D@1
|.432
when forced to dismount by knockback.  This does _not_ implement that.
This commit is contained in:
PatR
2022-10-03 15:53:35 -07:00
parent a8bfeb4dca
commit 546fea7db8
3 changed files with 45 additions and 27 deletions
+6 -5
View File
@@ -1,4 +1,4 @@
/* NetHack 3.7 hack.h $NHDT-Date: 1652861829 2022/05/18 08:17:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.181 $ */ /* NetHack 3.7 hack.h $NHDT-Date: 1664837602 2022/10/03 22:53:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.196 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Pasi Kallinen, 2017. */ /*-Copyright (c) Pasi Kallinen, 2017. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -75,10 +75,11 @@ enum dismount_types {
DISMOUNT_GENERIC = 0, DISMOUNT_GENERIC = 0,
DISMOUNT_FELL = 1, DISMOUNT_FELL = 1,
DISMOUNT_THROWN = 2, DISMOUNT_THROWN = 2,
DISMOUNT_POLY = 3, DISMOUNT_KNOCKED = 3, /* hero hit for knockback effect */
DISMOUNT_ENGULFED = 4, DISMOUNT_POLY = 4,
DISMOUNT_BONES = 5, DISMOUNT_ENGULFED = 5,
DISMOUNT_BYCHOICE = 6 DISMOUNT_BONES = 6,
DISMOUNT_BYCHOICE = 7
}; };
/* polyself flags */ /* polyself flags */
+14 -4
View File
@@ -1,4 +1,4 @@
/* NetHack 3.7 steed.c $NHDT-Date: 1646171628 2022/03/01 21:53:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.95 $ */ /* NetHack 3.7 steed.c $NHDT-Date: 1664837604 2022/10/03 22:53:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.100 $ */
/* Copyright (c) Kevin Hugo, 1998-1999. */ /* Copyright (c) Kevin Hugo, 1998-1999. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -445,6 +445,13 @@ landing_spot(
boolean found = FALSE; boolean found = FALSE;
struct trap *t; struct trap *t;
/*
* TODO:
* for reason==DISMOUNT_KNOCKED, prefer the spot directly behind
* current position relative to the attacker; first need to figure
* how to obtain attacker information...
*/
/* avoid known traps (i == 0) and boulders, but allow them as a backup */ /* avoid known traps (i == 0) and boulders, but allow them as a backup */
if (reason != DISMOUNT_BYCHOICE || Stunned || Confusion || Fumbling) if (reason != DISMOUNT_BYCHOICE || Stunned || Confusion || Fumbling)
i = 1; i = 1;
@@ -498,18 +505,21 @@ dismount_steed(
/* Sanity check */ /* Sanity check */
if (!mtmp) /* Just return silently */ if (!mtmp) /* Just return silently */
return; return;
u.usteed = 0; /* affects Fly test; could hypothetically affect Lev */ u.usteed = 0; /* affects Fly test; could hypothetically affect Lev;
* also affects u_locomotion() */
ufly = Flying ? TRUE : FALSE; ufly = Flying ? TRUE : FALSE;
ulev = Levitation ? TRUE : FALSE; ulev = Levitation ? TRUE : FALSE;
verb = u_locomotion("fall"); /* only used for _FELL and _KNOCKED */
u.usteed = mtmp; u.usteed = mtmp;
/* Check the reason for dismounting */ /* Check the reason for dismounting */
otmp = which_armor(mtmp, W_SADDLE); otmp = which_armor(mtmp, W_SADDLE);
switch (reason) { switch (reason) {
case DISMOUNT_THROWN: case DISMOUNT_THROWN:
verb = "are thrown";
/*FALLTHRU*/
case DISMOUNT_KNOCKED:
case DISMOUNT_FELL: case DISMOUNT_FELL:
verb = (reason == DISMOUNT_THROWN) ? "are thrown"
: u_locomotion("fall");
You("%s off of %s!", verb, mon_nam(mtmp)); You("%s off of %s!", verb, mon_nam(mtmp));
if (!have_spot) if (!have_spot)
have_spot = landing_spot(&cc, reason, 1); have_spot = landing_spot(&cc, reason, 1);
+25 -18
View File
@@ -1,4 +1,4 @@
/* NetHack 3.7 uhitm.c $NHDT-Date: 1650963745 2022/04/26 09:02:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.348 $ */ /* NetHack 3.7 uhitm.c $NHDT-Date: 1664837605 2022/10/03 22:53:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.364 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1511,6 +1511,8 @@ hmon_hitmon(
return destroyed ? FALSE : TRUE; return destroyed ? FALSE : TRUE;
} }
RESTORE_WARNING_FORMAT_NONLITERAL
/* joust or martial arts punch is knocking the target back; that might /* joust or martial arts punch is knocking the target back; that might
kill 'mon' (via trap) before known_hitum() has a chance to do so; kill 'mon' (via trap) before known_hitum() has a chance to do so;
return True if we kill mon, False otherwise */ return True if we kill mon, False otherwise */
@@ -1586,8 +1588,6 @@ shade_aware(struct obj *obj)
return FALSE; return FALSE;
} }
RESTORE_WARNING_FORMAT_NONLITERAL
/* used for hero vs monster and monster vs monster; also handles /* used for hero vs monster and monster vs monster; also handles
monster vs hero but that won't happen because hero can't be a shade */ monster vs hero but that won't happen because hero can't be a shade */
boolean boolean
@@ -4593,8 +4593,8 @@ m_is_steadfast(struct monst *mtmp)
struct obj *otmp = is_u ? uwep : MON_WEP(mtmp); struct obj *otmp = is_u ? uwep : MON_WEP(mtmp);
/* must be on the ground */ /* must be on the ground */
if ((is_u && (Flying || Levitation)) if (is_u ? (Flying || Levitation)
|| (!is_u && (is_flyer(mtmp->data) || is_floater(mtmp->data)))) : (is_flyer(mtmp->data) || is_floater(mtmp->data)))
return FALSE; return FALSE;
if (is_art(otmp, ART_GIANTSLAYER)) if (is_art(otmp, ART_GIANTSLAYER))
@@ -4604,11 +4604,12 @@ m_is_steadfast(struct monst *mtmp)
/* monster hits another monster hard enough to knock it back? */ /* monster hits another monster hard enough to knock it back? */
boolean boolean
mhitm_knockback(struct monst *magr, mhitm_knockback(
struct monst *mdef, struct monst *magr, /* attacker; might be hero */
struct attack *mattk, struct monst *mdef, /* defender; might be hero (only if magr isn't) */
int *hitflags, struct attack *mattk, /* attack type and damage info */
boolean weapon_used) int *hitflags, /* modified if magr or mdef dies */
boolean weapon_used) /* True: via weapon hit */
{ {
boolean u_agr = (magr == &g.youmonst); boolean u_agr = (magr == &g.youmonst);
boolean u_def = (mdef == &g.youmonst); boolean u_def = (mdef == &g.youmonst);
@@ -4651,10 +4652,13 @@ mhitm_knockback(struct monst *magr,
if (u_def || canseemon(mdef)) { if (u_def || canseemon(mdef)) {
boolean dosteed = u_def && u.usteed; boolean dosteed = u_def && u.usteed;
/* uhitm: You knock the gnome back with a powerful blow! */ /*
/* mhitu: The red dragon knocks you back with a forceful blow! */ * uhitm: You knock the gnome back with a powerful blow!
/* mhitm: The fire giant knocks the gnome back with a forceful strike! */ * mhitu: The red dragon knocks you back with a forceful blow!
* mhitm: The fire giant knocks the gnome back with a forceful strike!
*
* TODO? if saddle is cursed, knock both hero and steed back?
*/
pline("%s knock%s %s %s with a %s %s!", pline("%s knock%s %s %s with a %s %s!",
u_agr ? "You" : Monnam(magr), u_agr ? "You" : Monnam(magr),
u_agr ? "" : "s", u_agr ? "" : "s",
@@ -4662,22 +4666,25 @@ mhitm_knockback(struct monst *magr,
dosteed ? "out of your saddle" : "back", dosteed ? "out of your saddle" : "back",
rn2(2) ? "forceful" : "powerful", rn2(2) ? "forceful" : "powerful",
rn2(2) ? "blow" : "strike"); rn2(2) ? "blow" : "strike");
} else if (u_agr) {
/* hero knocks unseen foe back; noticed by touch */
You("knock %s back!", some_mon_nam(mdef));
} }
/* do the actual knockback effect */ /* do the actual knockback effect */
if (u_def) { if (u_def) {
if (u.usteed) if (u.usteed)
dismount_steed(DISMOUNT_FELL); dismount_steed(DISMOUNT_KNOCKED);
else else
hurtle(u.ux - magr->mx, u.uy - magr->my, rnd(2), FALSE); hurtle(u.ux - magr->mx, u.uy - magr->my, rnd(2), FALSE);
if (!rn2(4)) if (!rn2(4))
make_stunned((HStun & TIMEOUT) + (long) rnd(2) + 1, TRUE); make_stunned((HStun & TIMEOUT) + (long) rnd(2) + 1L, TRUE);
} else { } else {
coordxy x = u_agr ? u.ux : magr->mx; coordxy x = u_agr ? u.ux : magr->mx;
coordxy y = u_agr ? u.uy : magr->my; coordxy y = u_agr ? u.uy : magr->my;
mhurtle(mdef, mdef->mx - x, mhurtle(mdef, mdef->mx - x, mdef->my - y, rnd(2));
mdef->my - y, rnd(2));
if (DEADMONSTER(mdef)) if (DEADMONSTER(mdef))
*hitflags |= MM_DEF_DIED; *hitflags |= MM_DEF_DIED;
else if (!rn2(4)) else if (!rn2(4))