-/* NetHack 3.6 detect.c $NHDT-Date: 1446369464 2015/11/01 09:17:44 $ $NHDT-Branch: master $:$NHDT-Revision: 1.61 $ */
+/* NetHack 3.6 detect.c $NHDT-Date: 1522891623 2018/04/05 01:27:03 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.81 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/*-Copyright (c) Robert Patrick Rankin, 2018. */
/* NetHack may be freely redistributed. See license for details. */
/*
extern boolean known; /* from read.c */
+STATIC_DCL boolean NDECL(unconstrain_map);
+STATIC_DCL void NDECL(reconstrain_map);
+STATIC_DCL void FDECL(browse_map, (int, const char *));
+STATIC_DCL void FDECL(map_monst, (struct monst *, BOOLEAN_P));
STATIC_DCL void FDECL(do_dknown_of, (struct obj *));
STATIC_DCL boolean FDECL(check_map_spot, (int, int, CHAR_P, unsigned));
STATIC_DCL boolean FDECL(clear_stale_map, (CHAR_P, unsigned));
STATIC_DCL void FDECL(show_map_spot, (int, int));
STATIC_PTR void FDECL(findone, (int, int, genericptr_t));
STATIC_PTR void FDECL(openone, (int, int, genericptr_t));
+STATIC_DCL int FDECL(mfind0, (struct monst *, BOOLEAN_P));
+STATIC_DCL int FDECL(reveal_terrain_getglyph, (int, int, int,
+ unsigned, int, int));
-/* Recursively search obj for an object in class oclass and return 1st found
- */
+/* bring hero out from underwater or underground or being engulfed;
+ return True iff any change occurred */
+STATIC_OVL boolean
+unconstrain_map()
+{
+ boolean res = u.uinwater || u.uburied || u.uswallow;
+
+ /* bring Underwater, buried, or swallowed hero to normal map */
+ iflags.save_uinwater = u.uinwater, u.uinwater = 0;
+ iflags.save_uburied = u.uburied, u.uburied = 0;
+ iflags.save_uswallow = u.uswallow, u.uswallow = 0;
+
+ return res;
+}
+
+/* put hero back underwater or underground or engulfed */
+STATIC_OVL void
+reconstrain_map()
+{
+ u.uinwater = iflags.save_uinwater, iflags.save_uinwater = 0;
+ u.uburied = iflags.save_uburied, iflags.save_uburied = 0;
+ u.uswallow = iflags.save_uswallow, iflags.save_uswallow = 0;
+}
+
+/* use getpos()'s 'autodescribe' to view whatever is currently shown on map */
+STATIC_DCL void
+browse_map(ter_typ, ter_explain)
+int ter_typ;
+const char *ter_explain;
+{
+ coord dummy_pos; /* don't care whether player actually picks a spot */
+ boolean save_autodescribe;
+
+ dummy_pos.x = u.ux, dummy_pos.y = u.uy; /* starting spot for getpos() */
+ save_autodescribe = iflags.autodescribe;
+ iflags.autodescribe = TRUE;
+ iflags.terrainmode = ter_typ;
+ getpos(&dummy_pos, FALSE, ter_explain);
+ iflags.terrainmode = 0;
+ iflags.autodescribe = save_autodescribe;
+}
+
+/* extracted from monster_detection() so can be shared by do_vicinity_map() */
+STATIC_DCL void
+map_monst(mtmp, showtail)
+struct monst *mtmp;
+boolean showtail;
+{
+ if (def_monsyms[(int) mtmp->data->mlet].sym == ' ')
+ show_glyph(mtmp->mx, mtmp->my, detected_mon_to_glyph(mtmp));
+ else
+ show_glyph(mtmp->mx, mtmp->my,
+ mtmp->mtame ? pet_to_glyph(mtmp) : mon_to_glyph(mtmp));
+
+ if (showtail && mtmp->data == &mons[PM_LONG_WORM])
+ detect_wsegs(mtmp, 0);
+}
+
+/* this is checking whether a trap symbol represents a trapped chest,
+ not whether a trapped chest is actually present */
+boolean
+trapped_chest_at(ttyp, x, y)
+int ttyp;
+int x, y;
+{
+ struct monst *mtmp;
+ struct obj *otmp;
+
+ if (!glyph_is_trap(glyph_at(x, y)))
+ return FALSE;
+ if (ttyp != BEAR_TRAP || (Hallucination && rn2(20)))
+ return FALSE;
+
+ /*
+ * TODO? We should check containers recursively like the trap
+ * detecting routine does. Chests and large boxes do not nest in
+ * themselves or each other, but could be contained inside statues.
+ *
+ * For farlook, we should also check for buried containers, but
+ * for '^' command to examine adjacent trap glyph, we shouldn't.
+ */
+
+ /* on map, presence of any trappable container will do */
+ if (sobj_at(CHEST, x, y) || sobj_at(LARGE_BOX, x, y))
+ return TRUE;
+ /* in inventory, we need to find one which is actually trapped */
+ if (x == u.ux && y == u.uy) {
+ for (otmp = invent; otmp; otmp = otmp->nobj)
+ if (Is_box(otmp) && otmp->otrapped)
+ return TRUE;
+ if (u.usteed) { /* steed isn't on map so won't be found by m_at() */
+ for (otmp = u.usteed->minvent; otmp; otmp = otmp->nobj)
+ if (Is_box(otmp) && otmp->otrapped)
+ return TRUE;
+ }
+ }
+ if ((mtmp = m_at(x, y)) != 0)
+ for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
+ if (Is_box(otmp) && otmp->otrapped)
+ return TRUE;
+ return FALSE;
+}
+
+/* this is checking whether a trap symbol represents a trapped door,
+ not whether the door here is actually trapped */
+boolean
+trapped_door_at(ttyp, x, y)
+int ttyp;
+int x, y;
+{
+ struct rm *lev;
+
+ if (!glyph_is_trap(glyph_at(x, y)))
+ return FALSE;
+ if (ttyp != BEAR_TRAP || (Hallucination && rn2(20)))
+ return FALSE;
+ lev = &levl[x][y];
+ if (!IS_DOOR(lev->typ))
+ return FALSE;
+ if ((lev->doormask & (D_NODOOR | D_BROKEN | D_ISOPEN)) != 0
+ && trapped_chest_at(ttyp, x, y))
+ return FALSE;
+ return TRUE;
+}
+
+/* recursively search obj for an object in class oclass, return 1st found */
struct obj *
o_in(obj, oclass)
struct obj *obj;
for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
if (otmp->oclass == oclass)
return otmp;
- else if (Has_contents(otmp) && (temp = o_in(otmp, oclass)))
+ else if (Has_contents(otmp) && (temp = o_in(otmp, oclass)) != 0)
return temp;
}
return (struct obj *) 0;
if (objects[otmp->otyp].oc_material == material)
return otmp;
else if (Has_contents(otmp)
- && (temp = o_material(otmp, material)))
+ && (temp = o_material(otmp, material)) != 0)
return temp;
}
return (struct obj *) 0;
{
register struct obj *obj;
register struct monst *mtmp;
- struct obj *temp;
- boolean stale;
+ struct obj gold, *temp = 0;
+ boolean stale, ugold = FALSE, steedgold = FALSE;
+ int ter_typ = TER_DETECT | TER_OBJ;
- known = stale =
- clear_stale_map(COIN_CLASS, (unsigned) (sobj->blessed ? GOLD : 0));
+ known = stale = clear_stale_map(COIN_CLASS,
+ (unsigned) (sobj->blessed ? GOLD : 0));
/* look for gold carried by monsters (might be in a container) */
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue; /* probably not needed in this case but... */
if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
- known = TRUE;
- goto outgoldmap; /* skip further searching */
- } else
+ if (mtmp == u.usteed) {
+ steedgold = TRUE;
+ } else {
+ known = TRUE;
+ goto outgoldmap; /* skip further searching */
+ }
+ } else {
for (obj = mtmp->minvent; obj; obj = obj->nobj)
- if (sobj->blessed && o_material(obj, GOLD)) {
- known = TRUE;
- goto outgoldmap;
- } else if (o_in(obj, COIN_CLASS)) {
- known = TRUE;
- goto outgoldmap; /* skip further searching */
+ if ((sobj->blessed && o_material(obj, GOLD))
+ || o_in(obj, COIN_CLASS)) {
+ if (mtmp == u.usteed) {
+ steedgold = TRUE;
+ } else {
+ known = TRUE;
+ goto outgoldmap; /* skip further searching */
+ }
}
+ }
}
/* look for gold objects */
adjust message if you have gold in your inventory */
if (sobj) {
char buf[BUFSZ];
- if (youmonst.data == &mons[PM_GOLD_GOLEM]) {
+
+ if (youmonst.data == &mons[PM_GOLD_GOLEM])
/*JP
Sprintf(buf, "You feel like a million %s!", currency(2L));
*/
Strcpy(buf, "\82 \82È\82½\82Í\8bà\8e\9d\82¿\82É\82È\82Á\82½\82æ\82¤\82É\8a´\82¶\82½\81I");
- } else if (hidden_gold() || money_cnt(invent))
+ else if (money_cnt(invent) || hidden_gold())
Strcpy(buf,
/*JP
"You feel worried about your future financial situation.");
*/
"\82 \82È\82½\82Í\8f«\97\88\82Ì\8co\8dÏ\8fó\8bµ\82ª\90S\94z\82É\82È\82Á\82½\81D");
+ else if (steedgold)
+ Sprintf(buf, "You feel interested in %s financial situation.",
+ s_suffix(x_monnam(u.usteed,
+ u.usteed->mtame ? ARTICLE_YOUR
+ : ARTICLE_THE,
+ (char *) 0,
+ SUPPRESS_SADDLE, FALSE)));
else
/*JP
Strcpy(buf, "You feel materially poor.");
*/
Strcpy(buf, "\82 \82È\82½\82Í\82Ð\82à\82¶\82³\82ð\8a´\82¶\82½\81D");
+
strange_feeling(sobj, buf);
}
return 1;
outgoldmap:
cls();
- iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
- u.uinwater = u.uburied = 0;
+ (void) unconstrain_map();
/* Discover gold locations. */
for (obj = fobj; obj; obj = obj->nobj) {
- if (sobj->blessed && (temp = o_material(obj, GOLD))) {
+ if (sobj->blessed && (temp = o_material(obj, GOLD)) != 0) {
if (temp != obj) {
temp->ox = obj->ox;
temp->oy = obj->oy;
}
map_object(temp, 1);
- } else if ((temp = o_in(obj, COIN_CLASS))) {
+ } else if ((temp = o_in(obj, COIN_CLASS)) != 0) {
if (temp != obj) {
temp->ox = obj->ox;
temp->oy = obj->oy;
}
map_object(temp, 1);
}
+ if (temp && temp->ox == u.ux && temp->oy == u.uy)
+ ugold = TRUE;
}
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue; /* probably overkill here */
+ temp = 0;
if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
- struct obj gold;
gold = zeroobj; /* ensure oextra is cleared too */
gold.otyp = GOLD_PIECE;
+ gold.quan = (long) rnd(10); /* usually more than 1 */
gold.ox = mtmp->mx;
gold.oy = mtmp->my;
map_object(&gold, 1);
- } else
+ temp = &gold;
+ } else {
for (obj = mtmp->minvent; obj; obj = obj->nobj)
- if (sobj->blessed && (temp = o_material(obj, GOLD))) {
+ if (sobj->blessed && (temp = o_material(obj, GOLD)) != 0) {
temp->ox = mtmp->mx;
temp->oy = mtmp->my;
map_object(temp, 1);
break;
- } else if ((temp = o_in(obj, COIN_CLASS))) {
+ } else if ((temp = o_in(obj, COIN_CLASS)) != 0) {
temp->ox = mtmp->mx;
temp->oy = mtmp->my;
map_object(temp, 1);
break;
}
+ }
+ if (temp && temp->ox == u.ux && temp->oy == u.uy)
+ ugold = TRUE;
+ }
+ if (!ugold) {
+ newsym(u.ux, u.uy);
+ ter_typ |= TER_MON; /* so autodescribe will recognize hero */
}
- newsym(u.ux, u.uy);
- u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
/*JP
You_feel("very greedy, and sense gold!");
*/
You("\82Ç\82ñ\97~\82É\82È\82Á\82½\82æ\82¤\82È\8bC\82ª\82µ\82½\81C\82»\82µ\82Ä\8bà\89Ý\82Ì\88Ê\92u\82ð\8a´\92m\82µ\82½\81I");
exercise(A_WIS, TRUE);
- display_nhwindow(WIN_MAP, TRUE);
+
+ browse_map(ter_typ, "gold");
+
+ reconstrain_map();
docrt();
if (Underwater)
under_water(2);
const char *what = confused ? "\83n\83\89\83w\83\8a" : "\90H\82×\95¨";
stale = clear_stale_map(oclass, 0);
+ if (u.usteed) /* some situations leave steed with stale coordinates */
+ u.usteed->mx = u.ux, u.usteed->my = u.uy;
for (obj = fobj; obj; obj = obj->nobj)
if (o_in(obj, oclass)) {
else
ct++;
}
- for (mtmp = fmon; mtmp && !ct; mtmp = mtmp->nmon) {
- /* no DEADMONSTER(mtmp) check needed since dmons never have inventory
- */
+ for (mtmp = fmon; mtmp && (!ct || !ctu); mtmp = mtmp->nmon) {
+ /* no DEADMONSTER(mtmp) check needed -- dmons never have inventory */
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if (o_in(obj, oclass)) {
- ct++;
+ if (mtmp->mx == u.ux && mtmp->my == u.uy)
+ ctu++; /* steed or an engulfer with inventory */
+ else
+ ct++;
break;
}
}
}
} else if (sobj) {
char buf[BUFSZ];
-#if 0 /*JP*/
+
+#if 0 /*JP:T*/
Sprintf(buf, "Your %s twitches%s.", body_part(NOSE),
(sobj->blessed && !u.uedibility)
? " then starts to tingle"
}
} else {
struct obj *temp;
+ int ter_typ = TER_DETECT | TER_OBJ;
+
known = TRUE;
cls();
- iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
- u.uinwater = u.uburied = 0;
+ (void) unconstrain_map();
for (obj = fobj; obj; obj = obj->nobj)
if ((temp = o_in(obj, oclass)) != 0) {
if (temp != obj) {
map_object(temp, 1);
}
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- /* no DEADMONSTER(mtmp) check needed since dmons never have
- * inventory */
+ /* no DEADMONSTER() check needed -- dmons never have inventory */
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if ((temp = o_in(obj, oclass)) != 0) {
temp->ox = mtmp->mx;
map_object(temp, 1);
break; /* skip rest of this monster's inventory */
}
- newsym(u.ux, u.uy);
- u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
+ if (!ctu) {
+ newsym(u.ux, u.uy);
+ ter_typ |= TER_MON; /* for autodescribe of self */
+ }
if (sobj) {
if (sobj->blessed) {
#if 0 /*JP*/
You("sense %s.", what);
*/
You("%s\82ð\8a´\92m\82µ\82½\81D", what);
- display_nhwindow(WIN_MAP, TRUE);
exercise(A_WIS, TRUE);
+
+ browse_map(ter_typ, "food");
+
+ reconstrain_map();
docrt();
if (Underwater)
under_water(2);
int ct = 0, ctu = 0;
register struct obj *obj, *otmp = (struct obj *) 0;
register struct monst *mtmp;
- int sym, boulder = 0;
+ int sym, boulder = 0, ter_typ = TER_DETECT | TER_OBJ;
if (class < 0 || class >= MAXOCLASSES) {
impossible("object_detect: illegal class %d", class);
do_dknown_of(obj);
}
+ if (u.usteed)
+ u.usteed->mx = u.ux, u.usteed->my = u.uy;
+
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
cls();
- iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
- u.uinwater = u.uburied = 0;
+ (void) unconstrain_map();
/*
* Map all buried objects first.
*/
for (obj = level.buriedobjlist; obj; obj = obj->nobj)
- if (!class || (otmp = o_in(obj, class))) {
+ if (!class || (otmp = o_in(obj, class)) != 0) {
if (class) {
if (otmp != obj) {
otmp->ox = obj->ox;
for (x = 1; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
- if ((!class && !boulder) || (otmp = o_in(obj, class))
- || (otmp = o_in(obj, boulder))) {
+ if ((!class && !boulder) || (otmp = o_in(obj, class)) != 0
+ || (otmp = o_in(obj, boulder)) != 0) {
if (class || boulder) {
if (otmp != obj) {
otmp->ox = obj->ox;
if (DEADMONSTER(mtmp))
continue;
for (obj = mtmp->minvent; obj; obj = obj->nobj)
- if ((!class && !boulder) || (otmp = o_in(obj, class))
- || (otmp = o_in(obj, boulder))) {
+ if ((!class && !boulder) || (otmp = o_in(obj, class)) != 0
+ || (otmp = o_in(obj, boulder)) != 0) {
if (!class && !boulder)
otmp = obj;
otmp->ox = mtmp->mx; /* at monster location */
&& (!class || class == objects[mtmp->mappearance].oc_class)) {
struct obj temp;
- temp.oextra = (struct oextra *) 0;
+ temp = zeroobj;
temp.otyp = mtmp->mappearance; /* needed for obj_to_glyph() */
+ temp.quan = 1L;
temp.ox = mtmp->mx;
temp.oy = mtmp->my;
temp.corpsenm = PM_TENGU; /* if mimicing a corpse */
} else if (findgold(mtmp->minvent)
&& (!class || class == COIN_CLASS)) {
struct obj gold;
+
gold = zeroobj; /* ensure oextra is cleared too */
gold.otyp = GOLD_PIECE;
+ gold.quan = (long) rnd(10); /* usually more than 1 */
gold.ox = mtmp->mx;
gold.oy = mtmp->my;
map_object(&gold, 1);
}
}
-
- newsym(u.ux, u.uy);
- u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
+ if (!glyph_is_object(glyph_at(u.ux, u.uy))) {
+ newsym(u.ux, u.uy);
+ ter_typ |= TER_MON;
+ }
/*JP
You("detect the %s of %s.", ct ? "presence" : "absence", stuff);
*/
You("%s%s\81D", stuff, ct ? "\82ð\94\8c©\82µ\82½" : "\82Í\89½\82à\82È\82¢\82±\82Æ\82ª\82í\82©\82Á\82½" );
- display_nhwindow(WIN_MAP, TRUE);
- /*
- * What are we going to do when the hero does an object detect while blind
- * and the detected object covers a known pool?
- */
- docrt(); /* this will correctly reset vision */
+ if (!ct)
+ display_nhwindow(WIN_MAP, TRUE);
+ else
+ browse_map(ter_typ, "object");
+
+ reconstrain_map();
+ docrt(); /* this will correctly reset vision */
if (Underwater)
under_water(2);
if (u.uburied)
: "\82 \82È\82½\82Í\8b°\95|\82Å\82¼\82\82Á\82Æ\82µ\82½\81D");
return 1;
} else {
- boolean woken = FALSE;
+ boolean unconstrained, woken = FALSE;
+ unsigned swallowed = u.uswallow; /* before unconstrain_map() */
cls();
+ unconstrained = unconstrain_map();
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (!mclass || mtmp->data->mlet == mclass
|| (mtmp->data == &mons[PM_LONG_WORM]
&& mclass == S_WORM_TAIL))
- if (mtmp->mx > 0) {
- if (mclass && def_monsyms[mclass].sym == ' ')
- show_glyph(mtmp->mx, mtmp->my,
- detected_mon_to_glyph(mtmp));
- else
- show_glyph(mtmp->mx, mtmp->my,
- mtmp->mtame ? pet_to_glyph(mtmp) : mon_to_glyph(mtmp));
- /* don't be stingy - display entire worm */
- if (mtmp->data == &mons[PM_LONG_WORM])
- detect_wsegs(mtmp, 0);
- }
+ map_monst(mtmp, TRUE);
+
if (otmp && otmp->cursed
&& (mtmp->msleeping || !mtmp->mcanmove)) {
mtmp->msleeping = mtmp->mfrozen = 0;
woken = TRUE;
}
}
- display_self();
+ if (!swallowed)
+ display_self();
/*JP
You("sense the presence of monsters.");
*/
pline("Monsters sense the presence of you.");
*/
pline("\89ö\95¨\82Í\82 \82È\82½\82Ì\91¶\8dÝ\82ð\9ak\82¬\82Â\82¯\82½\81D");
- display_nhwindow(WIN_MAP, TRUE);
- docrt();
+
+ if ((otmp && otmp->blessed) && !unconstrained) {
+ /* persistent detection--just show updated map */
+ display_nhwindow(WIN_MAP, TRUE);
+ } else {
+ /* one-shot detection--allow player to move cursor around and
+ get autodescribe feedback */
+ EDetect_monsters |= I_SPECIAL;
+ browse_map(TER_DETECT | TER_MON, "monster of interest");
+ EDetect_monsters &= ~I_SPECIAL;
+ }
+
+ reconstrain_map();
+ docrt(); /* redraw the screen to remove unseen monsters from map */
if (Underwater)
under_water(2);
if (u.uburied)
if (Hallucination || src_cursed) {
struct obj obj; /* fake object */
- obj.oextra = (struct oextra *) 0;
+ obj = zeroobj;
if (trap) {
obj.ox = trap->tx;
obj.oy = trap->ty;
obj.ox = x;
obj.oy = y;
}
- obj.otyp = (src_cursed) ? GOLD_PIECE : random_object();
+ obj.otyp = !Hallucination ? GOLD_PIECE : random_object();
+ obj.quan = (long) ((obj.otyp == GOLD_PIECE) ? rnd(10)
+ : objects[obj.otyp].oc_merge ? rnd(2) : 1);
obj.corpsenm = random_monster(); /* if otyp == CORPSE */
map_object(&obj, 1);
} else if (trap) {
map_trap(trap, 1);
trap->tseen = 1;
- } else {
+ } else { /* trapped door or trapped chest */
struct trap temp_trap; /* fake trap */
+
+ (void) memset((genericptr_t) &temp_trap, 0, sizeof temp_trap);
temp_trap.tx = x;
temp_trap.ty = y;
temp_trap.ttyp = BEAR_TRAP; /* some kind of trap */
xchar x, y;
int result = OTRAP_NONE;
+ /*
+ * TODO? Display locations of unarmed land mine and beartrap objects.
+ * If so, should they be displayed as objects or as traps?
+ */
+
for (otmp = objlist; otmp; otmp = otmp->nobj) {
if (Is_box(otmp) && otmp->otrapped
&& get_obj_location(otmp, &x, &y, BURIED_TOO | CONTAINED_TOO)) {
*/
int
trap_detect(sobj)
-register struct obj *sobj;
-/* sobj is null if crystal ball, *scroll if gold detection scroll */
+struct obj *sobj; /* null if crystal ball, *scroll if gold detection scroll */
{
register struct trap *ttmp;
struct monst *mon;
- int door, glyph, tr;
+ int door, glyph, tr, ter_typ = TER_DETECT | TER_TRP;
int cursed_src = sobj && sobj->cursed;
boolean found = FALSE;
coord cc;
+ if (u.usteed)
+ u.usteed->mx = u.ux, u.usteed->my = u.uy;
+
/* floor/ceiling traps */
for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
if (ttmp->tx != u.ux || ttmp->ty != u.uy)
else
found = TRUE;
}
- if ((tr = detect_obj_traps(level.buriedobjlist, FALSE, 0))
- != OTRAP_NONE) {
+ if ((tr = detect_obj_traps(level.buriedobjlist, FALSE, 0)) != OTRAP_NONE) {
if (tr & OTRAP_THERE)
goto outtrapmap;
else
*/
Your("%s\82Í\82Þ\82¸\82Þ\82¸\82µ\82½\81D", makeplural(body_part(TOE)));
return 0;
+
outtrapmap:
cls();
- iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
- u.uinwater = u.uburied = 0;
-
+ (void) unconstrain_map();
/* show chest traps first, so that subsequent floor trap display
will override if both types are present at the same location */
(void) detect_obj_traps(fobj, TRUE, cursed_src);
/* redisplay hero unless sense_trap() revealed something at <ux,uy> */
glyph = glyph_at(u.ux, u.uy);
- if (!(glyph_is_trap(glyph) || glyph_is_object(glyph)))
+ if (!(glyph_is_trap(glyph) || glyph_is_object(glyph))) {
newsym(u.ux, u.uy);
- u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
-
+ ter_typ |= TER_MON; /* for autodescribe at <u.ux,u.uy> */
+ }
/*JP
You_feel("%s.", cursed_src ? "very greedy" : "entrapped");
*/
You("%s\8bC\8e\9d\82É\82È\82Á\82½\81D", cursed_src ? "\82Æ\82Ä\82à\82Ç\82ñ\97~\82È" : "\82¾\82Ü\82³\82ê\82Ä\82¢\82é\82æ\82¤\82È");
- /* wait for user to respond, then reset map display to normal */
- display_nhwindow(WIN_MAP, TRUE);
- docrt();
+
+ browse_map(ter_typ, "trap of interest");
+
+ reconstrain_map();
+ docrt(); /* redraw the screen to remove unseen traps from the map */
if (Underwater)
under_water(2);
if (u.uburied)
*/
multi_reason = "\90\85\8f»\8b\85\82ð\94`\82«\8d\9e\82ñ\82Å\82¢\82é\8e\9e\82É";
nomovemsg = "";
- if (obj->spe <= 0)
+ if (obj->spe <= 0) {
/*JP
pline_The("vision is unclear.");
*/
pline("\89f\91\9c\82Í\95s\91N\96¾\82¾\82Á\82½\81D");
- else {
- int class;
+ } else {
+ int class, i;
int ret = 0;
makeknown(CRYSTAL_BALL);
case '^':
ret = trap_detect((struct obj *) 0);
break;
- default: {
- int i = rn2(SIZE(level_detects));
-#if 0 /*JP*/
+ default:
+ i = rn2(SIZE(level_detects));
+#if 0 /*JP:T*/
You_see("%s, %s.", level_detects[i].what,
level_distance(level_detects[i].where));
#else
You_see("%s\82ð%s\8c©\82½\81D", level_detects[i].what,
level_distance(level_detects[i].where));
#endif
- }
ret = 0;
break;
}
do_mapping()
{
register int zx, zy;
+ boolean unconstrained;
- iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
- u.uinwater = u.uburied = 0;
+ unconstrained = unconstrain_map();
for (zx = 1; zx < COLNO; zx++)
for (zy = 0; zy < ROWNO; zy++)
show_map_spot(zx, zy);
- u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
- if (!level.flags.hero_memory || Underwater) {
+
+ if (!level.flags.hero_memory || unconstrained) {
flush_screen(1); /* flush temp screen */
- display_nhwindow(WIN_MAP, TRUE); /* wait */
+ /* browse_map() instead of display_nhwindow(WIN_MAP, TRUE) */
+ browse_map(TER_DETECT | TER_MAP | TER_TRP | TER_OBJ,
+ "anything of interest");
docrt();
}
+ reconstrain_map();
exercise(A_WIS, TRUE);
}
+/* clairvoyance */
void
-do_vicinity_map()
+do_vicinity_map(sobj)
+struct obj *sobj; /* scroll--actually fake spellbook--object */
{
register int zx, zy;
- int lo_y = (u.uy - 5 < 0 ? 0 : u.uy - 5),
- hi_y = (u.uy + 6 > ROWNO ? ROWNO : u.uy + 6),
- lo_x = (u.ux - 9 < 1 ? 1 : u.ux - 9), /* avoid column 0 */
- hi_x = (u.ux + 10 > COLNO ? COLNO : u.ux + 10);
-
- for (zx = lo_x; zx < hi_x; zx++)
- for (zy = lo_y; zy < hi_y; zy++)
+ struct monst *mtmp;
+ boolean unconstrained, refresh = FALSE, mdetected = FALSE,
+ extended = (sobj && sobj->blessed);
+ int lo_y = ((u.uy - 5 < 0) ? 0 : u.uy - 5),
+ hi_y = ((u.uy + 6 >= ROWNO) ? ROWNO - 1 : u.uy + 6),
+ lo_x = ((u.ux - 9 < 1) ? 1 : u.ux - 9), /* avoid column 0 */
+ hi_x = ((u.ux + 10 >= COLNO) ? COLNO - 1 : u.ux + 10),
+ ter_typ = TER_DETECT | TER_MAP | TER_TRP | TER_OBJ;
+
+ unconstrained = unconstrain_map();
+ for (zx = lo_x; zx <= hi_x; zx++)
+ for (zy = lo_y; zy <= hi_y; zy++) {
show_map_spot(zx, zy);
- if (!level.flags.hero_memory || Underwater) {
+ if (extended && (mtmp = m_at(zx, zy)) != 0
+ && mtmp->mx == zx && mtmp->my == zy) { /* skip worm tails */
+ int oldglyph = glyph_at(zx, zy);
+
+ map_monst(mtmp, FALSE);
+ if (glyph_at(zx, zy) != oldglyph)
+ mdetected = TRUE;
+ }
+ }
+
+ if (!level.flags.hero_memory || unconstrained || mdetected) {
flush_screen(1); /* flush temp screen */
- display_nhwindow(WIN_MAP, TRUE); /* wait */
- docrt();
+ /* the getpos() prompt from browse_map() is only shown when
+ flags.verbose is set, but make this unconditional so that
+ not-verbose users become aware of the prompting situation */
+ You("sense your surroundings.");
+ if (extended || glyph_is_monster(glyph_at(u.ux, u.uy)))
+ ter_typ |= TER_MON;
+ if (extended)
+ EDetect_monsters |= I_SPECIAL;
+ browse_map(ter_typ, "anything of interest");
+ EDetect_monsters &= ~I_SPECIAL;
+ refresh = TRUE;
}
+ reconstrain_map();
+ if (refresh)
+ docrt();
}
/* convert a secret door into a normal door */
}
if (!canspotmon(mtmp) && !glyph_is_invisible(levl[zx][zy].glyph))
map_invisible(zx, zy);
- } else if (glyph_is_invisible(levl[zx][zy].glyph)) {
- unmap_object(zx, zy);
- newsym(zx, zy);
+ } else if (unmap_invisible(zx, zy)) {
(*(int *) num)++;
}
}
}
}
+STATIC_OVL int
+mfind0(mtmp, via_warning)
+struct monst *mtmp;
+boolean via_warning;
+{
+ xchar x = mtmp->mx,
+ y = mtmp->my;
+
+ if (via_warning && !warning_of(mtmp))
+ return -1;
+
+ if (mtmp->m_ap_type) {
+ seemimic(mtmp);
+ find:
+ exercise(A_WIS, TRUE);
+ if (!canspotmon(mtmp)) {
+ if (glyph_is_invisible(levl[x][y].glyph)) {
+ /* Found invisible monster in a square which already has
+ * an 'I' in it. Logically, this should still take time
+ * and lead to a return 1, but if we did that the player
+ * would keep finding the same monster every turn.
+ */
+ return -1;
+ } else {
+/*JP
+ You_feel("an unseen monster!");
+*/
+ You("\8c©\82¦\82È\82¢\89ö\95¨\82Ì\8bC\94z\82ð\8a´\82¶\82½\81I");
+ map_invisible(x, y);
+ }
+ } else if (!sensemon(mtmp))
+#if 0 /*JP:T*/
+ You("find %s.",
+ mtmp->mtame ? y_monnam(mtmp) : a_monnam(mtmp));
+#else
+ You("%s\82ð\8c©\82Â\82¯\82½\81D",
+ mtmp->mtame ? y_monnam(mtmp) : a_monnam(mtmp));
+#endif
+ return 1;
+ }
+ if (!canspotmon(mtmp)) {
+ if (mtmp->mundetected
+ && (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL))
+ if (via_warning) {
+ Your("warning senses cause you to take a second %s.",
+ Blind ? "to check nearby" : "look close by");
+ display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
+ }
+ mtmp->mundetected = 0;
+ newsym(x, y);
+ goto find;
+ }
+ return 0;
+}
+
int
dosearch0(aflag)
register int aflag; /* intrinsic autosearch vs explicit searching */
{
#ifdef GCC_BUG
- /* some versions of gcc seriously muck up nested loops. if you get strange
- crashes while searching in a version compiled with gcc, try putting
- #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the
- makefile).
+ /* Some old versions of gcc seriously muck up nested loops. If you get
+ * strange crashes while searching in a version compiled with gcc, try
+ * putting #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in
+ * the makefile).
*/
volatile xchar x, y;
#else
unblock_point(x, y); /* vision */
exercise(A_WIS, TRUE);
nomul(0);
- feel_location(x, y); /* make sure it shows up */
+ feel_newsym(x, y); /* make sure it shows up */
/*JP
You("find a hidden passage.");
*/
} else {
/* Be careful not to find anything in an SCORR or SDOOR */
if ((mtmp = m_at(x, y)) != 0 && !aflag) {
- if (mtmp->m_ap_type) {
- seemimic(mtmp);
- find:
- exercise(A_WIS, TRUE);
- if (!canspotmon(mtmp)) {
- if (glyph_is_invisible(levl[x][y].glyph)) {
- /* found invisible monster in a square
- * which already has an 'I' in it.
- * Logically, this should still take
- * time and lead to a return(1), but
- * if we did that the player would keep
- * finding the same monster every turn.
- */
- continue;
- } else {
-/*JP
- You_feel("an unseen monster!");
-*/
- You("\8c©\82¦\82È\82¢\89ö\95¨\82Ì\8bC\94z\82ð\8a´\82¶\82½\81I");
- map_invisible(x, y);
- }
- } else if (!sensemon(mtmp))
-/*JP
- You("find %s.", mtmp->mtame
-*/
- You("%s\82ð\8c©\82Â\82¯\82½\81D", mtmp->mtame
- ? y_monnam(mtmp)
- : a_monnam(mtmp));
- return 1;
- }
- if (!canspotmon(mtmp)) {
- if (mtmp->mundetected
- && (is_hider(mtmp->data)
- || mtmp->data->mlet == S_EEL))
- mtmp->mundetected = 0;
- newsym(x, y);
- goto find;
- }
+ int mfres = mfind0(mtmp, 0);
+
+ if (mfres == -1)
+ continue;
+ else if (mfres > 0)
+ return mfres;
}
/* see if an invisible monster has moved--if Blind,
* feel_location() already did it
*/
- if (!aflag && !mtmp && !Blind
- && glyph_is_invisible(levl[x][y].glyph)) {
- unmap_object(x, y);
- newsym(x, y);
- }
+ if (!aflag && !mtmp && !Blind)
+ (void) unmap_invisible(x, y);
if ((trap = t_at(x, y)) && !trap->tseen && !rnl(8)) {
nomul(0);
return dosearch0(0);
}
+void
+warnreveal()
+{
+ int x, y;
+ struct monst *mtmp;
+
+ for (x = u.ux - 1; x <= u.ux + 1; x++)
+ for (y = u.uy - 1; y <= u.uy + 1; y++) {
+ if (!isok(x, y) || (x == u.ux && y == u.uy))
+ continue;
+ if ((mtmp = m_at(x, y)) != 0
+ && warning_of(mtmp) && mtmp->mundetected)
+ (void) mfind0(mtmp, 1); /* via_warning */
+ }
+}
+
/* Pre-map the sokoban levels */
void
sokoban_detect()
}
}
+STATIC_DCL int
+reveal_terrain_getglyph(x, y, full, swallowed, default_glyph, which_subset)
+int x, y, full;
+unsigned swallowed;
+int default_glyph, which_subset;
+{
+ int glyph, levl_glyph;
+ uchar seenv;
+ boolean keep_traps = (which_subset & TER_TRP) !=0,
+ keep_objs = (which_subset & TER_OBJ) != 0,
+ keep_mons = (which_subset & TER_MON) != 0;
+ struct monst *mtmp;
+ struct trap *t;
+
+ /* for 'full', show the actual terrain for the entire level,
+ otherwise what the hero remembers for seen locations with
+ monsters, objects, and/or traps removed as caller dictates */
+ seenv = (full || level.flags.hero_memory)
+ ? levl[x][y].seenv : cansee(x, y) ? SVALL : 0;
+ if (full) {
+ levl[x][y].seenv = SVALL;
+ glyph = back_to_glyph(x, y);
+ levl[x][y].seenv = seenv;
+ } else {
+ levl_glyph = level.flags.hero_memory
+ ? levl[x][y].glyph
+ : seenv ? back_to_glyph(x, y): default_glyph;
+ /* glyph_at() returns the displayed glyph, which might
+ be a monster. levl[][].glyph contains the remembered
+ glyph, which will never be a monster (unless it is
+ the invisible monster glyph, which is handled like
+ an object, replacing any object or trap at its spot) */
+ glyph = !swallowed ? glyph_at(x, y) : levl_glyph;
+ if (keep_mons && x == u.ux && y == u.uy && swallowed)
+ glyph = mon_to_glyph(u.ustuck);
+ else if (((glyph_is_monster(glyph)
+ || glyph_is_warning(glyph)) && !keep_mons)
+ || glyph_is_swallow(glyph))
+ glyph = levl_glyph;
+ if (((glyph_is_object(glyph) && !keep_objs)
+ || glyph_is_invisible(glyph))
+ && keep_traps && !covers_traps(x, y)) {
+ if ((t = t_at(x, y)) != 0 && t->tseen)
+ glyph = trap_to_glyph(t);
+ }
+ if ((glyph_is_object(glyph) && !keep_objs)
+ || (glyph_is_trap(glyph) && !keep_traps)
+ || glyph_is_invisible(glyph)) {
+ if (!seenv) {
+ glyph = default_glyph;
+ } else if (lastseentyp[x][y] == levl[x][y].typ) {
+ glyph = back_to_glyph(x, y);
+ } else {
+ /* look for a mimic here posing as furniture;
+ if we don't find one, we'll have to fake it */
+ if ((mtmp = m_at(x, y)) != 0
+ && mtmp->m_ap_type == M_AP_FURNITURE) {
+ glyph = cmap_to_glyph(mtmp->mappearance);
+ } else {
+ /* we have a topology type but we want a screen
+ symbol in order to derive a glyph; some screen
+ symbols need the flags field of levl[][] in
+ addition to the type (to disambiguate STAIRS to
+ S_upstair or S_dnstair, for example; current
+ flags might not be intended for remembered type,
+ but we've got no other choice) */
+ schar save_typ = levl[x][y].typ;
+
+ levl[x][y].typ = lastseentyp[x][y];
+ glyph = back_to_glyph(x, y);
+ levl[x][y].typ = save_typ;
+ }
+ }
+ }
+ }
+ if (glyph == cmap_to_glyph(S_darkroom))
+ glyph = cmap_to_glyph(S_room); /* FIXME: dirty hack */
+ return glyph;
+}
+
+#ifdef DUMPLOG
+void
+dump_map()
+{
+ int x, y, glyph, skippedrows, lastnonblank;
+ int subset = TER_MAP | TER_TRP | TER_OBJ | TER_MON;
+ int default_glyph = cmap_to_glyph(level.flags.arboreal ? S_tree : S_stone);
+ char buf[BUFSZ];
+ boolean blankrow, toprow;
+
+ /*
+ * Squeeze out excess vertial space when dumping the map.
+ * If there are any blank map rows at the top, suppress them
+ * (our caller has already printed a separator). If there is
+ * more than one blank map row at the bottom, keep just one.
+ * Any blank rows within the middle of the map are kept.
+ * Note: putstr() with winid==0 is for dumplog.
+ */
+ skippedrows = 0;
+ toprow = TRUE;
+ for (y = 0; y < ROWNO; y++) {
+ blankrow = TRUE; /* assume blank until we discover otherwise */
+ lastnonblank = -1; /* buf[] index rather than map's x */
+ for (x = 1; x < COLNO; x++) {
+ int ch, color;
+ unsigned special;
+
+ glyph = reveal_terrain_getglyph(x, y, FALSE, u.uswallow,
+ default_glyph, subset);
+ (void) mapglyph(glyph, &ch, &color, &special, x, y);
+ buf[x - 1] = ch;
+ if (ch != ' ') {
+ blankrow = FALSE;
+ lastnonblank = x - 1;
+ }
+ }
+ if (!blankrow) {
+ buf[lastnonblank + 1] = '\0';
+ if (toprow) {
+ skippedrows = 0;
+ toprow = FALSE;
+ }
+ for (x = 0; x < skippedrows; x++)
+ putstr(0, 0, "");
+ putstr(0, 0, buf); /* map row #y */
+ skippedrows = 0;
+ } else {
+ ++skippedrows;
+ }
+ }
+ if (skippedrows)
+ putstr(0, 0, "");
+}
+#endif /* DUMPLOG */
+
/* idea from crawl; show known portion of map without any monsters,
objects, or traps occluding the view of the underlying terrain */
void
*/
You("\8d¬\97\90\82µ\82Ä\82¢\82é\82Ì\82Å\82»\82ê\82Í\82Å\82«\82È\82¢\81D");
} else {
- int x, y, glyph, levl_glyph, default_glyph;
- uchar seenv;
- unsigned save_swallowed;
- struct monst *mtmp;
- struct trap *t;
+ int x, y, glyph, default_glyph;
char buf[BUFSZ];
- boolean keep_traps = (which_subset & 1) !=0,
- keep_objs = (which_subset & 2) != 0,
- keep_mons = (which_subset & 4) != 0; /* actually always 0 */
-
- save_swallowed = u.uswallow;
- iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
- u.uinwater = u.uburied = 0;
- u.uswallow = 0;
+ /* there is a TER_MAP bit too; we always show map regardless of it */
+ boolean keep_traps = (which_subset & TER_TRP) !=0,
+ keep_objs = (which_subset & TER_OBJ) != 0,
+ keep_mons = (which_subset & TER_MON) != 0; /* not used */
+ unsigned swallowed = u.uswallow; /* before unconstrain_map() */
+
+ if (unconstrain_map())
+ docrt();
default_glyph = cmap_to_glyph(level.flags.arboreal ? S_tree : S_stone);
- /* for 'full', show the actual terrain for the entire level,
- otherwise what the hero remembers for seen locations with
- monsters, objects, and/or traps removed as caller dictates */
+
for (x = 1; x < COLNO; x++)
for (y = 0; y < ROWNO; y++) {
- seenv = (full || level.flags.hero_memory)
- ? levl[x][y].seenv : cansee(x, y) ? SVALL : 0;
- if (full) {
- levl[x][y].seenv = SVALL;
- glyph = back_to_glyph(x, y);
- levl[x][y].seenv = seenv;
- } else {
- levl_glyph = level.flags.hero_memory
- ? levl[x][y].glyph
- : seenv
- ? back_to_glyph(x, y)
- : default_glyph;
- /* glyph_at() returns the displayed glyph, which might
- be a monster. levl[][].glyph contains the remembered
- glyph, which will never be a monster (unless it is
- the invisible monster glyph, which is handled like
- an object, replacing any object or trap at its spot) */
- glyph = !save_swallowed ? glyph_at(x, y) : levl_glyph;
- if (keep_mons && x == u.ux && y == u.uy && save_swallowed)
- glyph = mon_to_glyph(u.ustuck);
- else if (((glyph_is_monster(glyph)
- || glyph_is_warning(glyph)) && !keep_mons)
- || glyph_is_swallow(glyph))
- glyph = levl_glyph;
- if (((glyph_is_object(glyph) && !keep_objs)
- || glyph_is_invisible(glyph))
- && keep_traps && !covers_traps(x, y)) {
- if ((t = t_at(x, y)) != 0 && t->tseen)
- glyph = trap_to_glyph(t);
- }
- if ((glyph_is_object(glyph) && !keep_objs)
- || (glyph_is_trap(glyph) && !keep_traps)
- || glyph_is_invisible(glyph)) {
- if (!seenv) {
- glyph = default_glyph;
- } else if (lastseentyp[x][y] == levl[x][y].typ) {
- glyph = back_to_glyph(x, y);
- } else {
- /* look for a mimic here posing as furniture;
- if we don't find one, we'll have to fake it */
- if ((mtmp = m_at(x, y)) != 0
- && mtmp->m_ap_type == M_AP_FURNITURE) {
- glyph = cmap_to_glyph(mtmp->mappearance);
- } else {
- /* we have a topology type but we want a
- screen symbol in order to derive a glyph;
- some screen symbols need the flags field
- of levl[][] in addition to the type
- (to disambiguate STAIRS to S_upstair or
- S_dnstair, for example; current flags
- might not be intended for remembered
- type, but we've got no other choice) */
- schar save_typ = levl[x][y].typ;
-
- levl[x][y].typ = lastseentyp[x][y];
- glyph = back_to_glyph(x, y);
- levl[x][y].typ = save_typ;
- }
- }
- }
- }
+ glyph = reveal_terrain_getglyph(x,y, full, swallowed,
+ default_glyph, which_subset);
show_glyph(x, y, glyph);
}
- /* [TODO: highlight hero's location somehow] */
- u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
- if (save_swallowed)
- u.uswallow = 1;
+ /* hero's location is not highlighted, but getpos() starts with
+ cursor there, and after moving it anywhere '@' moves it back */
flush_screen(1);
if (full) {
/*JP
pline("Showing %s only...", buf);
*/
pline("%s\82¾\82¯\82ð\8c©\82é\81D\81D\81D", buf);
- display_nhwindow(WIN_MAP, TRUE); /* give "--More--" prompt */
+
+ /* allow player to move cursor around and get autodescribe feedback
+ based on what is visible now rather than what is on 'real' map */
+ which_subset |= TER_MAP; /* guarantee non-zero */
+ browse_map(which_subset, "anything of interest");
+
+ reconstrain_map();
docrt(); /* redraw the screen, restoring regular map */
if (Underwater)
under_water(2);