From: nethack.allison Date: Sun, 9 Feb 2003 05:39:32 +0000 (+0000) Subject: B18009 animate figurine over water X-Git-Tag: MOVE2GIT~2203 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c2c72d11e753df77c566046c0c55467ed484f8ec;p=nethack B18009 animate figurine over water >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. --- 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);