]> granicus.if.org Git - nethack/commitdiff
mnearto/mnexto/enexto
authorPatR <rankin@nethack.org>
Thu, 30 May 2019 14:50:38 +0000 (07:50 -0700)
committerPatR <rankin@nethack.org>
Thu, 30 May 2019 14:50:38 +0000 (07:50 -0700)
This doesn't solve the <0,0> problem but it does prevent mnexto()
from using uninitialized coordinates if enexto() fails.  It also adds
several debugging messages.

enexto() was ignoring map row #0 (unlike column #0, row #0 contains
valid map locations).  Fixing that doesn't matter for Plane of Water
though since that row is stone there--that's probably a bug.  It was
also repeatedly re-testing the top+1 and bottom rows and left and
right columns after they had already failed to be acceptable.  It
still does some of that, but less.

include/hack.h
src/mkmaze.c
src/mon.c
src/teleport.c

index f686f7a4a178e69355220b1855cd3edec6331e51..8cb0b7253031e9a39f1271b2ae0d78bc7abf8de6 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 hack.h  $NHDT-Date: 1549327459 2019/02/05 00:44:19 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.102 $ */
+/* NetHack 3.6 hack.h  $NHDT-Date: 1559227823 2019/05/30 14:50:23 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.105 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Pasi Kallinen, 2017. */
 /* NetHack may be freely redistributed.  See license for details. */
 #define OFF 0
 #define BOLT_LIM 8        /* from this distance ranged attacks will be made */
 #define MAX_CARR_CAP 1000 /* so that boulders can be heavier */
-#define DUMMY \
-    {         \
-        0     \
-    }
+#define DUMMY { 0 }       /* array initializer, letting [1..N-1] default */
 
 /* symbolic names for capacity levels */
 enum encumbrance_types {
@@ -244,24 +241,25 @@ typedef struct sortloot_item Loot;
 #include "extern.h"
 #endif /* USE_TRAMPOLI */
 
-/* flags to control makemon() */
+/* flags to control makemon(); goodpos() uses some plus has some of its own */
 #define NO_MM_FLAGS 0x00000 /* use this rather than plain 0 */
-#define NO_MINVENT 0x00001  /* suppress minvent when creating mon */
-#define MM_NOWAIT 0x00002   /* don't set STRAT_WAITMASK flags */
-#define MM_NOCOUNTBIRTH \
-    0x00004 /* don't increment born counter (for revival) */
-#define MM_IGNOREWATER 0x00008 /* ignore water when positioning */
-#define MM_ADJACENTOK \
-    0x00010               /* it is acceptable to use adjacent coordinates */
-#define MM_ANGRY  0x00020  /* monster is created angry */
-#define MM_NONAME 0x00040 /* monster is not christened */
-#define MM_EGD    0x00100    /* add egd structure */
-#define MM_EPRI   0x00200   /* add epri structure */
-#define MM_ESHK   0x00400   /* add eshk structure */
-#define MM_EMIN   0x00800   /* add emin structure */
-#define MM_EDOG   0x01000   /* add edog structure */
-#define MM_ASLEEP 0x02000   /* monsters should be generated asleep */
-#define MM_NOGRP  0x04000   /* suppress creation of monster groups */
+#define NO_MINVENT  0x00001 /* suppress minvent when creating mon */
+#define MM_NOWAIT   0x00002 /* don't set STRAT_WAITMASK flags */
+#define MM_NOCOUNTBIRTH 0x00004 /* don't increment born count (for revival) */
+#define MM_IGNOREWATER  0x00008 /* ignore water when positioning */
+#define MM_ADJACENTOK   0x00010 /* acceptable to use adjacent coordinates */
+#define MM_ANGRY    0x00020 /* monster is created angry */
+#define MM_NONAME   0x00040 /* monster is not christened */
+#define MM_EGD      0x00100 /* add egd structure */
+#define MM_EPRI     0x00200 /* add epri structure */
+#define MM_ESHK     0x00400 /* add eshk structure */
+#define MM_EMIN     0x00800 /* add emin structure */
+#define MM_EDOG     0x01000 /* add edog structure */
+#define MM_ASLEEP   0x02000 /* monsters should be generated asleep */
+#define MM_NOGRP    0x04000 /* suppress creation of monster groups */
+/* if more MM_ flag masks are added, skip or renumber the GP_ one(s) */
+#define GP_ALLOW_XY 0x08000 /* [actually used by enexto() to decide whether
+                             * to make an extra call to goodpos()]          */
 
 /* flags for make_corpse() and mkcorpstat() */
 #define CORPSTAT_NONE 0x00
