see_monsters() wasn't called when you lost the innate warning intrinsic due
to level loss
xorns sink if the drawbridge they're standing on is raised
+applying figurines to an adjacent spot over water does drowning checks
Platform- and/or Interface-Specific Fixes
/* ### teleport.c ### */
-E boolean FDECL(goodpos, (int,int,struct monst *));
+E boolean FDECL(goodpos, (int,int,struct monst *,unsigned));
E boolean FDECL(enexto, (coord *,XCHAR_P,XCHAR_P,struct permonst *));
+E boolean FDECL(enexto_core, (coord *,XCHAR_P,XCHAR_P,struct permonst *,unsigned));
E void FDECL(teleds, (int,int,BOOLEAN_P));
E boolean FDECL(safe_teleds, (BOOLEAN_P));
E boolean FDECL(teleport_pet, (struct monst *,BOOLEAN_P));
#define MM_ANGRY 0x10 /* monster is created angry */
#define MM_NONAME 0x20 /* monster is not christened */
#define MM_NOCOUNTBIRTH 0x40 /* don't increment born counter (for revival) */
+#define MM_IGNOREWATER 0x80 /* ignore water when positioning */
/* flags for special ggetobj status returns */
#define ALL_FINISHED 0x01 /* called routine already finished the job */
if (!figurine_location_checks(obj, &cc, FALSE)) return;
You("%s and it transforms.",
(u.dx||u.dy) ? "set the figurine beside you" :
- (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) ?
+ (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ||
+ is_pool(cc.x, cc.y)) ?
"release the figurine" :
(u.dz < 0 ?
"toss the figurine into the air" :
"set the figurine on the ground"));
- (void) make_familiar(obj, u.ux+u.dx, u.uy+u.dy, FALSE);
+ (void) make_familiar(obj, cc.x, cc.y, FALSE);
(void) stop_timer(FIG_TRANSFORM, (genericptr_t)obj);
useup(obj);
}
}
}
- mtmp = makemon(pm, x, y, MM_EDOG);
+ mtmp = makemon(pm, x, y, MM_EDOG|MM_IGNOREWATER);
if (otmp && !mtmp) { /* monster was genocided or square occupied */
if (!quietly)
pline_The("figurine writhes and then shatters into pieces!");
if (!mtmp) return (struct monst *)0;
+ if (is_pool(mtmp->mx, mtmp->my) && minliquid(mtmp))
+ return (struct monst *)0;
+
initedog(mtmp);
mtmp->msleeping = 0;
if (otmp) { /* figurine; resulting monster might not become a pet */
ny = sgn(omy - u.uy);
cc.x = u.ux + nx;
cc.y = u.uy + ny;
- if (goodpos(cc.x, cc.y, mtmp)) goto dognext;
+ if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
i = xytod(nx, ny);
for (j = (i + 7)%8; j < (i + 1)%8; j++) {
dtoxy(&cc, j);
- if (goodpos(cc.x, cc.y, mtmp)) goto dognext;
+ if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
}
for (j = (i + 6)%8; j < (i + 2)%8; j++) {
dtoxy(&cc, j);
- if (goodpos(cc.x, cc.y, mtmp)) goto dognext;
+ if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext;
}
cc.x = mtmp->mx;
cc.y = mtmp->my;
/* see if the monster has a place to move into */
mdx = mon->mx + u.dx;
mdy = mon->my + u.dy;
- if(goodpos(mdx, mdy, mon)) {
+ if(goodpos(mdx, mdy, mon, 0)) {
pline("%s reels from the blow.", Monnam(mon));
if (m_in_out_region(mon, mdx, mdy)) {
remove_monster(mon->mx, mon->my);
/* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially
* rather than just stopping before.
*/
- if (goodpos(x, y, mon) && m_in_out_region(mon, x, y)) {
+ if (goodpos(x, y, mon, 0) && m_in_out_region(mon, x, y)) {
remove_monster(mon->mx, mon->my);
newsym(mon->mx, mon->my);
place_monster(mon, x, y);
tx = rn1(COLNO-3,2);
ty = rn2(ROWNO);
} while (engr_at(tx, ty) ||
- !goodpos(tx, ty, (struct monst *)0));
+ !goodpos(tx, ty, (struct monst *)0, 0));
ep->engr_x = tx;
ep->engr_y = ty;
/* this location might not be safe, if not, move revived monster */
if (revived) {
mtmp = m_at(x,y);
- if (mtmp && !goodpos(x, y, mtmp) &&
+ if (mtmp && !goodpos(x, y, mtmp, 0) &&
enexto(&cc, x, y, mtmp->data)) {
rloc_to(mtmp, cc.x, cc.y);
}
boolean byyou = (x == u.ux && y == u.uy);
boolean allow_minvent = ((mmflags & NO_MINVENT) == 0);
boolean countbirth = ((mmflags & MM_NOCOUNTBIRTH) == 0);
+ unsigned gpflags = (mmflags & MM_IGNOREWATER) ? MM_IGNOREWATER : 0;
uchar lim;
/* if caller wants random location, do it here */
do {
x = rn1(COLNO-3,2);
y = rn2(ROWNO);
- } while(!goodpos(x, y, ptr ? &fakemon : (struct monst *)0) ||
+ } while(!goodpos(x, y, ptr ? &fakemon : (struct monst *)0, gpflags) ||
(!in_mklev && tryct++ < 50 && cansee(x, y)));
} else if (byyou && !in_mklev) {
coord bypos;
- if(enexto(&bypos, u.ux, u.uy, ptr)) {
+ if(enexto_core(&bypos, u.ux, u.uy, ptr, gpflags)) {
x = bypos.x;
y = bypos.y;
} else
return((struct monst *) 0); /* no more monsters! */
}
fakemon.data = ptr; /* set up for goodpos */
- } while(!goodpos(x, y, &fakemon) && tryct++ < 50);
+ } while(!goodpos(x, y, &fakemon, gpflags) && tryct++ < 50);
mndx = monsndx(ptr);
}
/* if it's unique, don't ever make it again */
croom = &rooms[0]; /* only one room on the medusa level */
for (tryct = rnd(4); tryct; tryct--) {
x = somex(croom); y = somey(croom);
- if (goodpos(x, y, (struct monst *)0)) {
+ if (goodpos(x, y, (struct monst *)0, 0)) {
otmp = mk_tt_object(STATUE, x, y);
while (otmp && (poly_when_stoned(&mons[otmp->corpsenm]) ||
pm_resistance(&mons[otmp->corpsenm],MR_STONE))) {
newx = x;
newy = y;
- if (!goodpos(newx, newy, mtmp)) {
+ if (!goodpos(newx, newy, mtmp, 0)) {
/* actually we have real problems if enexto ever fails.
* migrating_mons that need to be placed will cause
* no end of trouble.
do {
x = rn1(COLNO-4, 2);
y = rnd(ROWNO-2);
- } while(!goodpos(x, y, &fakemon) && tryct++ <= 50);
+ } while(!goodpos(x, y, &fakemon, 0) && tryct++ <= 50);
/* if pos not found in 50 tries, don't bother to continue */
if(tryct > 50) return;
* call it to generate new monster positions with fake monster structures.
*/
boolean
-goodpos(x, y, mtmp)
+goodpos(x, y, mtmp, gpflags)
int x,y;
struct monst *mtmp;
+unsigned gpflags;
{
struct permonst *mdat = NULL;
+ boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0);
if (!isok(x, y)) return FALSE;
return FALSE;
mdat = mtmp->data;
- if (is_pool(x,y)) {
+ if (is_pool(x,y) && !ignorewater) {
if (mtmp == &youmonst)
return !!(HLevitation || Flying || Wwalking ||
Swimming || Amphibious);
else return (is_flyer(mdat) || is_swimmer(mdat) ||
is_clinger(mdat));
- } else if (mdat->mlet == S_EEL && rn2(13)) {
+ } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) {
return FALSE;
} else if (is_lava(x,y)) {
if (mtmp == &youmonst)
}
if (passes_walls(mdat) && may_passwall(x,y)) return TRUE;
}
- if (!ACCESSIBLE(levl[x][y].typ)) return FALSE;
+ if (!ACCESSIBLE(levl[x][y].typ)) {
+ if (!(is_pool(x,y) && ignorewater)) return FALSE;
+ }
+
if (closed_door(x, y) && (!mdat || !amorphous(mdat)))
return FALSE;
if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat)))
coord *cc;
register xchar xx, yy;
struct permonst *mdat;
+{
+ return enexto_core(cc, xx, yy, mdat, 0);
+}
+
+boolean
+enexto_core(cc, xx, yy, mdat, entflags)
+coord *cc;
+register xchar xx, yy;
+struct permonst *mdat;
+unsigned entflags;
{
#define MAX_GOOD 15
coord good[MAX_GOOD], *good_ptr;
ymax = min(ROWNO-1, yy+range);
for (x = xmin; x <= xmax; x++)
- if (goodpos(x, ymin, &fakemon)) {
+ if (goodpos(x, ymin, &fakemon, entflags)) {
good_ptr->x = x;
good_ptr->y = ymin ;
/* beware of accessing beyond segment boundaries.. */
if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
}
for (x = xmin; x <= xmax; x++)
- if (goodpos(x, ymax, &fakemon)) {
+ 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++)
- if (goodpos(xmin, y, &fakemon)) {
+ 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)) {
+ if (goodpos(xmax, y, &fakemon, entflags)) {
good_ptr->x = xmax;
good_ptr->y = y ;
/* beware of accessing beyond segment boundaries.. */
boolean trapok;
{
if (!trapok && t_at(x, y)) return FALSE;
- if (!goodpos(x, y, &youmonst)) return FALSE;
+ if (!goodpos(x, y, &youmonst, 0)) return FALSE;
if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE;
if (!in_out_region(x, y)) return FALSE;
return TRUE;
{
register int xx, yy;
- if (!goodpos(x, y, mtmp)) return FALSE;
+ if (!goodpos(x, y, mtmp, 0)) return FALSE;
/*
* Check for restricted areas present in some special levels.
*
/* if the wiz teleports away to heal, try the up staircase,
to block the player's escaping before he's healed
(deliberately use `goodpos' rather than `rloc_pos_ok' here) */
- if (goodpos(x, y, mtmp))
+ if (goodpos(x, y, mtmp, 0))
goto found_xy;
}
x = rn1(COLNO-3,2);
y = rn2(ROWNO);
if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
- : goodpos(x, y, mtmp))
+ : goodpos(x, y, mtmp, 0))
goto found_xy;
} while (++trycount < 1000);
/* last ditch attempt to find a good place */
for (x = 2; x < COLNO - 1; x++)
for (y = 0; y < ROWNO; y++)
- if (goodpos(x, y, mtmp))
+ if (goodpos(x, y, mtmp, 0))
goto found_xy;
/* level either full of monsters or somehow faulty */
coord c;
if (croom && somexy(croom, &c) &&
- goodpos(c.x, c.y, mtmp)) {
+ goodpos(c.x, c.y, mtmp, 0)) {
rloc_to(mtmp, c.x, c.y);
return;
}
tx = rn1(COLNO-3,2);
ty = rn2(ROWNO);
if (!--try_limit) break;
- } while (!goodpos(tx, ty, (struct monst *)0) ||
+ } while (!goodpos(tx, ty, (struct monst *)0, 0) ||
/* bug: this lacks provision for handling the Wizard's tower */
(restricted_fall &&
(!within_bounded_area(tx, ty, dndest.lx, dndest.ly,
for (i = 0; i < 100; i++) {
x = rn1(3,u.ux - 1);
y = rn1(3,u.uy - 1);
- if (goodpos(x, y, &youmonst)) {
+ if (goodpos(x, y, &youmonst, 0)) {
crawl_ok = TRUE;
goto crawl;
}
/* one more scan */
for (x = u.ux - 1; x <= u.ux + 1; x++)
for (y = u.uy - 1; y <= u.uy + 1; y++)
- if (goodpos(x, y, &youmonst)) {
+ if (goodpos(x, y, &youmonst, 0)) {
crawl_ok = TRUE;
goto crawl;
}
do {
random_dir(ox, oy, &nx, &ny);
- } while (!goodpos(nx, ny, worm) && (tryct++ < 50));
+ } while (!goodpos(nx, ny, worm, 0) && (tryct++ < 50));
if (tryct < 50) {
place_worm_seg(worm, nx, ny);