mnearto/mnexto/enexto

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.
This commit is contained in:
PatR
2019-05-30 07:50:38 -07:00
parent 1a35c15588
commit 791b87833b
4 changed files with 97 additions and 76 deletions
+37 -39
View 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) 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. */
@@ -17,10 +17,7 @@
#define OFF 0 #define OFF 0
#define BOLT_LIM 8 /* from this distance ranged attacks will be made */ #define BOLT_LIM 8 /* from this distance ranged attacks will be made */
#define MAX_CARR_CAP 1000 /* so that boulders can be heavier */ #define MAX_CARR_CAP 1000 /* so that boulders can be heavier */
#define DUMMY \ #define DUMMY { 0 } /* array initializer, letting [1..N-1] default */
{ \
0 \
}
/* symbolic names for capacity levels */ /* symbolic names for capacity levels */
enum encumbrance_types { enum encumbrance_types {
@@ -244,24 +241,25 @@ typedef struct sortloot_item Loot;
#include "extern.h" #include "extern.h"
#endif /* USE_TRAMPOLI */ #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_MM_FLAGS 0x00000 /* use this rather than plain 0 */
#define NO_MINVENT 0x00001 /* suppress minvent when creating mon */ #define NO_MINVENT 0x00001 /* suppress minvent when creating mon */
#define MM_NOWAIT 0x00002 /* don't set STRAT_WAITMASK flags */ #define MM_NOWAIT 0x00002 /* don't set STRAT_WAITMASK flags */
#define MM_NOCOUNTBIRTH \ #define MM_NOCOUNTBIRTH 0x00004 /* don't increment born count (for revival) */
0x00004 /* don't increment born counter (for revival) */ #define MM_IGNOREWATER 0x00008 /* ignore water when positioning */
#define MM_IGNOREWATER 0x00008 /* ignore water when positioning */ #define MM_ADJACENTOK 0x00010 /* acceptable to use adjacent coordinates */
#define MM_ADJACENTOK \ #define MM_ANGRY 0x00020 /* monster is created angry */
0x00010 /* it is acceptable to use adjacent coordinates */ #define MM_NONAME 0x00040 /* monster is not christened */
#define MM_ANGRY 0x00020 /* monster is created angry */ #define MM_EGD 0x00100 /* add egd structure */
#define MM_NONAME 0x00040 /* monster is not christened */ #define MM_EPRI 0x00200 /* add epri structure */
#define MM_EGD 0x00100 /* add egd structure */ #define MM_ESHK 0x00400 /* add eshk structure */
#define MM_EPRI 0x00200 /* add epri structure */ #define MM_EMIN 0x00800 /* add emin structure */
#define MM_ESHK 0x00400 /* add eshk structure */ #define MM_EDOG 0x01000 /* add edog structure */
#define MM_EMIN 0x00800 /* add emin structure */ #define MM_ASLEEP 0x02000 /* monsters should be generated asleep */
#define MM_EDOG 0x01000 /* add edog structure */ #define MM_NOGRP 0x04000 /* suppress creation of monster groups */
#define MM_ASLEEP 0x02000 /* monsters should be generated asleep */ /* if more MM_ flag masks are added, skip or renumber the GP_ one(s) */
#define MM_NOGRP 0x04000 /* suppress creation of monster groups */ #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() */ /* flags for make_corpse() and mkcorpstat() */
#define CORPSTAT_NONE 0x00 #define CORPSTAT_NONE 0x00
@@ -293,27 +291,27 @@ typedef struct sortloot_item Loot;
#define ALL_FINISHED 0x01 /* called routine already finished the job */ #define ALL_FINISHED 0x01 /* called routine already finished the job */
/* flags to control query_objlist() */ /* flags to control query_objlist() */
#define BY_NEXTHERE 0x1 /* follow objlist by nexthere field */ #define BY_NEXTHERE 0x01 /* follow objlist by nexthere field */
#define AUTOSELECT_SINGLE 0x2 /* if only 1 object, don't ask */ #define AUTOSELECT_SINGLE 0x02 /* if only 1 object, don't ask */
#define USE_INVLET 0x4 /* use object's invlet */ #define USE_INVLET 0x04 /* use object's invlet */
#define INVORDER_SORT 0x8 /* sort objects by packorder */ #define INVORDER_SORT 0x08 /* sort objects by packorder */
#define SIGNAL_NOMENU 0x10 /* return -1 rather than 0 if none allowed */ #define SIGNAL_NOMENU 0x10 /* return -1 rather than 0 if none allowed */
#define SIGNAL_ESCAPE 0x20 /* return -2 rather than 0 for ESC */ #define SIGNAL_ESCAPE 0x20 /* return -2 rather than 0 for ESC */
#define FEEL_COCKATRICE 0x40 /* engage cockatrice checks and react */ #define FEEL_COCKATRICE 0x40 /* engage cockatrice checks and react */
#define INCLUDE_HERO 0x80 /* show hero among engulfer's inventory */ #define INCLUDE_HERO 0x80 /* show hero among engulfer's inventory */
/* Flags to control query_category() */ /* Flags to control query_category() */
/* BY_NEXTHERE used by query_category() too, so skip 0x01 */ /* BY_NEXTHERE used by query_category() too, so skip 0x01 */
#define UNPAID_TYPES 0x02 #define UNPAID_TYPES 0x002
#define GOLD_TYPES 0x04 #define GOLD_TYPES 0x004
#define WORN_TYPES 0x08 #define WORN_TYPES 0x008
#define ALL_TYPES 0x10 #define ALL_TYPES 0x010
#define BILLED_TYPES 0x20 #define BILLED_TYPES 0x020
#define CHOOSE_ALL 0x40 #define CHOOSE_ALL 0x040
#define BUC_BLESSED 0x80 #define BUC_BLESSED 0x080
#define BUC_CURSED 0x100 #define BUC_CURSED 0x100
#define BUC_UNCURSED 0x200 #define BUC_UNCURSED 0x200
#define BUC_UNKNOWN 0x400 #define BUC_UNKNOWN 0x400
#define BUC_ALLBKNOWN (BUC_BLESSED | BUC_CURSED | BUC_UNCURSED) #define BUC_ALLBKNOWN (BUC_BLESSED | BUC_CURSED | BUC_UNCURSED)
#define BUCX_TYPES (BUC_ALLBKNOWN | BUC_UNKNOWN) #define BUCX_TYPES (BUC_ALLBKNOWN | BUC_UNKNOWN)
#define ALL_TYPES_SELECTED -2 #define ALL_TYPES_SELECTED -2
+8 -2
View 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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Pasi Kallinen, 2018. */ /*-Copyright (c) Pasi Kallinen, 2018. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1858,6 +1858,7 @@ boolean ini;
for (olist = (struct obj *) cons->list; olist; olist = otmp) { for (olist = (struct obj *) cons->list; olist; olist = otmp) {
otmp = olist->nexthere; otmp = olist->nexthere;
place_object(olist, cons->x, cons->y); place_object(olist, cons->x, cons->y);
stackobj(olist);
} }
break; break;
} }
@@ -1865,7 +1866,12 @@ boolean ini;
case CONS_MON: { case CONS_MON: {
struct monst *mon = (struct monst *) cons->list; 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; break;
} }
+7 -8
View File
@@ -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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Derek S. Ray, 2015. */ /*-Copyright (c) Derek S. Ray, 2015. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -2595,12 +2595,11 @@ struct monst *mtmp;
return; 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); m_into_limbo(mtmp);
return; return;
} }
if (!isok(mm.x, mm.y))
return;
rloc_to(mtmp, mm.x, mm.y); rloc_to(mtmp, mm.x, mm.y);
if (!in_mklev && (mtmp->mstrategy & STRAT_APPEARMSG)) { if (!in_mklev && (mtmp->mstrategy & STRAT_APPEARMSG)) {
mtmp->mstrategy &= ~STRAT_APPEARMSG; /* one chance only */ 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 * Migrating_mons that need to be placed will cause
* no end of trouble. * no end of trouble.
*/ */
if (!enexto(&mm, newx, newy, mtmp->data)) if (!enexto(&mm, newx, newy, mtmp->data) || !isok(mm.x, mm.y))
return 0;
if (!isok(mm.x, mm.y))
return 0; return 0;
newx = mm.x; newx = mm.x;
newy = mm.y; 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) { if (move_other && othermon) {
res = 2; /* moving another monster out of the way */ 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); m_into_limbo(othermon);
}
} }
return res; return res;
+45 -27
View 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) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2011. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */
/* NetHack may be freely redistributed. See license for details. */ /* 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. * which could be co-located and thus get restricted a bit too much.
* oh well. * 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)) && (!u.usteed || mtmp != u.usteed))
return FALSE; return FALSE;
@@ -108,22 +109,24 @@ coord *cc;
register xchar xx, yy; register xchar xx, yy;
struct permonst *mdat; struct permonst *mdat;
{ {
return enexto_core(cc, xx, yy, mdat, 0); return enexto_core(cc, xx, yy, mdat, NO_MM_FLAGS);
} }
boolean boolean
enexto_core(cc, xx, yy, mdat, entflags) enexto_core(cc, xx, yy, mdat, entflags)
coord *cc; coord *cc;
register xchar xx, yy; xchar xx, yy;
struct permonst *mdat; struct permonst *mdat;
unsigned entflags; unsigned entflags;
{ {
#define MAX_GOOD 15 #define MAX_GOOD 15
coord good[MAX_GOOD], *good_ptr; coord good[MAX_GOOD], *good_ptr;
int x, y, range, i; int x, y, range, i;
int xmin, xmax, ymin, ymax; int xmin, xmax, ymin, ymax, rangemax;
struct monst fakemon; /* dummy monster */ struct monst fakemon; /* dummy monster */
boolean allow_xx_yy = (boolean) ((entflags & GP_ALLOW_XY) != 0);
entflags &= ~GP_ALLOW_XY;
if (!mdat) { if (!mdat) {
debugpline0("enexto() called with null mdat"); debugpline0("enexto() called with null mdat");
/* default to player's original monster type */ /* default to player's original monster type */
@@ -132,6 +135,13 @@ unsigned entflags;
fakemon = zeromonst; fakemon = zeromonst;
set_mon_data(&fakemon, mdat); /* set up for goodpos */ 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; good_ptr = good;
range = 1; range = 1;
/* /*
@@ -144,7 +154,7 @@ unsigned entflags;
ymin = max(0, yy - range); ymin = max(0, yy - range);
ymax = min(ROWNO - 1, 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)) { if (goodpos(x, ymin, &fakemon, entflags)) {
good_ptr->x = x; good_ptr->x = x;
good_ptr->y = ymin; good_ptr->y = ymin;
@@ -152,38 +162,46 @@ unsigned entflags;
if (good_ptr++ == &good[MAX_GOOD - 1]) if (good_ptr++ == &good[MAX_GOOD - 1])
goto full; goto full;
} }
for (x = xmin; x <= xmax; x++)
if (goodpos(x, ymax, &fakemon, entflags)) { if (goodpos(x, ymax, &fakemon, entflags)) {
good_ptr->x = x; good_ptr->x = x;
good_ptr->y = ymax; good_ptr->y = ymax;
/* beware of accessing beyond segment boundaries.. */
if (good_ptr++ == &good[MAX_GOOD - 1]) if (good_ptr++ == &good[MAX_GOOD - 1])
goto full; 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)) { if (goodpos(xmin, y, &fakemon, entflags)) {
good_ptr->x = xmin; good_ptr->x = xmin;
good_ptr->y = y; good_ptr->y = y;
/* beware of accessing beyond segment boundaries.. */
if (good_ptr++ == &good[MAX_GOOD - 1]) if (good_ptr++ == &good[MAX_GOOD - 1])
goto full; goto full;
} }
for (y = ymin + 1; y < ymax; y++)
if (goodpos(xmax, y, &fakemon, entflags)) { if (goodpos(xmax, y, &fakemon, entflags)) {
good_ptr->x = xmax; good_ptr->x = xmax;
good_ptr->y = y; good_ptr->y = y;
/* beware of accessing beyond segment boundaries.. */
if (good_ptr++ == &good[MAX_GOOD - 1]) if (good_ptr++ == &good[MAX_GOOD - 1])
goto full; goto full;
} }
range++; }
} while (++range <= rangemax && good_ptr == good);
/* return if we've grown too big (nothing is valid) */ /* return False if we exhausted 'range' without finding anything */
if (range > ROWNO && range > COLNO) 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; 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)); i = rn2((int) (good_ptr - good));
cc->x = good[i].x; cc->x = good[i].x;
cc->y = good[i].y; cc->y = good[i].y;
@@ -426,7 +444,7 @@ boolean force_it;
return FALSE; return FALSE;
} else { } else {
Your("leash goes slack."); Your("leash goes slack.");
release_it: release_it:
m_unleash(mtmp, FALSE); m_unleash(mtmp, FALSE);
return TRUE; return TRUE;
} }
@@ -795,7 +813,7 @@ level_tele()
schar destlev; schar destlev;
xchar destdnum; xchar destdnum;
levTport_menu: levTport_menu:
destlev = 0; destlev = 0;
destdnum = 0; destdnum = 0;
newlev = (int) print_dungeon(TRUE, &destlev, &destdnum); newlev = (int) print_dungeon(TRUE, &destlev, &destdnum);
@@ -863,7 +881,7 @@ level_tele()
if (In_quest(&u.uz) && newlev > 0) if (In_quest(&u.uz) && newlev > 0)
newlev = newlev + dungeons[u.uz.dnum].depth_start - 1; newlev = newlev + dungeons[u.uz.dnum].depth_start - 1;
} else { /* involuntary level tele */ } else { /* involuntary level tele */
random_levtport: random_levtport:
newlev = random_teleport_level(); newlev = random_teleport_level();
if (newlev == depth(&u.uz)) { if (newlev == depth(&u.uz)) {
You1(shudder_for_moment); You1(shudder_for_moment);
@@ -1146,7 +1164,7 @@ register int x, y;
register int oldx = mtmp->mx, oldy = mtmp->my; register int oldx = mtmp->mx, oldy = mtmp->my;
boolean resident_shk = mtmp->isshk && inhishop(mtmp); 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 */ return; /* that was easy */
if (oldx) { /* "pick up" monster */ if (oldx) { /* "pick up" monster */
@@ -1167,11 +1185,11 @@ register int x, y;
if (u.ustuck == mtmp) { if (u.ustuck == mtmp) {
if (u.uswallow) { if (u.uswallow) {
u.ux = x; u_on_newpos(mtmp->mx, mtmp->my);
u.uy = y;
docrt(); docrt();
} else } else if (distu(mtmp->mx, mtmp->my) > 2) {
u.ustuck = 0; unstuck(mtmp);
}
} }
newsym(x, y); /* update new location */ newsym(x, y); /* update new location */
@@ -1232,7 +1250,7 @@ boolean suppress_impossible;
impossible("rloc(): couldn't relocate monster"); impossible("rloc(): couldn't relocate monster");
return FALSE; return FALSE;
found_xy: found_xy:
rloc_to(mtmp, x, y); rloc_to(mtmp, x, y);
return TRUE; return TRUE;
} }
@@ -1241,7 +1259,7 @@ STATIC_OVL void
mvault_tele(mtmp) mvault_tele(mtmp)
struct monst *mtmp; struct monst *mtmp;
{ {
register struct mkroom *croom = search_special(VAULT); struct mkroom *croom = search_special(VAULT);
coord c; coord c;
if (croom && somexy(croom, &c) && goodpos(c.x, c.y, mtmp, 0)) { if (croom && somexy(croom, &c) && goodpos(c.x, c.y, mtmp, 0)) {