@@ -293,27 +291,27 @@ typedef struct sortloot_item Loot;
 #define ALL_FINISHED 0x01 /* called routine already finished the job */
 
 /* flags to control query_objlist() */
-#define BY_NEXTHERE 0x1       /* follow objlist by nexthere field */
-#define AUTOSELECT_SINGLE 0x2 /* if only 1 object, don't ask */
-#define USE_INVLET 0x4        /* use object's invlet */
-#define INVORDER_SORT 0x8     /* sort objects by packorder */
-#define SIGNAL_NOMENU 0x10    /* return -1 rather than 0 if none allowed */
-#define SIGNAL_ESCAPE 0x20    /* return -2 rather than 0 for ESC */
-#define FEEL_COCKATRICE 0x40  /* engage cockatrice checks and react */
-#define INCLUDE_HERO 0x80     /* show hero among engulfer's inventory */
+#define BY_NEXTHERE     0x01   /* follow objlist by nexthere field */
+#define AUTOSELECT_SINGLE 0x02 /* if only 1 object, don't ask */
+#define USE_INVLET      0x04   /* use object's invlet */
+#define INVORDER_SORT   0x08   /* sort objects by packorder */
+#define SIGNAL_NOMENU   0x10   /* return -1 rather than 0 if none allowed */
+#define SIGNAL_ESCAPE   0x20   /* return -2 rather than 0 for ESC */
+#define FEEL_COCKATRICE 0x40   /* engage cockatrice checks and react */
+#define INCLUDE_HERO    0x80   /* show hero among engulfer's inventory */
 
 /* Flags to control query_category() */
 /* BY_NEXTHERE used by query_category() too, so skip 0x01 */
-#define UNPAID_TYPES 0x02
-#define GOLD_TYPES 0x04
-#define WORN_TYPES 0x08
-#define ALL_TYPES 0x10
-#define BILLED_TYPES 0x20
-#define CHOOSE_ALL 0x40
-#define BUC_BLESSED 0x80
-#define BUC_CURSED 0x100
+#define UNPAID_TYPES 0x002
+#define GOLD_TYPES   0x004
+#define WORN_TYPES   0x008
+#define ALL_TYPES    0x010
+#define BILLED_TYPES 0x020
+#define CHOOSE_ALL   0x040
+#define BUC_BLESSED  0x080
+#define BUC_CURSED   0x100
 #define BUC_UNCURSED 0x200
-#define BUC_UNKNOWN 0x400
+#define BUC_UNKNOWN  0x400
 #define BUC_ALLBKNOWN (BUC_BLESSED | BUC_CURSED | BUC_UNCURSED)
 #define BUCX_TYPES (BUC_ALLBKNOWN | BUC_UNKNOWN)
 #define ALL_TYPES_SELECTED -2
index 7bea6485e8306d4d951a2d62a21a933b232a9909..a660faf99b063c6b6eca7080c8ff132c039aa836 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 mkmaze.c        $NHDT-Date: 1559088524 2019/05/29 00:08:44 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.71 $ */
+/* NetHack 3.6 mkmaze.c        $NHDT-Date: 1559227829 2019/05/30 14:50:29 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.72 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Pasi Kallinen, 2018. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -1858,6 +1858,7 @@ boolean ini;
                 for (olist = (struct obj *) cons->list; olist; olist = otmp) {
                     otmp = olist->nexthere;
                     place_object(olist, cons->x, cons->y);
+                    stackobj(olist);
                 }
                 break;
             }
@@ -1865,7 +1866,12 @@ boolean ini;
             case CONS_MON: {
                 struct monst *mon = (struct monst *) cons->list;
 
-                (void) mnearto(mon, cons->x, cons->y, TRUE);
+                /* mnearto() might fail, and putting the monster into limbo
+                   to try next time hero comes to this level makes no sense
+                   because we can't leave and return (outside wizard mode) */
+                if (!mnearto(mon, cons->x, cons->y, TRUE)) {
+                    ; /* ? */
+                }
                 break;
             }
 
index 7bb0d0f9886e2a76f15a4267368012a4534b4040..de07a96a6db121aa2cdc0b63b6fc31e461d5f815 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -1,4 +1,4 @@
-/* NetHack 3.6 mon.c   $NHDT-Date: 1556139724 2019/04/24 21:02:04 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.284 $ */
+/* NetHack 3.6 mon.c   $NHDT-Date: 1559227828 2019/05/30 14:50:28 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.286 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Derek S. Ray, 2015. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -2595,12 +2595,11 @@ struct monst *mtmp;
         return;
     }
 
-    if (!enexto(&mm, u.ux, u.uy, mtmp->data)) {
+    if (!enexto(&mm, u.ux, u.uy, mtmp->data) || !isok(mm.x, mm.y)) {
+        debugpline1("mnexto: sending %s into limbo", m_monnam(mtmp));
         m_into_limbo(mtmp);
         return;
     }
-    if (!isok(mm.x, mm.y))
-        return;
     rloc_to(mtmp, mm.x, mm.y);
     if (!in_mklev && (mtmp->mstrategy & STRAT_APPEARMSG)) {
         mtmp->mstrategy &= ~STRAT_APPEARMSG; /* one chance only */
