]> granicus.if.org Git - nethack/commitdiff
getting knocked off flying steed
authorPatR <rankin@nethack.org>
Mon, 3 Oct 2022 22:53:35 +0000 (15:53 -0700)
committerPatR <rankin@nethack.org>
Mon, 3 Oct 2022 22:53:35 +0000 (15:53 -0700)
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.

include/hack.h
src/steed.c
src/uhitm.c

index 59beb4ce761cc258ccf0fe9821b1d005e02b083f..af66cd132c38afe7006afad2c051911f486dbe0e 100644 (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) Pasi Kallinen, 2017. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -75,10 +75,11 @@ enum dismount_types {
     DISMOUNT_GENERIC  = 0,
     DISMOUNT_FELL     = 1,
     DISMOUNT_THROWN   = 2,
-    DISMOUNT_POLY     = 3,
-    DISMOUNT_ENGULFED = 4,
-    DISMOUNT_BONES    = 5,
-    DISMOUNT_BYCHOICE = 6
+    DISMOUNT_KNOCKED  = 3, /* hero hit for knockback effect */
+    DISMOUNT_POLY     = 4,
+    DISMOUNT_ENGULFED = 5,
+    DISMOUNT_BONES    = 6,
+    DISMOUNT_BYCHOICE = 7
 };
 
 /* polyself flags */
index 515d3581932cb617a0ac3fc45f1996ff599a6293..68de17f851e342dfcf95760ac79d84d73d77977e 100644 (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. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -445,6 +445,13 @@ landing_spot(
     boolean found = FALSE;
     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 */
     if (reason != DISMOUNT_BYCHOICE || Stunned || Confusion || Fumbling)
         i = 1;
@@ -498,18 +505,21 @@ dismount_steed(
     /* Sanity check */
     if (!mtmp) /* Just return silently */
         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;
     ulev = Levitation ? TRUE : FALSE;
+    verb = u_locomotion("fall"); /* only used for _FELL and _KNOCKED */
     u.usteed = mtmp;
 
     /* Check the reason for dismounting */
     otmp = which_armor(mtmp, W_SADDLE);
     switch (reason) {
     case DISMOUNT_THROWN:
+        verb = "are thrown";
+        /*FALLTHRU*/
+    case DISMOUNT_KNOCKED:
     case DISMOUNT_FELL:
-        verb = (reason == DISMOUNT_THROWN) ? "are thrown"
-            : u_locomotion("fall");
         You("%s off of %s!", verb, mon_nam(mtmp));
         if (!have_spot)
             have_spot = landing_spot(&cc, reason, 1);
index 779ccef554c8e27910765641dac6b2d4119ec2f5..cb369e0f372a06235d4b9804d5650bd17bdb2849 100644 (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) Robert Patrick Rankin, 2012. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -1511,6 +1511,8 @@ hmon_hitmon(
     return destroyed ? FALSE : TRUE;
 }
 
+RESTORE_WARNING_FORMAT_NONLITERAL
+
 /* 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;
    return True if we kill mon, False otherwise */
@@ -1586,8 +1588,6 @@ shade_aware(struct obj *obj)
     return FALSE;
 }
 
-RESTORE_WARNING_FORMAT_NONLITERAL
-
 /* 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 */
 boolean
@@ -4593,8 +4593,8 @@ m_is_steadfast(struct monst *mtmp)
     struct obj *otmp = is_u ? uwep : MON_WEP(mtmp);
 
     /* must be on the ground */
-    if ((is_u && (Flying || Levitation))
-        || (!is_u && (is_flyer(mtmp->data) || is_floater(mtmp->data))))
+    if (is_u ? (Flying || Levitation)
+             : (is_flyer(mtmp->data) || is_floater(mtmp->data)))
         return FALSE;
 
     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? */
 boolean
-mhitm_knockback(struct monst *magr,
-                struct monst *mdef,
-                struct attack *mattk,
-                int *hitflags,
-                boolean weapon_used)
+mhitm_knockback(
+    struct monst *magr,   /* attacker; might be hero */
+    struct monst *mdef,   /* defender; might be hero (only if magr isn't)  */
+    struct attack *mattk, /* attack type and damage info */
+    int *hitflags,        /* modified if magr or mdef dies */
+    boolean weapon_used)  /* True: via weapon hit */
 {
     boolean u_agr = (magr == &g.youmonst);
     boolean u_def = (mdef == &g.youmonst);
@@ -4651,10 +4652,13 @@ mhitm_knockback(struct monst *magr,
     if (u_def || canseemon(mdef)) {
         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! */
-        /* mhitm: The fire giant knocks the gnome back with a forceful strike! */
-
+        /*
+         * uhitm: You knock the gnome back with a powerful blow!
+         * 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!",
               u_agr ? "You" : Monnam(magr),
               u_agr ? "" : "s",
@@ -4662,22 +4666,25 @@ mhitm_knockback(struct monst *magr,
               dosteed ? "out of your saddle" : "back",
               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));
     }
 
     /* do the actual knockback effect */
     if (u_def) {
         if (u.usteed)
-            dismount_steed(DISMOUNT_FELL);
+            dismount_steed(DISMOUNT_KNOCKED);
         else
             hurtle(u.ux - magr->mx, u.uy - magr->my, rnd(2), FALSE);
+
         if (!rn2(4))
-            make_stunned((HStun & TIMEOUT) + (long) rnd(2) + 1, TRUE);
+            make_stunned((HStun & TIMEOUT) + (long) rnd(2) + 1L, TRUE);
     } 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));
+        mhurtle(mdef, mdef->mx - x, mdef->my - y, rnd(2));
         if (DEADMONSTER(mdef))
             *hitflags |= MM_DEF_DIED;
         else if (!rn2(4))