diff --git a/doc/fixes34.1 b/doc/fixes34.1 index 10e76bd27..2f7ad612d 100644 --- a/doc/fixes34.1 +++ b/doc/fixes34.1 @@ -377,6 +377,7 @@ punished with ball and chain on the same floor square as a trapped chest 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 diff --git a/include/extern.h b/include/extern.h index 88126ba27..b6a37794f 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1899,8 +1899,9 @@ E void FDECL(place_monster, (struct monst *,int,int)); /* ### 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)); diff --git a/include/hack.h b/include/hack.h index 9bf619c8f..a2b79e857 100644 --- a/include/hack.h +++ b/include/hack.h @@ -139,6 +139,7 @@ NEARDATA extern coord bhitpos; /* place where throw or zap hits or stops */ #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 */ diff --git a/src/apply.c b/src/apply.c index 3459bc2ff..57f049366 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1704,12 +1704,13 @@ register struct obj *obj; 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); } diff --git a/src/dog.c b/src/dog.c index 09b06be1e..d16173858 100644 --- a/src/dog.c +++ b/src/dog.c @@ -81,7 +81,7 @@ boolean quietly; } } - 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!"); @@ -91,6 +91,9 @@ boolean quietly; 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 */ diff --git a/src/dogmove.c b/src/dogmove.c index 2670da118..070e46c0e 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -760,16 +760,16 @@ newdogpos: 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; diff --git a/src/dokick.c b/src/dokick.c index d6558acde..d3e0744e7 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -93,7 +93,7 @@ register boolean clumsy; /* 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); diff --git a/src/dothrow.c b/src/dothrow.c index b1ec8230e..983123fff 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -555,7 +555,7 @@ mhurtle_step(arg, x, y) /* 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); diff --git a/src/engrave.c b/src/engrave.c index 8d74acf4a..b4bc4c4c9 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -1188,7 +1188,7 @@ struct engr *ep; 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; diff --git a/src/hack.c b/src/hack.c index 904221886..7f5308b8f 100644 --- a/src/hack.c +++ b/src/hack.c @@ -47,7 +47,7 @@ const char *msg; /* 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); } diff --git a/src/makemon.c b/src/makemon.c index bd62b9c3c..65f6de066 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -766,6 +766,7 @@ register int mmflags; 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 */ @@ -777,12 +778,12 @@ register int mmflags; 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 @@ -819,7 +820,7 @@ register int mmflags; 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 */ diff --git a/src/mkmaze.c b/src/mkmaze.c index 4a50703b2..f15c46761 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -417,7 +417,7 @@ fixup_special() 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))) { diff --git a/src/mon.c b/src/mon.c index 7eb64fd31..dc0038800 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1919,7 +1919,7 @@ boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */ 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. diff --git a/src/mplayer.c b/src/mplayer.c index a62fba85d..255a54b99 100644 --- a/src/mplayer.c +++ b/src/mplayer.c @@ -305,7 +305,7 @@ boolean special; 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; diff --git a/src/teleport.c b/src/teleport.c index 755ed3528..8bded7405 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -18,11 +18,13 @@ STATIC_DCL void FDECL(mvault_tele, (struct monst *)); * 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; @@ -56,13 +58,13 @@ struct monst *mtmp; 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) @@ -72,7 +74,10 @@ struct monst *mtmp; } 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))) @@ -93,6 +98,16 @@ enexto(cc, xx, yy, 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; @@ -121,28 +136,28 @@ struct permonst *mdat; 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.. */ @@ -205,7 +220,7 @@ register int x, y; 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; @@ -826,7 +841,7 @@ struct monst *mtmp; { 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. * @@ -938,7 +953,7 @@ struct monst *mtmp; /* mx==0 implies migrating monster arrival */ /* 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; } @@ -947,14 +962,14 @@ struct monst *mtmp; /* mx==0 implies migrating monster arrival */ 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 */ @@ -973,7 +988,7 @@ struct monst *mtmp; 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; } @@ -1114,7 +1129,7 @@ register struct obj *obj; 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, diff --git a/src/trap.c b/src/trap.c index 9e555dea7..2b32638ac 100644 --- a/src/trap.c +++ b/src/trap.c @@ -2737,7 +2737,7 @@ drown() 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; } @@ -2745,7 +2745,7 @@ drown() /* 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; } diff --git a/src/worm.c b/src/worm.c index 43db7aa26..fb6a2bcb1 100644 --- a/src/worm.c +++ b/src/worm.c @@ -613,7 +613,7 @@ place_worm_tail_randomly(worm, x, y) 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);