@@ -2674,9 +2673,7 @@ boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */
          * Migrating_mons that need to be placed will cause
          * no end of trouble.
          */
-        if (!enexto(&mm, newx, newy, mtmp->data))
-            return 0;
-        if (!isok(mm.x, mm.y))
+        if (!enexto(&mm, newx, newy, mtmp->data) || !isok(mm.x, mm.y))
             return 0;
         newx = mm.x;
         newy = mm.y;
@@ -2685,8 +2682,10 @@ boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */
 
     if (move_other && othermon) {
         res = 2; /* moving another monster out of the way */
-        if (!mnearto(othermon, x, y, FALSE)) /* no 'move_other' this time */
+        if (!mnearto(othermon, x, y, FALSE)) { /* no 'move_other' this time */
+            debugpline1("mnearto: sending %s into limbo", m_monnam(othermon));
             m_into_limbo(othermon);
+        }
     }
 
     return res;
index 76d36f35caa49359a6dd61d64d4f1d283c6f8f40..fe5689aeb24bf4b268073c35f33adb74d2f8c56b 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 teleport.c      $NHDT-Date: 1553885439 2019/03/29 18:50:39 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.86 $ */
+/* NetHack 3.6 teleport.c      $NHDT-Date: 1559227830 2019/05/30 14:50:30 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.87 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2011. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -39,7 +39,8 @@ unsigned gpflags;
      * which could be co-located and thus get restricted a bit too much.
      * oh well.
      */
-    if (mtmp != &youmonst && x == u.ux && y == u.uy
+    if (x == u.ux && y == u.uy
+        && mtmp != &youmonst && (mtmp != u.ustuck || !u.uswallow)
         && (!u.usteed || mtmp != u.usteed))
         return FALSE;
 
@@ -108,22 +109,24 @@ coord *cc;
 register xchar xx, yy;
 struct permonst *mdat;
 {
-    return enexto_core(cc, xx, yy, mdat, 0);
+    return enexto_core(cc, xx, yy, mdat, NO_MM_FLAGS);
 }
 
 boolean
 enexto_core(cc, xx, yy, mdat, entflags)
 coord *cc;
-register xchar xx, yy;
+xchar xx, yy;
 struct permonst *mdat;
 unsigned entflags;
 {
 #define MAX_GOOD 15
     coord good[MAX_GOOD], *good_ptr;
     int x, y, range, i;
-    int xmin, xmax, ymin, ymax;
+    int xmin, xmax, ymin, ymax, rangemax;
     struct monst fakemon; /* dummy monster */
+    boolean allow_xx_yy = (boolean) ((entflags & GP_ALLOW_XY) != 0);
 
+    entflags &= ~GP_ALLOW_XY;
     if (!mdat) {
         debugpline0("enexto() called with null mdat");
         /* default to player's original monster type */
@@ -132,6 +135,13 @@ unsigned entflags;
     fakemon = zeromonst;
     set_mon_data(&fakemon, mdat); /* set up for goodpos */
 
+    /* used to use 'if (range > ROWNO && range > COLNO) return FALSE' below,
+       so effectively 'max(ROWNO, COLNO)' which performs useless iterations
+       (possibly many iterations if <xx,yy> is in the center of the map) */
+    xmax = max(xx - 1, (COLNO - 1) - xx);
+    ymax = max(yy - 0, (ROWNO - 1) - yy);
+    rangemax = max(xmax, ymax);
+    /* setup: no suitable spots yet, first iteration checks adjacent spots */
     good_ptr = good;
     range = 1;
     /*
@@ -144,7 +154,7 @@ unsigned entflags;
         ymin = max(0, yy - range);
         ymax = min(ROWNO - 1, yy + range);
 
-        for (x = xmin; x <= xmax; x++)
+        for (x = xmin; x <= xmax; x++) {
             if (goodpos(x, ymin, &fakemon, entflags)) {
                 good_ptr->x = x;
                 good_ptr->y = ymin;
@@ -152,38 +162,46 @@ unsigned entflags;
                 if (good_ptr++ == &good[MAX_GOOD - 1])
                     goto full;
             }
-        for (x = xmin; x <= xmax; x++)
             if (goodpos(x, ymax, &fakemon, entflags)) {
                 good_ptr->x = x;
                 good_ptr->y = ymax;
-                /* beware of accessing beyond segment boundaries.. */
                 if (good_ptr++ == &good[MAX_GOOD - 1])
                     goto full;
             }
-        for (y = ymin + 1; y < ymax; y++)
+        }
+        /* 3.6.3: this used to use 'ymin+1' which left top row unchecked */
+        for (y = ymin; y < ymax; y++) {
             if (goodpos(xmin, y, &fakemon, entflags)) {
                 good_ptr->x = xmin;
                 good_ptr->y = y;
-                /* beware of accessing beyond segment boundaries.. */
                 if (good_ptr++ == &good[MAX_GOOD - 1])
                     goto full;
             }
-        for (y = ymin + 1; y < ymax; y++)
             if (goodpos(xmax, y, &fakemon, entflags)) {
                 good_ptr->x = xmax;
                 good_ptr->y = y;
-                /* beware of accessing beyond segment boundaries.. */
                 if (good_ptr++ == &good[MAX_GOOD - 1])
                     goto full;
             }
-        range++;
-
-        /* return if we've grown too big (nothing is valid) */
-        if (range > ROWNO && range > COLNO)
+        }
+    } while (++range <= rangemax && good_ptr == good);
+
+    /* return False if we exhausted 'range' without finding anything */
+    if (good_ptr == good) {
+        /* 3.6.3: earlier versions didn't have the option to try <xx,yy>,
+           and left 'cc' uninitialized when returning False */
+        cc->x = xx, cc->y = yy;
+        /* if every spot other than <xx,yy> has failed, try <xx,yy> itself */
+        if (allow_xx_yy && goodpos(xx, yy, &fakemon, entflags)) {
+            return TRUE; /* 'cc' is set */
+        } else {
+            debugpline3("enexto(\"%s\",%d,%d) failed", mdat->mname, xx, yy);
             return FALSE;
-    } while (good_ptr == good);
+        }
+    }
 
