From 4e46a7de6903b387c95e89671d31a1f68ec587cb Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 21 May 2023 17:30:06 -0700 Subject: [PATCH] change enexto() to use collect_coords() Greatly simplify enexto(). The new code might does more work up front but less overall when/if a nearby spot is hard to find. --- src/teleport.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/src/teleport.c b/src/teleport.c index 0d07a24bc..cdd00b0af 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -4,6 +4,7 @@ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" +#define NEW_ENEXTO static boolean goodpos_onscary(coordxy, coordxy, struct permonst *); static boolean tele_jump_ok(coordxy, coordxy, coordxy, coordxy); @@ -188,6 +189,70 @@ enexto( || enexto_core(cc, xx, yy, mdat, NO_MM_FLAGS)); } +#ifdef NEW_ENEXTO + +boolean +enexto_core( + coord *cc, /* output; as close as feasible to */ + coordxy xx, coordxy yy, /* input coordinates */ + struct permonst *mdat, /* type of monster; affects whether water or + * lava or boulder spots will be considered */ + mmflags_nht entflags) /* flags for goodpos() */ +{ + coord candy[ROWNO * (COLNO - 1)]; /* enough room for every location */ + int i, nearcandyct, allcandyct; + struct monst fakemon; /* dummy monster */ + boolean allow_xx_yy = (boolean) ((entflags & GP_ALLOW_XY) != 0); + /* note: GP_ALLOW_XY isn't used by goodpos(); old enext_core() used no + mask it off to hide it from goodpos but that isn't required and we + want to keep it in case the debugpline() below prints 'entflags' */ + + if (!mdat) { + debugpline0("enexto() called with null mdat"); + /* default to player's original monster type */ + mdat = &mons[u.umonster]; + } + fakemon = cg.zeromonst; + set_mon_data(&fakemon, mdat); /* set up for goodpos() */ + + /* gather candidate coordinates within 3 steps, those 1 step away in + random order first, then those 2 steps away in random order, then 3; + this will usually find a good spot without scanning the whole map */ + nearcandyct = collect_coords(candy, xx, yy, 3, CC_NO_FLAGS, + (boolean (*)(coordxy, coordxy)) 0); + for (i = 0; i < nearcandyct; ++i) { + *cc = candy[i]; + if (goodpos(cc->x, cc->y, &fakemon, entflags)) + return TRUE; + } + + /* didn't find a spot; gather coordinates for the whole map except + for itself, ordered in expanding distance from + (subsets of equal distance grouped together with order randomized) */ + allcandyct = collect_coords(candy, xx, yy, 0, CC_NO_FLAGS, + (boolean (*)(coordxy, coordxy)) 0); + /* skip first 'nearcandyct' spots, they have already been rejected; + they will occur in different random order but same overall total */ + for (i = nearcandyct; i < allcandyct; ++i) { + *cc = candy[i]; + if (goodpos(cc->x, cc->y, &fakemon, entflags)) + return TRUE; + } + + /* still didn't find a spot; maybe try itself */ + cc->x = xx, cc->y = yy; /* final value for 'cc' in case we return False */ + if (allow_xx_yy && goodpos(cc->x, cc->y, &fakemon, entflags)) + return TRUE; + + /* failed to find any acceptable spot */ + debugpline4("enexto(\"%s\",%d,%d,0x%08lx) failed", + mdat->pmnames[NEUTRAL], (int) xx, (int) yy, + (unsigned long) entflags); + return FALSE; +} + +#else /* !NEW_ENEXTO */ + boolean enexto_core( coord *cc, @@ -272,7 +337,7 @@ enexto_core( return TRUE; /* 'cc' is set */ } else { debugpline3("enexto(\"%s\",%d,%d) failed", - mdat->pmnames[NEUTRAL], xx, yy); + mdat->pmnames[NEUTRAL], (int) xx, (int) yy); return FALSE; } } @@ -286,6 +351,8 @@ enexto_core( #undef MAX_GOOD } +#endif /* ?NEW_ENEXTO */ + /* * Check for restricted areas present in some special levels. (This might * need to be augmented to allow deliberate passage in wizard mode, but