]> granicus.if.org Git - nethack/commitdiff
B18009 animate figurine over water
authornethack.allison <nethack.allison>
Sun, 9 Feb 2003 05:39:32 +0000 (05:39 +0000)
committernethack.allison <nethack.allison>
Sun, 9 Feb 2003 05:39:32 +0000 (05:39 +0000)
>More worrying is the fact that applying a figurine over water lets
>the monster wait until its next move before it drowns (giving
>you time to teleport it to safety, or whatever) [...]
>Should there be a minliquid() check as part of make_familiar()?

Applying at the water location next to you was easy. But
applying it at your own location (triggering BY_YOU)  could
end up placing the figurine at the far side of the level if
there was lots of water.

Correcting that required the ability to pass a flag from
make_familiar to makemon() telling it to not rule out
water locations as good positions.  The flag had to
be passed on down to goodpos() and enexto().

The bulk of this patch is just adding an additional
argument to goodpos() in all of the callers.

17 files changed:
doc/fixes34.1
include/extern.h
include/hack.h
src/apply.c
src/dog.c
src/dogmove.c
src/dokick.c
src/dothrow.c
src/engrave.c
src/hack.c
src/makemon.c
src/mkmaze.c
src/mon.c
src/mplayer.c
src/teleport.c
src/trap.c
src/worm.c

index 10e76bd277af8c2edd634487ed2ca589415fd239..2f7ad612d5c467cd341c30b4ac0a2c55b294215a 100644 (file)
@@ -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
index 88126ba27ce7dedfe1e168c4fe3cea6042e97da3..b6a37794f538828742f012957418d18adc21294e 100644 (file)
@@ -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));
index 9bf619c8f78bbc8a7aff568f50b38039259954fd..a2b79e8573bbe358823841ce69f32bd73c560a6c 100644 (file)
@@ -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 */
index 3459bc2ff0bacadb334dd4556aaa10ab8f8247db..57f0493667f0f151ebb682a7484cb0d7bbf97eb5 100644 (file)
@@ -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);
 }
index 09b06be1e9ad6d2c9e85234b083a2a19a48bfbb4..d1617385832216f7a90d0ce3ef43c7dcacb02617 100644 (file)
--- 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 */
index 2670da118cb70e544353cb03fc195f6a2421bffd..070e46c0e83a20be0f18a96acc25c1175ca808df 100644 (file)
@@ -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;
index d6558acdef817571ce2257edca139f1d27764acc..d3e0744e7ff85209bf26a6b2d2744780439f50f8 100644 (file)
@@ -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);
index b1ec8230e4ee3712ab1b2da236c23e7dd7ada4ff..983123fff545e8b6b0fc8e1f57d494c71c9dfcbe 100644 (file)
@@ -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);
index 8d74acf4a1bb6051a6a7ba77e09a970fd975ce7d..b4bc4c4c98c79bee74e3edf6db70dedda1640b11 100644 (file)
@@ -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;
index 904221886a76fc7b2c1401fee18309cc809545e0..7f5308b8fef2357011fc95dc86f5ae2dec215cb1 100644 (file)
@@ -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);
        }
index bd62b9c3c34ca8094a70edf9d352f27353fff63f..65f6de06635efe12a99311cdd3c799f734f70a16 100644 (file)
@@ -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 */
index 4a50703b2dcb7f5a2c7a3fb59f646fd25b4b0784..f15c4676154daf33cf4da254e096d33ee85120a0 100644 (file)
@@ -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))) {
index 7eb64fd319cba639fa0d8d106076639de3938e6e..dc003880063d6df9afff9b1af08fcc43d0a6febe 100644 (file)
--- 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.
index a62fba85d5efd063e5a0361cb48e551994ef2db8..255a54b9958e10007f7c43e1bd3e72f2a6efec58 100644 (file)
@@ -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;
index 755ed3528181f55c46de0bf6c57e71d8fd4dc831..8bded74053640cb837d6603b410c09328e874810 100644 (file)
@@ -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,
index 9e555dea7674e26f2afcb48a29e6acc6f4565ad2..2b32638ac40155514fba79726144147247a77cad 100644 (file)
@@ -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;
                        }
index 43db7aa26cc6535bfdcac306851429e57904022e..fb6a2bcb13fd5929659b031785b5dff873bf385e 100644 (file)
@@ -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);