-full:
+ full:
+    /* we've got between 1 and SIZE(good) candidates; choose one */
     i = rn2((int) (good_ptr - good));
     cc->x = good[i].x;
     cc->y = good[i].y;
@@ -426,7 +444,7 @@ boolean force_it;
             return FALSE;
         } else {
             Your("leash goes slack.");
       release_it:
+ release_it:
             m_unleash(mtmp, FALSE);
             return TRUE;
         }
@@ -795,7 +813,7 @@ level_tele()
                 schar destlev;
                 xchar destdnum;
 
           levTport_menu:
+ levTport_menu:
                 destlev = 0;
                 destdnum = 0;
                 newlev = (int) print_dungeon(TRUE, &destlev, &destdnum);
@@ -863,7 +881,7 @@ level_tele()
         if (In_quest(&u.uz) && newlev > 0)
             newlev = newlev + dungeons[u.uz.dnum].depth_start - 1;
     } else { /* involuntary level tele */
   random_levtport:
+ random_levtport:
         newlev = random_teleport_level();
         if (newlev == depth(&u.uz)) {
             You1(shudder_for_moment);
@@ -1146,7 +1164,7 @@ register int x, y;
     register int oldx = mtmp->mx, oldy = mtmp->my;
     boolean resident_shk = mtmp->isshk && inhishop(mtmp);
 
-    if (x == mtmp->mx && y == mtmp->my && m_at(x,y) == mtmp)
+    if (x == mtmp->mx && y == mtmp->my && m_at(x, y) == mtmp)
         return; /* that was easy */
 
     if (oldx) { /* "pick up" monster */
@@ -1167,11 +1185,11 @@ register int x, y;
 
     if (u.ustuck == mtmp) {
         if (u.uswallow) {
-            u.ux = x;
-            u.uy = y;
+            u_on_newpos(mtmp->mx, mtmp->my);
             docrt();
-        } else
-            u.ustuck = 0;
+        } else if (distu(mtmp->mx, mtmp->my) > 2) {
+           unstuck(mtmp);
+        }
     }
 
     newsym(x, y);      /* update new location */
@@ -1232,7 +1250,7 @@ boolean suppress_impossible;
         impossible("rloc(): couldn't relocate monster");
     return FALSE;
 
-found_xy:
+ found_xy:
     rloc_to(mtmp, x, y);
     return TRUE;
 }
@@ -1241,7 +1259,7 @@ STATIC_OVL void
 mvault_tele(mtmp)
 struct monst *mtmp;
 {
-    register struct mkroom *croom = search_special(VAULT);
+    struct mkroom *croom = search_special(VAULT);
     coord c;
 
     if (croom && somexy(croom, &c) && goodpos(c.x, c.y, mtmp, 0)) {