Blindfold removal fix
[slashemextended.git] / src / detect.c
bloba1691ac077722116cb481c367b7a1560ce18434f
1 /* SCCS Id: @(#)detect.c 3.4 2003/08/13 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /*
6 * Detection routines, including crystal ball, magic mapping, and search
7 * command.
8 */
10 #include "hack.h"
11 #include "artifact.h"
13 extern boolean known; /* from read.c */
15 STATIC_DCL void do_dknown_of(struct obj *);
16 STATIC_DCL boolean check_map_spot(int,int,CHAR_P,unsigned);
17 STATIC_DCL boolean clear_stale_map(CHAR_P,unsigned);
18 STATIC_DCL void sense_trap(struct trap *,XCHAR_P,XCHAR_P,int);
19 STATIC_DCL void show_map_spot(int,int);
20 STATIC_DCL void show_map_spotX(int,int);
21 STATIC_PTR void findone(int,int,void *);
22 STATIC_PTR void findoneX(int,int,void *);
23 STATIC_PTR void openone(int,int,void *);
25 /* Recursively search obj for an object in class oclass and return 1st found */
26 struct obj *
27 o_in(obj, oclass)
28 struct obj* obj;
29 char oclass;
31 register struct obj* otmp;
32 struct obj *temp;
34 if (obj->oclass == oclass) return obj;
37 * Pills inside medical kits are specially handled (see apply.c).
38 * We don't want them to detect as food because then they will be
39 * shown as pink pills, which are something quite different. In
40 * practice the only other possible contents of medical kits are
41 * bandages and phials, neither of which is detectable by any
42 * means so we can simply avoid looking in medical kits.
44 if (Has_contents(obj) && obj->otyp != MEDICAL_KIT) {
45 for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
46 if (otmp->oclass == oclass) return otmp;
47 else if (Has_contents(otmp) && otmp->otyp != MEDICAL_KIT &&
48 (temp = o_in(otmp, oclass)))
49 return temp;
51 return (struct obj *) 0;
54 /* Recursively search obj for an object made of specified material and return 1st found */
55 struct obj *
56 o_material(obj, material)
57 struct obj* obj;
58 unsigned material;
60 register struct obj* otmp;
61 struct obj *temp;
63 if (objects[obj->otyp].oc_material == material) return obj;
65 if (Has_contents(obj)) {
66 for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
67 if (objects[otmp->otyp].oc_material == material) return otmp;
68 else if (Has_contents(otmp) && (temp = o_material(otmp, material)))
69 return temp;
71 return (struct obj *) 0;
74 STATIC_OVL void
75 do_dknown_of(obj)
76 struct obj *obj;
78 struct obj *otmp;
80 obj->dknown = 1;
81 if (Has_contents(obj)) {
82 for(otmp = obj->cobj; otmp; otmp = otmp->nobj)
83 do_dknown_of(otmp);
87 /* Check whether the location has an outdated object displayed on it. */
88 STATIC_OVL boolean
89 check_map_spot(x, y, oclass, material)
90 int x, y;
91 register char oclass;
92 unsigned material;
94 register int glyph;
95 register struct obj *otmp;
96 register struct monst *mtmp;
98 glyph = glyph_at(x,y);
99 if (glyph_is_object(glyph)) {
100 /* there's some object shown here */
101 if (oclass == ALL_CLASSES) {
102 return((boolean)( !(level.objects[x][y] || /* stale if nothing here */
103 ((mtmp = m_at(x,y)) != 0 &&
105 #ifndef GOLDOBJ
106 mtmp->mgold ||
107 #endif
108 mtmp->minvent)))));
109 } else {
110 if (material && objects[glyph_to_obj(glyph)].oc_material == material) {
111 /* the object shown here is of interest because material matches */
112 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
113 if (o_material(otmp, MT_GOLD)) return FALSE;
114 /* didn't find it; perhaps a monster is carrying it */
115 if ((mtmp = m_at(x,y)) != 0) {
116 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
117 if (o_material(otmp, MT_GOLD)) return FALSE;
119 /* detection indicates removal of this object from the map */
120 return TRUE;
122 if (oclass && objects[glyph_to_obj(glyph)].oc_class == oclass) {
123 /* the object shown here is of interest because its class matches */
124 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
125 if (o_in(otmp, oclass)) return FALSE;
126 /* didn't find it; perhaps a monster is carrying it */
127 #ifndef GOLDOBJ
128 if ((mtmp = m_at(x,y)) != 0) {
129 if (oclass == COIN_CLASS && mtmp->mgold)
130 return FALSE;
131 else for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
132 if (o_in(otmp, oclass)) return FALSE;
134 #else
135 if ((mtmp = m_at(x,y)) != 0) {
136 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
137 if (o_in(otmp, oclass)) return FALSE;
139 #endif
140 /* detection indicates removal of this object from the map */
141 return TRUE;
145 return FALSE;
149 When doing detection, remove stale data from the map display (corpses
150 rotted away, objects carried away by monsters, etc) so that it won't
151 reappear after the detection has completed. Return true if noticeable
152 change occurs.
154 STATIC_OVL boolean
155 clear_stale_map(oclass, material)
156 register char oclass;
157 unsigned material;
159 register int zx, zy;
160 register boolean change_made = FALSE;
162 for (zx = 1; zx < COLNO; zx++)
163 for (zy = 0; zy < ROWNO; zy++)
164 if (check_map_spot(zx, zy, oclass,material)) {
165 unmap_object(zx, zy);
166 change_made = TRUE;
169 return change_made;
172 /* look for gold, on the floor or in monsters' possession */
174 gold_detect(sobj)
175 register struct obj *sobj;
177 register struct obj *obj;
178 register struct monst *mtmp;
179 int uw = u.uinwater;
180 struct obj *temp;
181 boolean stale;
183 known = stale = clear_stale_map(COIN_CLASS,
184 (unsigned)(sobj->blessed ? MT_GOLD : 0));
186 if (DetectionMethodsDontWork) {
187 if (sobj) strange_feeling(sobj, "Huh.");
188 return 0;
191 /* look for gold carried by monsters (might be in a container) */
192 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
193 if (DEADMONSTER(mtmp)) continue; /* probably not needed in this case but... */
194 #ifndef GOLDOBJ
195 if (mtmp->mgold || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
196 #else
197 if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
198 #endif
199 known = TRUE;
200 goto outgoldmap; /* skip further searching */
201 } else for (obj = mtmp->minvent; obj; obj = obj->nobj)
202 if (sobj->blessed && o_material(obj, MT_GOLD)) {
203 known = TRUE;
204 goto outgoldmap;
205 } else if (o_in(obj, COIN_CLASS)) {
206 known = TRUE;
207 goto outgoldmap; /* skip further searching */
211 /* look for gold objects */
212 for (obj = fobj; obj; obj = obj->nobj) {
213 if (sobj->blessed && o_material(obj, MT_GOLD)) {
214 known = TRUE;
215 if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap;
216 } else if (o_in(obj, COIN_CLASS)) {
217 known = TRUE;
218 if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap;
222 if (!known) {
223 /* no gold found on floor or monster's inventory.
224 adjust message if you have gold in your inventory */
225 if (sobj) {
226 char buf[BUFSZ];
227 if (youmonst.data == &mons[PM_GOLD_GOLEM]) {
228 sprintf(buf, "You feel like a million %s!",
229 currency(2L));
230 } else if (hidden_gold() ||
231 #ifndef GOLDOBJ
232 u.ugold)
233 #else
234 money_cnt(invent))
235 #endif
236 strcpy(buf,
237 "You feel worried about your future financial situation.");
238 else
239 strcpy(buf, "You feel materially poor.");
240 strange_feeling(sobj, buf);
242 return(1);
244 /* only under me - no separate display required */
245 if (stale) docrt();
246 You("notice some gold between your %s.", makeplural(body_part(FOOT)));
247 return(0);
249 outgoldmap:
250 cls();
252 u.uinwater = 0;
253 /* Discover gold locations. */
254 for (obj = fobj; obj; obj = obj->nobj) {
255 if (sobj->blessed && (temp = o_material(obj, MT_GOLD))) {
256 if (temp != obj) {
257 temp->ox = obj->ox;
258 temp->oy = obj->oy;
260 map_object(temp,1);
261 } else if ((temp = o_in(obj, COIN_CLASS))) {
262 if (temp != obj) {
263 temp->ox = obj->ox;
264 temp->oy = obj->oy;
266 map_object(temp,1);
269 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
270 if (DEADMONSTER(mtmp)) continue; /* probably overkill here */
271 #ifndef GOLDOBJ
272 if (mtmp->mgold || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
273 #else
274 if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
275 #endif
276 struct obj gold;
278 gold.otyp = GOLD_PIECE;
279 gold.ox = mtmp->mx;
280 gold.oy = mtmp->my;
281 map_object(&gold,1);
282 } else for (obj = mtmp->minvent; obj; obj = obj->nobj)
283 if (sobj->blessed && (temp = o_material(obj, MT_GOLD))) {
284 temp->ox = mtmp->mx;
285 temp->oy = mtmp->my;
286 map_object(temp,1);
287 break;
288 } else if ((temp = o_in(obj, COIN_CLASS))) {
289 temp->ox = mtmp->mx;
290 temp->oy = mtmp->my;
291 map_object(temp,1);
292 break;
296 newsym(u.ux,u.uy);
297 You_feel("very greedy, and sense gold!");
298 exercise(A_WIS, TRUE);
299 display_nhwindow(WIN_MAP, TRUE);
300 docrt();
301 u.uinwater = uw;
302 if (Underwater && !Swimming) under_water(2);
303 if (u.uburied) under_ground(2);
304 return(0);
307 /* returns 1 if nothing was detected */
308 /* returns 0 if something was detected */
310 food_detect(sobj)
311 register struct obj *sobj;
313 register struct obj *obj;
314 register struct monst *mtmp;
315 register int ct = 0, ctu = 0;
316 boolean confused = (Confusion || (sobj && sobj->cursed)), stale;
317 char oclass = confused ? POTION_CLASS : FOOD_CLASS;
318 const char *what = confused ? something : "food";
319 int uw = u.uinwater;
321 boolean stupiddetect = (sobj && (sobj->otyp == SPE_DETECT_FOOD));
322 boolean guaranteed = (!sobj || (sobj && (sobj->otyp != SPE_DETECT_FOOD)) );
324 stale = clear_stale_map(oclass, 0);
326 if (DetectionMethodsDontWork) {
327 if (sobj) strange_feeling(sobj, "Huh.");
328 return 0;
331 for (obj = fobj; obj; obj = obj->nobj)
332 if (o_in(obj, oclass)) {
333 if (obj->ox == u.ux && obj->oy == u.uy) ctu++;
334 else ct++;
336 for (mtmp = fmon; mtmp && !ct; mtmp = mtmp->nmon) {
337 /* no DEADMONSTER(mtmp) check needed since dmons never have inventory */
338 for (obj = mtmp->minvent; obj; obj = obj->nobj)
339 if (o_in(obj, oclass)) {
340 ct++;
341 break;
345 if (!ct && !ctu) {
346 known = stale && !confused;
347 if (stale) {
348 docrt();
349 You("sense a lack of %s nearby.", what);
350 if (sobj && sobj->blessed) {
351 if (!u.urealedibility) Your("%s starts to tingle.", body_part(NOSE));
352 u.urealedibility += 1;
354 } else if (sobj) {
355 char buf[BUFSZ];
356 sprintf(buf, "Your %s twitches%s.", body_part(NOSE),
357 (sobj->blessed && !u.urealedibility) ? " then starts to tingle" : "");
358 if (sobj->blessed && !u.urealedibility) {
359 boolean savebeginner = flags.beginner; /* prevent non-delivery of */
360 flags.beginner = FALSE; /* message */
361 strange_feeling(sobj, buf);
362 flags.beginner = savebeginner;
363 u.urealedibility += 1;
364 } else {
365 if (sobj->blessed) u.urealedibility += 1;
366 strange_feeling(sobj, buf);
369 return !stale;
370 } else if (!ct) {
371 known = TRUE;
372 You("%s %s nearby.", sobj ? "smell" : "sense", what);
373 if (sobj && sobj->blessed) {
374 if (!u.urealedibility) pline("Your %s starts to tingle.", body_part(NOSE));
375 u.urealedibility += 1;
377 } else {
378 struct obj *temp;
379 known = TRUE;
380 cls();
381 u.uinwater = 0;
382 for (obj = fobj; obj; obj = obj->nobj)
383 if ((temp = o_in(obj, oclass)) != 0) {
384 if (temp != obj) {
385 temp->ox = obj->ox;
386 temp->oy = obj->oy;
388 if ( (guaranteed || rn2(2)) && !(stupiddetect && isok(temp->ox, temp->oy) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, temp->ox, temp->oy) > 1601) ) ) map_object(temp, 1);
391 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
392 /* no DEADMONSTER(mtmp) check needed since dmons never have inventory */
393 for (obj = mtmp->minvent; obj; obj = obj->nobj)
394 if ((temp = o_in(obj, oclass)) != 0) {
395 temp->ox = mtmp->mx;
396 temp->oy = mtmp->my;
398 if ( (guaranteed || rn2(2)) && !(stupiddetect && isok(temp->ox, temp->oy) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, temp->ox, temp->oy) > 1601) ) ) map_object(temp,1);
399 break; /* skip rest of this monster's inventory */
401 newsym(u.ux,u.uy);
402 if (sobj) {
403 if (sobj->blessed) {
404 Your("%s %s to tingle and you smell %s.", body_part(NOSE),
405 u.urealedibility ? "continues" : "starts", what);
406 u.urealedibility += 1;
407 } else
408 Your("%s tingles and you smell %s.", body_part(NOSE), what);
410 else You("sense %s.", what);
411 display_nhwindow(WIN_MAP, TRUE);
412 exercise(A_WIS, TRUE);
413 docrt();
414 u.uinwater = uw;
415 if (Underwater && !Swimming) under_water(2);
416 if (u.uburied) under_ground(2);
418 return(0);
422 * Used for scrolls, potions, spells, and crystal balls. Returns:
424 * 1 - nothing was detected
425 * 0 - something was detected
428 object_detect(detector, class)
429 struct obj *detector; /* object doing the detecting */
430 int class; /* an object class, 0 for all */
432 register int x, y;
433 char stuff[BUFSZ];
434 int is_cursed = (detector && detector->cursed);
435 int do_dknown = (detector && (detector->oclass == POTION_CLASS ||
436 detector->oclass == SPBOOK_CLASS ||
437 detector->oartifact ) &&
438 detector->blessed);
439 int guaranteed = (detector && !(detector->otyp == SPE_DETECT_TREASURE) && !(detector->otyp == SPE_RANDOM_DETECTION) && !(detector->otyp == SPE_MAP_LEVEL) && !(detector->otyp == SPE_MAGIC_MAPPING));
440 boolean stupiddetect = (detector && (detector->otyp == SPE_DETECT_TREASURE || detector->otyp == SPE_RANDOM_DETECTION || detector->otyp == SPE_MAGIC_MAPPING));
441 int likely = (detector && (detector->otyp == SPE_MAP_LEVEL));
442 int ct = 0, ctu = 0;
443 register struct obj *obj, *otmp = (struct obj *)0;
444 register struct monst *mtmp;
445 int uw = u.uinwater;
446 int sym, boulder = 0;
448 if (DetectionMethodsDontWork) {
449 if (detector) strange_feeling(detector, "Huh.");
450 return 1;
453 if (class < 0 || class >= MAXOCLASSES) {
454 impossible("object_detect: illegal class %d", class);
455 class = 0;
458 /* Special boulder symbol check - does the class symbol happen
459 * to match iflags.bouldersym which is a user-defined?
460 * If so, that means we aren't sure what they really wanted to
461 * detect. Rather than trump anything, show both possibilities.
462 * We can exclude checking the buried obj chain for boulders below.
464 sym = class ? def_oc_syms[class] : 0;
465 if (sym && iflags.bouldersym && sym == iflags.bouldersym)
466 boulder = ROCK_CLASS;
468 if (Hallucination || (Confusion && class == SCROLL_CLASS))
469 strcpy(stuff, something);
470 else
471 strcpy(stuff, class ? oclass_names[class] : "objects");
472 if (boulder && class != ROCK_CLASS) strcat(stuff, " and/or large stones");
474 if (do_dknown) for(obj = invent; obj; obj = obj->nobj) {
475 if (guaranteed || (likely && rn2(2)) || !rn2(3)) do_dknown_of(obj);
478 for (obj = fobj; obj; obj = obj->nobj) {
479 if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) {
480 if (obj->ox == u.ux && obj->oy == u.uy) ctu++;
481 else ct++;
483 if (do_dknown && (guaranteed || (likely && rn2(2)) || !rn2(3)) ) do_dknown_of(obj);
486 for (obj = level.buriedobjlist; obj; obj = obj->nobj) {
487 if (!class || o_in(obj, class)) {
488 if (obj->ox == u.ux && obj->oy == u.uy) ctu++;
489 else ct++;
491 if (do_dknown && (guaranteed || (likely && rn2(2)) || !rn2(3)) ) do_dknown_of(obj);
494 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
495 if (DEADMONSTER(mtmp)) continue;
496 for (obj = mtmp->minvent; obj; obj = obj->nobj) {
497 if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) ct++;
498 if (do_dknown && (guaranteed || (likely && rn2(2)) || !rn2(3)) ) do_dknown_of(obj);
500 if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT &&
501 (!class || class == objects[mtmp->mappearance].oc_class)) ||
502 #ifndef GOLDOBJ
503 (mtmp->mgold && (!class || class == COIN_CLASS))) {
504 #else
505 (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) {
506 #endif
507 ct++;
508 break;
512 if (!clear_stale_map(!class ? ALL_CLASSES : class, 0) && !ct) {
513 if (!ctu) {
514 if (detector)
515 strange_feeling(detector, "You feel a lack of something.");
516 return 1;
519 You("sense %s nearby.", stuff);
520 return 0;
523 cls();
525 u.uinwater = 0;
527 * Map all buried objects first.
529 for (obj = level.buriedobjlist; obj; obj = obj->nobj)
530 if (!class || (otmp = o_in(obj, class))) {
531 if (class) {
532 if (otmp != obj) {
533 otmp->ox = obj->ox;
534 otmp->oy = obj->oy;
536 if ((guaranteed || (likely && rn2(2)) || !rn2(3)) && !(stupiddetect && isok(obj->ox, obj->oy) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, obj->ox, obj->oy) > 1226) ) ) map_object(otmp, 1);
537 } else
538 if ((guaranteed || (likely && rn2(2)) || !rn2(3)) && !(stupiddetect && isok(obj->ox, obj->oy) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, obj->ox, obj->oy) > 1226) ) ) map_object(obj, 1);
541 * If we are mapping all objects, map only the top object of a pile or
542 * the first object in a monster's inventory. Otherwise, go looking
543 * for a matching object class and display the first one encountered
544 * at each location.
546 * Objects on the floor override buried objects.
548 for (x = 1; x < COLNO; x++)
549 for (y = 0; y < ROWNO; y++)
550 for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
551 if ((!class && !boulder) ||
552 (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) {
553 if (class || boulder) {
554 if (otmp != obj) {
555 otmp->ox = obj->ox;
556 otmp->oy = obj->oy;
558 if ((guaranteed || (likely && rn2(2)) || !rn2(3)) && !(stupiddetect && isok(obj->ox, obj->oy) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, obj->ox, obj->oy) > 1226) ) ) map_object(otmp, 1);
559 } else
560 if ((guaranteed || (likely && rn2(2)) || !rn2(3)) && !(stupiddetect && isok(obj->ox, obj->oy) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, obj->ox, obj->oy) > 1226) ) ) map_object(obj, 1);
561 break;
564 /* Objects in the monster's inventory override floor objects. */
565 for (mtmp = fmon ; mtmp ; mtmp = mtmp->nmon) {
566 if (DEADMONSTER(mtmp)) continue;
567 for (obj = mtmp->minvent; obj; obj = obj->nobj)
568 if ((!class && !boulder) ||
569 (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) {
570 if (!class && !boulder) otmp = obj;
571 otmp->ox = mtmp->mx; /* at monster location */
572 otmp->oy = mtmp->my;
573 if ((guaranteed || (likely && rn2(2)) || !rn2(3)) && !(stupiddetect && isok(obj->ox, obj->oy) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, obj->ox, obj->oy) > 1226) ) ) map_object(otmp, 1);
574 break;
576 /* Allow a mimic to override the detected objects it is carrying. */
577 if (is_cursed && mtmp->m_ap_type == M_AP_OBJECT &&
578 (!class || class == objects[mtmp->mappearance].oc_class)) {
579 struct obj temp;
581 temp.otyp = mtmp->mappearance; /* needed for obj_to_glyph() */
582 temp.ox = mtmp->mx;
583 temp.oy = mtmp->my;
584 temp.corpsenm = PM_TENGU; /* if mimicing a corpse */
585 map_object(&temp, 1);
586 #ifndef GOLDOBJ
587 } else if (mtmp->mgold && (!class || class == COIN_CLASS)) {
588 #else
589 } else if (findgold(mtmp->minvent) && (!class || class == COIN_CLASS)) {
590 #endif
591 struct obj gold;
593 gold.otyp = GOLD_PIECE;
594 gold.ox = mtmp->mx;
595 gold.oy = mtmp->my;
596 if ((guaranteed || (likely && rn2(2)) || !rn2(3)) && !(stupiddetect && isok(mtmp->mx, mtmp->my) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, mtmp->mx, mtmp->my) > 1226) ) ) map_object(&gold, 1);
600 newsym(u.ux,u.uy);
601 You("detect the %s of %s.", ct ? "presence" : "absence", stuff);
602 display_nhwindow(WIN_MAP, TRUE);
604 * What are we going to do when the hero does an object detect while blind
605 * and the detected object covers a known pool?
607 docrt(); /* this will correctly reset vision */
609 u.uinwater = uw;
610 if (Underwater && !Swimming) under_water(2);
611 if (u.uburied) under_ground(2);
612 return 0;
615 /* function by Amy: reveal "tileamount" random tiles on the current level */
616 void
617 displayrandomtiles(tileamount)
618 int tileamount;
620 int zx, zy;
622 if (tileamount > 100000) tileamount = 100000; /* sanity check */
624 if (tileamount < 0) {
625 impossible("displayrandomtiles called with wrong argument %d?", tileamount);
626 return;
629 while (tileamount > 0) {
630 tileamount--;
632 zx = rn2(COLNO);
633 zy = rn2(ROWNO);
635 if (isok(zx, zy)) show_map_spot(zx, zy);
637 pline("Part of the map has been revealed!");
641 * Used for artifact effects. Returns:
643 * 1 - nothing was detected
644 * 0 - something was detected
647 artifact_detect(detector)
648 struct obj *detector; /* object doing the detecting */
650 register int x, y;
651 char stuff[BUFSZ];
652 int is_cursed = (detector && detector->cursed);
653 int do_dknown = (detector && (detector->oclass == POTION_CLASS ||
654 detector->oclass == SPBOOK_CLASS ||
655 detector->oartifact) &&
656 detector->blessed);
657 int ct = 0;
658 register struct obj *obj, *otmp = (struct obj *)0;
659 register struct monst *mtmp;
660 int uw = u.uinwater;
662 if (DetectionMethodsDontWork) {
663 if (detector) strange_feeling(detector, "Huh.");
664 return 1;
667 if (is_cursed){ /* Possible false negative */
668 strange_feeling(detector, "You feel a lack of something.");
669 return 1;
672 if (Hallucination)
673 strcpy(stuff, something);
674 else
675 strcpy(stuff, "artifacts");
677 if (do_dknown) for(obj = invent; obj; obj = obj->nobj) do_dknown_of(obj);
679 for (obj = fobj; obj; obj = obj->nobj) {
680 if (obj && obj->oartifact) {
681 if (obj->ox != u.ux || obj->oy != u.uy) ct++;
683 if (do_dknown) do_dknown_of(obj);
686 for (obj = level.buriedobjlist; obj; obj = obj->nobj) {
687 if (obj && obj->oartifact) {
688 if (obj->ox != u.ux || obj->oy != u.uy) ct++;
690 if (do_dknown) do_dknown_of(obj);
693 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
694 if (DEADMONSTER(mtmp)) continue;
695 for (obj = mtmp->minvent; obj; obj = obj->nobj) {
696 if (obj && obj->oartifact) ct++;
697 if (do_dknown) do_dknown_of(obj);
701 if (!clear_stale_map(ALL_CLASSES, 0) && !ct) {
702 strange_feeling(detector, "You feel a lack of something.");
703 return 1;
706 cls();
708 u.uinwater = 0;
710 * Map all buried objects first.
712 for (obj = level.buriedobjlist; obj; obj = obj->nobj)
713 if (obj && obj->oartifact) {
714 map_object(obj, 1);
717 * If we are mapping all objects, map only the top object of a pile or
718 * the first object in a monster's inventory. Otherwise, go looking
719 * for a matching object class and display the first one encountered
720 * at each location.
722 * Objects on the floor override buried objects.
724 for (x = 1; x < COLNO; x++)
725 for (y = 0; y < ROWNO; y++)
726 for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
727 if (obj && obj->oartifact) {
728 map_object(obj, 1);
729 break;
731 /* Objects in the monster's inventory override floor objects. */
732 for (mtmp = fmon ; mtmp ; mtmp = mtmp->nmon) {
733 if (DEADMONSTER(mtmp)) continue;
734 for (obj = mtmp->minvent; obj; obj = obj->nobj)
735 if (obj && obj->oartifact) {
736 map_object(obj, 1);
737 break;
741 newsym(u.ux,u.uy);
742 You("detect the %s of %s.", ct ? "presence" : "absence", stuff);
743 display_nhwindow(WIN_MAP, TRUE);
745 * What are we going to do when the hero does an object detect while blind
746 * and the detected object covers a known pool?
748 docrt(); /* this will correctly reset vision */
750 u.uinwater = uw;
751 if (Underwater && !Swimming) under_water(2);
752 if (u.uburied) under_ground(2);
753 return 0;
756 void
757 water_detect()
760 register int zx, zy;
761 int detectamount = 0;
763 if (DetectionMethodsDontWork) return;
765 for (zx = 1; zx < COLNO; zx++)
766 for (zy = 0; zy < ROWNO; zy++)
767 if (levl[zx][zy].typ == WATER || levl[zx][zy].typ == POOL || levl[zx][zy].typ == CRYSTALWATER || levl[zx][zy].typ == WATERTUNNEL || levl[zx][zy].typ == WELL || levl[zx][zy].typ == POISONEDWELL || levl[zx][zy].typ == RAINCLOUD || levl[zx][zy].typ == MOAT || levl[zx][zy].typ == FOUNTAIN || levl[zx][zy].typ == SINK || levl[zx][zy].typ == TOILET) {
768 show_map_spot(zx, zy);
769 detectamount++;
772 if (detectamount) pline("You detect some water.");
773 else pline("This dungeon level does not seem watery at all.");
775 flush_screen(1); /* flush temp screen */
776 display_nhwindow(WIN_MAP, TRUE); /* wait */
777 docrt();
781 void
782 water_detectX() /* for the spell, which is meant to be weaker than the scroll --Amy */
785 register int zx, zy;
786 int detectamount = 0;
788 if (DetectionMethodsDontWork) return;
790 for (zx = 1; zx < COLNO; zx++)
791 for (zy = 0; zy < ROWNO; zy++)
792 if ((levl[zx][zy].typ == WATER || levl[zx][zy].typ == POOL || levl[zx][zy].typ == CRYSTALWATER || levl[zx][zy].typ == WATERTUNNEL || levl[zx][zy].typ == WELL || levl[zx][zy].typ == POISONEDWELL || levl[zx][zy].typ == RAINCLOUD || levl[zx][zy].typ == MOAT || levl[zx][zy].typ == FOUNTAIN || levl[zx][zy].typ == SINK || levl[zx][zy].typ == TOILET) && rn2(2)) {
793 if (!(isok(zx, zy) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, zx, zy) > 901) ) ) show_map_spot(zx, zy);
794 detectamount++;
797 if (detectamount) pline("You detect some water.");
798 else pline("This dungeon level does not seem watery at all.");
800 flush_screen(1); /* flush temp screen */
801 display_nhwindow(WIN_MAP, TRUE); /* wait */
802 docrt();
807 * Used by: crystal balls, potions, fountains
809 * Returns 1 if nothing was detected.
810 * Returns 0 if something was detected.
813 monster_detect(otmp, mclass)
814 register struct obj *otmp; /* detecting object (if any) */
815 int mclass; /* monster class, 0 for all */
817 register struct monst *mtmp;
818 int mcnt = 0;
820 if (DetectionMethodsDontWork) {
821 if (otmp) strange_feeling(otmp, "Huh.");
822 return 1;
825 /* Note: This used to just check fmon for a non-zero value
826 * but in versions since 3.3.0 fmon can test TRUE due to the
827 * presence of dmons, so we have to find at least one
828 * with positive hit-points to know for sure.
830 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
831 if (!DEADMONSTER(mtmp)) {
832 mcnt++;
833 break;
836 if (!mcnt) {
837 if (otmp)
838 strange_feeling(otmp, FunnyHallu ?
839 "You get the heebie jeebies." :
840 "You feel threatened.");
841 return 1;
842 } else {
843 boolean woken = FALSE;
845 cls();
846 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
847 if (DEADMONSTER(mtmp)) continue;
848 if (!mclass || mtmp->data->mlet == mclass ||
849 (mtmp->data == &mons[PM_LONG_WORM] && mclass == S_WORM_TAIL))
850 if ((mtmp->mx > 0) && !(otmp && otmp->oclass == SPBOOK_CLASS && (mtmp && isok(u.ux, u.uy) && isok(mtmp->mx, mtmp->my) && (dist2(u.ux,u.uy,mtmp->mx,mtmp->my) > 101) ) ) && ( !(otmp && otmp->oclass == SPBOOK_CLASS) || rn2(2) ) ) {
851 if (mclass && def_monsyms[mclass] == ' ')
852 show_glyph(mtmp->mx,mtmp->my,
853 detected_mon_to_glyph(mtmp));
854 else
855 show_glyph(mtmp->mx,mtmp->my,mon_to_glyph(mtmp));
856 /* don't be stingy - display entire worm */
857 if (mtmp->data == &mons[PM_LONG_WORM]) detect_wsegs(mtmp,0);
859 if (otmp && otmp->cursed &&
860 (mtmp->msleeping || !mtmp->mcanmove)) {
861 mtmp->msleeping = mtmp->mfrozen = mtmp->masleep = 0;
862 mtmp->mcanmove = 1;
863 woken = TRUE;
866 display_self();
867 You("sense the presence of monsters.");
868 if (woken)
869 pline(FunnyHallu ? "They're after you! Now you know why you were always paranoid - they REALLY want to eat you alive!" : "Monsters sense the presence of you.");
870 display_nhwindow(WIN_MAP, TRUE);
871 docrt();
872 if (Underwater && !Swimming) under_water(2);
873 if (u.uburied) under_ground(2);
875 return 0;
878 STATIC_OVL void
879 sense_trap(trap, x, y, src_cursed)
880 struct trap *trap;
881 xchar x, y;
882 int src_cursed;
884 if (Hallucination || src_cursed) {
885 struct obj obj; /* fake object */
886 if (trap) {
887 obj.ox = trap->tx;
888 obj.oy = trap->ty;
889 } else {
890 obj.ox = x;
891 obj.oy = y;
893 obj.otyp = (src_cursed) ? GOLD_PIECE : random_object();
894 obj.corpsenm = random_monster(); /* if otyp == CORPSE */
895 map_object(&obj,1);
896 } else if (trap && !trap->hiddentrap) {
897 map_trap(trap,1);
898 trap->tseen = 1;
899 } else {
900 struct trap temp_trap; /* fake trap */
901 temp_trap.tx = x;
902 temp_trap.ty = y;
903 temp_trap.ttyp = BEAR_TRAP; /* some kind of trap */
904 map_trap(&temp_trap,1);
909 /* the detections are pulled out so they can */
910 /* also be used in the crystal ball routine */
911 /* returns 1 if nothing was detected */
912 /* returns 0 if something was detected */
914 trap_detect(sobj)
915 register struct obj *sobj;
916 /* sobj is null if crystal ball, *scroll if gold detection scroll */
918 register struct trap *ttmp;
919 register struct obj *obj;
920 register int door;
921 int uw = u.uinwater;
922 boolean found = FALSE;
923 int x, y;
925 if (DetectionMethodsDontWork) {
926 if (sobj) strange_feeling(sobj, "Huh.");
927 return 1;
930 for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
931 if (ttmp->tx != u.ux || ttmp->ty != u.uy)
932 goto outtrapmap;
933 else found = TRUE;
935 for (obj = fobj; obj; obj = obj->nobj) {
936 if ((obj->otyp==LARGE_BOX || obj->otyp==LEAD_BOX || obj->otyp==TOP_BOX || obj->otyp==TREASURE_CHEST || obj->otyp==LOOT_CHEST || obj->otyp==CHEST || obj->otyp==NANO_CHEST || obj->otyp==LARGE_BOX_OF_DIGESTION || obj->otyp==CHEST_OF_HOLDING) && obj->otrapped) {
937 if (obj->ox != u.ux || obj->oy != u.uy)
938 goto outtrapmap;
939 else found = TRUE;
942 for (door = 0; door < doorindex; door++) {
943 x = doors[door].x;
944 y = doors[door].y;
945 if (levl[x][y].doormask & D_TRAPPED) {
946 if (x != u.ux || y != u.uy)
947 goto outtrapmap;
948 else found = TRUE;
951 if (!found) {
952 char buf[42];
953 sprintf(buf, "Your %s stop itching.", makeplural(body_part(TOE)));
954 strange_feeling(sobj,buf);
955 return(1);
957 /* traps exist, but only under me - no separate display required */
958 Your("%s itch.", makeplural(body_part(TOE)));
959 return(0);
960 outtrapmap:
961 cls();
963 /* nerf by Amy - only detect 50% of all traps, because trap detection is very powerful if you think about it... */
964 u.uinwater = 0;
965 for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
966 if (rn2(2) && (ttmp->trapdiff < rnd(150)) && (!isfriday || (ttmp->trapdiff < rnd(150))) && (ttmp->trapdiff < rnd(150)) ) sense_trap(ttmp, 0, 0, sobj && sobj->cursed);
968 for (obj = fobj; obj; obj = obj->nobj)
969 if ((obj->otyp==LARGE_BOX || obj->otyp==LEAD_BOX || obj->otyp==TOP_BOX || obj->otyp==TREASURE_CHEST || obj->otyp==LOOT_CHEST || obj->otyp==CHEST || obj->otyp==NANO_CHEST || obj->otyp==LARGE_BOX_OF_DIGESTION || obj->otyp==CHEST_OF_HOLDING) && obj->otrapped)
970 if (rn2(2)) sense_trap((struct trap *)0, obj->ox, obj->oy, sobj && sobj->cursed);
972 for (door = 0; door < doorindex; door++) {
973 x = doors[door].x;
974 y = doors[door].y;
975 if (levl[x][y].doormask & D_TRAPPED)
976 if (rn2(2)) sense_trap((struct trap *)0, x, y, sobj && sobj->cursed);
979 newsym(u.ux,u.uy);
980 You_feel("%s.", sobj && sobj->cursed ? "very greedy" : "entrapped");
981 display_nhwindow(WIN_MAP, TRUE);
982 docrt();
983 u.uinwater = uw;
984 if (Underwater && !Swimming) under_water(2);
985 if (u.uburied) under_ground(2);
986 return(0);
989 /* weaker trap detection, from spell; currently only the entrapping spell uses this --Amy */
991 trap_detectX(sobj)
992 register struct obj *sobj;
993 /* sobj is null if crystal ball, *scroll if gold detection scroll */
995 register struct trap *ttmp;
996 register struct obj *obj;
997 register int door;
998 int uw = u.uinwater;
999 boolean found = FALSE;
1000 int x, y;
1002 if (DetectionMethodsDontWork) {
1003 if (sobj) strange_feeling(sobj, "Huh.");
1004 return 1;
1007 for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
1008 if (ttmp->tx != u.ux || ttmp->ty != u.uy)
1009 goto outtrapmap;
1010 else found = TRUE;
1012 for (obj = fobj; obj; obj = obj->nobj) {
1013 if ((obj->otyp==LARGE_BOX || obj->otyp==LEAD_BOX || obj->otyp==TOP_BOX || obj->otyp==CHEST || obj->otyp==NANO_CHEST || obj->otyp==TREASURE_CHEST || obj->otyp==LOOT_CHEST || obj->otyp==LARGE_BOX_OF_DIGESTION || obj->otyp==CHEST_OF_HOLDING) && obj->otrapped) {
1014 if (obj->ox != u.ux || obj->oy != u.uy)
1015 goto outtrapmap;
1016 else found = TRUE;
1019 for (door = 0; door < doorindex; door++) {
1020 x = doors[door].x;
1021 y = doors[door].y;
1022 if (levl[x][y].doormask & D_TRAPPED) {
1023 if (x != u.ux || y != u.uy)
1024 goto outtrapmap;
1025 else found = TRUE;
1028 if (!found) {
1029 char buf[42];
1030 sprintf(buf, "Your %s stop itching.", makeplural(body_part(TOE)));
1031 strange_feeling(sobj,buf);
1032 return(1);
1034 /* traps exist, but only under me - no separate display required */
1035 Your("%s itch.", makeplural(body_part(TOE)));
1036 return(0);
1037 outtrapmap:
1038 cls();
1040 /* nerf by Amy - only detect 50% of all traps, because trap detection is very powerful if you think about it... */
1041 u.uinwater = 0;
1042 for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
1043 if (!rn2(4) && !(isok(ttmp->tx, ttmp->ty) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, ttmp->tx, ttmp->ty) > 401) ) && (ttmp->trapdiff < rnd(150)) && (!isfriday || (ttmp->trapdiff < rnd(150))) && (ttmp->trapdiff < rnd(150)) ) sense_trap(ttmp, 0, 0, sobj && sobj->cursed);
1045 for (obj = fobj; obj; obj = obj->nobj)
1046 if ((obj->otyp==LARGE_BOX || obj->otyp==LEAD_BOX || obj->otyp==TOP_BOX || obj->otyp==CHEST || obj->otyp==NANO_CHEST || obj->otyp==TREASURE_CHEST || obj->otyp==LOOT_CHEST || obj->otyp==LARGE_BOX_OF_DIGESTION || obj->otyp==CHEST_OF_HOLDING) && obj->otrapped)
1047 if (!rn2(4) && !(isok(obj->ox, obj->oy) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, obj->ox, obj->oy) > 401) ))
1048 sense_trap((struct trap *)0, obj->ox, obj->oy, sobj && sobj->cursed);
1050 for (door = 0; door < doorindex; door++) {
1051 x = doors[door].x;
1052 y = doors[door].y;
1053 if (levl[x][y].doormask & D_TRAPPED)
1054 if (!rn2(4) && !(isok(x, y) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, x, y) > 401) )) sense_trap((struct trap *)0, x, y, sobj && sobj->cursed);
1057 newsym(u.ux,u.uy);
1058 You_feel("%s.", sobj && sobj->cursed ? "very greedy" : "entrapped");
1059 display_nhwindow(WIN_MAP, TRUE);
1060 docrt();
1061 u.uinwater = uw;
1062 if (Underwater && !Swimming) under_water(2);
1063 if (u.uburied) under_ground(2);
1064 return(0);
1067 const char *
1068 level_distance(where)
1069 d_level *where;
1071 register schar ll = depth(&u.uz) - depth(where);
1072 register boolean indun = (u.uz.dnum == where->dnum);
1074 if (ll < 0) {
1075 if (ll < (-8 - rn2(3))) {
1076 if (!indun) return "far away";
1077 else return "far below";
1079 else if (ll < -1) {
1080 if (!indun) return "away below you";
1081 else return "below you";
1083 else
1084 if (!indun) return "in the distance";
1085 else return "just below";
1086 } else if (ll > 0) {
1087 if (ll > (8 + rn2(3))) {
1088 if (!indun) return "far away";
1089 else return "far above";
1091 else if (ll > 1) {
1092 if (!indun) return "away above you";
1093 else return "above you";
1095 else
1096 if (!indun) return "in the distance";
1097 else return "just above";
1098 } else
1099 if (!indun) return "in the distance";
1100 else return "near you";
1103 static const struct {
1104 const char *what;
1105 d_level *where;
1106 } level_detects[] = {
1107 { "Delphi", &oracle_level },
1108 { "Medusa's lair", &medusa_level },
1109 { "a castle", &stronghold_level },
1110 { "the Wizard of Yendor's tower", &wiz1_level },
1113 boolean
1114 use_crystal_ball(obj)
1115 struct obj *obj;
1117 char ch;
1118 int oops;
1120 if (Blind) {
1121 pline("Too bad you can't see %s.", the(xname(obj)));
1122 return 0;
1124 oops = (rnd(20) > ACURR(A_INT) || obj->cursed);
1125 if (oops && (obj->spe > 0)) {
1126 switch (rnd((obj->oartifact && rn2(100)) ? 4 : 5)) {
1127 case 1 : pline("%s too much to comprehend!", Tobjnam(obj, "are"));
1128 break;
1129 case 2 : pline("%s you!", Tobjnam(obj, "confuse"));
1130 make_confused(HConfusion + rnd(50),FALSE);
1131 break;
1132 case 3 : if (!resists_blnd(&youmonst)) {
1133 pline("%s your vision!", Tobjnam(obj, "damage"));
1134 make_blinded(Blinded + rnd(50),FALSE);
1135 if (!Blind) Your("%s", vision_clears);
1136 } else {
1137 pline("%s your vision.", Tobjnam(obj, "assault"));
1138 You("are unaffected!");
1140 break;
1141 case 4 : pline("%s your mind!", Tobjnam(obj, "zap"));
1142 (void) make_hallucinated(HHallucination + rnd(50),FALSE,0L);
1143 break;
1144 case 5 : pline("%s!", Tobjnam(obj, "explode"));
1145 useup(obj);
1146 obj = 0; /* it's gone */
1147 losehp(rnd(30), "exploding crystal ball", KILLED_BY_AN);
1148 return 1;
1149 break;
1151 if (obj) consume_obj_charge(obj, TRUE);
1152 return 0;
1155 if (Hallucination) {
1156 if (!obj->spe) {
1157 pline("All you see is funky %s haze.", hcolor((char *)0));
1158 } else {
1159 switch(rnd(6)) {
1160 case 1 : You("grok some groovy globs of incandescent lava.");
1161 break;
1162 case 2 : pline("Whoa! Psychedelic colors, %s!",
1163 poly_gender() == 1 ? "babe" : "dude");
1164 break;
1165 case 3 : pline_The("crystal pulses with sinister %s light!",
1166 hcolor((char *)0));
1167 break;
1168 case 4 : You("see goldfish swimming above fluorescent rocks.");
1169 break;
1170 case 5 : You("see tiny snowflakes spinning around a miniature farmhouse.");
1171 break;
1172 default: pline("Oh wow... like a kaleidoscope!");
1173 break;
1175 consume_obj_charge(obj, TRUE);
1177 return 0;
1180 /* read a single character */
1181 if (flags.verbose) You("may look for an object or monster symbol.");
1182 ch = yn_function("What do you look for?", (char *)0, '\0');
1183 /* Don't filter out ' ' here; it has a use */
1184 if ((ch != def_monsyms[S_GHOST]) && index(quitchars,ch)) {
1185 if (flags.verbose) pline("%s", Never_mind);
1186 if (FailureEffects || u.uprops[FAILURE_EFFECTS].extrinsic || have_failurestone()) {
1187 pline("Oh wait, actually I do mind...");
1188 badeffect();
1190 return 0;
1192 You("peer into %s...", the(xname(obj)));
1193 nomul(-rnd(10), "gazing into a crystal ball", TRUE);
1194 nomovemsg = "";
1195 if (obj->spe <= 0)
1196 pline_The("vision is unclear.");
1197 else {
1198 int class;
1199 int ret = 0;
1201 makeknown(CRYSTAL_BALL);
1202 consume_obj_charge(obj, TRUE);
1204 /* special case: accept ']' as synonym for mimic
1205 * we have to do this before the def_char_to_objclass check
1207 if (ch == DEF_MIMIC_DEF) ch = DEF_MIMIC;
1209 if ((class = def_char_to_objclass(ch)) != MAXOCLASSES)
1210 ret = object_detect((struct obj *)0, class);
1211 else if ((class = def_char_to_monclass(ch)) != MAXMCLASSES)
1212 ret = monster_detect((struct obj *)0, class);
1213 else if (iflags.bouldersym && (ch == iflags.bouldersym))
1214 ret = object_detect((struct obj *)0, ROCK_CLASS);
1215 else switch(ch) {
1216 case '^':
1217 ret = trap_detect((struct obj *)0);
1218 break;
1219 default:
1221 int i = rn2(SIZE(level_detects));
1222 You("see %s, %s.",
1223 level_detects[i].what,
1224 level_distance(level_detects[i].where));
1226 ret = 0;
1227 break;
1230 if (ret) {
1231 if (!rn2(100)) /* make them nervous */
1232 You("see the Wizard of Yendor gazing out at you.");
1233 else pline_The("vision is unclear.");
1236 return 0;
1239 STATIC_OVL void
1240 show_map_spot(x, y)
1241 register int x, y;
1243 register struct rm *lev;
1245 if (Confusion && rn2(7)) return;
1247 if (isfriday && !rn2(10)) return;
1249 lev = &levl[x][y];
1251 lev->seenv = SVALL;
1253 /* Secret corridors are found, but not secret doors. */
1254 if (lev->typ == SCORR) {
1255 lev->typ = CORR;
1256 unblock_point(x,y);
1259 /* if we don't remember an object or trap there, map it */
1260 #ifdef DISPLAY_LAYERS
1261 if (!lev->mem_obj && !lev->mem_trap) {
1262 #else
1263 if (lev->typ == ROOM ?
1264 (glyph_is_cmap(lev->glyph) && !glyph_is_trap(lev->glyph) &&
1265 glyph_to_cmap(lev->glyph) != ROOM) :
1266 (!glyph_is_object(lev->glyph) && !glyph_is_trap(lev->glyph))) {
1267 #endif
1268 if (level.flags.hero_memory) {
1269 magic_map_background(x,y,0);
1270 newsym(x,y); /* show it, if not blocked */
1271 } else {
1272 magic_map_background(x,y,1); /* display it */
1277 STATIC_OVL void
1278 show_map_spotX(x, y)
1279 register int x, y;
1281 register struct rm *lev;
1283 if (rn2(10)) return;
1285 if (isfriday && !rn2(10)) return;
1287 lev = &levl[x][y];
1289 lev->seenv = SVALL;
1291 /* Secret corridors are found, but not secret doors. */
1292 if (lev->typ == SCORR) {
1293 lev->typ = CORR;
1294 unblock_point(x,y);
1297 /* if we don't remember an object or trap there, map it */
1298 #ifdef DISPLAY_LAYERS
1299 if (!lev->mem_obj && !lev->mem_trap) {
1300 #else
1301 if (lev->typ == ROOM ?
1302 (glyph_is_cmap(lev->glyph) && !glyph_is_trap(lev->glyph) &&
1303 glyph_to_cmap(lev->glyph) != ROOM) :
1304 (!glyph_is_object(lev->glyph) && !glyph_is_trap(lev->glyph))) {
1305 #endif
1306 if (level.flags.hero_memory) {
1307 magic_map_background(x,y,0);
1308 newsym(x,y); /* show it, if not blocked */
1309 } else {
1310 magic_map_background(x,y,1); /* display it */
1315 void
1316 do_mapping()
1318 register int zx, zy;
1319 int uw = u.uinwater;
1321 if (DetectionMethodsDontWork) return;
1323 u.uinwater = 0;
1324 for (zx = 1; zx < COLNO; zx++)
1325 for (zy = 0; zy < ROWNO; zy++)
1326 show_map_spot(zx, zy);
1327 exercise(A_WIS, TRUE);
1328 u.uinwater = uw;
1329 if (!level.flags.hero_memory || Underwater) {
1330 flush_screen(1); /* flush temp screen */
1331 display_nhwindow(WIN_MAP, TRUE); /* wait */
1332 docrt();
1336 void
1337 do_mappingX() /* magic mapping spell and roadmap cloak - they don't reveal as much info --Amy */
1339 register int zx, zy;
1340 int uw = u.uinwater;
1342 if (DetectionMethodsDontWork) return;
1344 u.uinwater = 0;
1345 for (zx = 1; zx < COLNO; zx++)
1346 for (zy = 0; zy < ROWNO; zy++)
1347 if (!(isok(zx, zy) && isok(u.ux, u.uy) && (dist2(u.ux, u.uy, zx, zy) > 626) ) ) show_map_spotX(zx, zy);
1348 exercise(A_WIS, TRUE);
1349 u.uinwater = uw;
1350 if (!level.flags.hero_memory || Underwater) {
1351 flush_screen(1); /* flush temp screen */
1352 display_nhwindow(WIN_MAP, TRUE); /* wait */
1353 docrt();
1357 void
1358 do_mappingY()
1360 register int zx, zy;
1361 int uw = u.uinwater;
1363 if (DetectionMethodsDontWork) return;
1365 u.uinwater = 0;
1366 for (zx = 1; zx < COLNO; zx++)
1367 for (zy = 0; zy < ROWNO; zy++)
1368 if (rn2(10)) show_map_spot(zx, zy);
1369 exercise(A_WIS, TRUE);
1370 u.uinwater = uw;
1371 if (!level.flags.hero_memory || Underwater) {
1372 flush_screen(1); /* flush temp screen */
1373 display_nhwindow(WIN_MAP, TRUE); /* wait */
1374 docrt();
1378 void
1379 do_mappingZ()
1381 register int zx, zy;
1382 int uw = u.uinwater;
1384 if (DetectionMethodsDontWork) return;
1386 u.uinwater = 0;
1387 for (zx = 1; zx < COLNO; zx++)
1388 for (zy = 0; zy < ROWNO; zy++)
1389 if (rn2(2)) show_map_spot(zx, zy);
1390 exercise(A_WIS, TRUE);
1391 u.uinwater = uw;
1392 if (!level.flags.hero_memory || Underwater) {
1393 flush_screen(1); /* flush temp screen */
1394 display_nhwindow(WIN_MAP, TRUE); /* wait */
1395 docrt();
1399 void
1400 do_vicinity_map()
1403 if (DetectionMethodsDontWork) return;
1404 if (level.flags.nommap) {
1405 pline("Something blocks your clairvoyance!");
1406 return;
1409 register int zx, zy;
1410 int lo_y = (u.uy-6 < 0 ? 0 : u.uy-6),
1411 hi_y = (u.uy+7 > ROWNO ? ROWNO : u.uy+7),
1412 lo_x = (u.ux-6 < 1 ? 1 : u.ux-6), /* avoid column 0 */
1413 hi_x = (u.ux+7 > COLNO ? COLNO : u.ux+7);
1415 for (zx = lo_x; zx < hi_x; zx++)
1416 for (zy = lo_y; zy < hi_y; zy++)
1417 show_map_spot(zx, zy);
1419 if (!level.flags.hero_memory || Underwater) {
1420 flush_screen(1); /* flush temp screen */
1421 display_nhwindow(WIN_MAP, TRUE); /* wait */
1422 docrt();
1426 void
1427 do_vicinity_mapX()
1430 if (DetectionMethodsDontWork) return;
1431 if (level.flags.nommap) {
1432 pline("Something blocks your clairvoyance!");
1433 return;
1436 register int zx, zy;
1437 int lo_y = (u.uy-4 < 0 ? 0 : u.uy-4),
1438 hi_y = (u.uy+5 > ROWNO ? ROWNO : u.uy+5),
1439 lo_x = (u.ux-4 < 1 ? 1 : u.ux-4), /* avoid column 0 */
1440 hi_x = (u.ux+5 > COLNO ? COLNO : u.ux+5);
1442 for (zx = lo_x; zx < hi_x; zx++)
1443 for (zy = lo_y; zy < hi_y; zy++)
1444 if (!rn2(5)) show_map_spot(zx, zy);
1446 if (!level.flags.hero_memory || Underwater) {
1447 flush_screen(1); /* flush temp screen */
1448 display_nhwindow(WIN_MAP, TRUE); /* wait */
1449 docrt();
1453 /* convert a secret door into a normal door */
1454 void
1455 cvt_sdoor_to_door(lev)
1456 struct rm *lev;
1458 int newmask = lev->doormask & ~WM_MASK;
1460 #ifdef REINCARNATION
1461 if (Is_rogue_level(&u.uz))
1462 /* rogue didn't have doors, only doorways */
1463 newmask = D_NODOOR;
1464 else
1465 #endif
1466 /* newly exposed door is closed */
1467 if (!(newmask & D_LOCKED)) newmask |= D_CLOSED;
1469 lev->typ = DOOR;
1470 lev->doormask = newmask;
1473 STATIC_PTR void
1474 findone(zx,zy,num)
1475 int zx,zy;
1476 void * num;
1478 register struct trap *ttmp;
1479 register struct monst *mtmp;
1481 int trapfindchance = 150;
1483 if (!(PlayerCannotUseSkills)) {
1484 switch (P_SKILL(P_SEARCHING)) {
1485 default: break;
1486 case P_BASIC: trapfindchance = 160; break;
1487 case P_SKILLED: trapfindchance = 170; break;
1488 case P_EXPERT: trapfindchance = 180; break;
1489 case P_MASTER: trapfindchance = 200; break;
1490 case P_GRAND_MASTER: trapfindchance = 225; break;
1491 case P_SUPREME_MASTER: trapfindchance = 250; break;
1495 trapfindchance += (boost_power_value() * 3);
1497 /* there should be at least some stat that makes it more likely to find a trap! --Amy */
1498 if (ACURR(A_WIS) > 14) trapfindchance += (ACURR(A_WIS) - 14);
1500 if(levl[zx][zy].typ == SDOOR) {
1501 cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */
1502 You("find a secret door!");
1503 u.cnd_searchsecretcount++;
1504 use_skill(P_SEARCHING,1);
1505 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1506 magic_map_background(zx, zy, 0);
1507 newsym(zx, zy);
1508 (*(int*)num)++;
1509 } else if(levl[zx][zy].typ == SCORR) {
1510 levl[zx][zy].typ = CORR;
1511 unblock_point(zx,zy);
1512 You("find a secret passage!");
1513 u.cnd_searchsecretcount++;
1514 use_skill(P_SEARCHING,1);
1515 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1516 magic_map_background(zx, zy, 0);
1517 newsym(zx, zy);
1518 (*(int*)num)++;
1519 } else if ((ttmp = t_at(zx, zy)) != 0) {
1520 if(!ttmp->tseen && !ttmp->hiddentrap && (ttmp->trapdiff < rnd(trapfindchance)) && (!isfriday || (ttmp->trapdiff < rnd(trapfindchance))) && (ttmp->trapdiff < rnd(trapfindchance)) && ttmp->ttyp != STATUE_TRAP && ttmp->ttyp != SATATUE_TRAP) {
1522 if (!ttmp->tdetected && !rn2(3)) {
1523 use_skill(P_SEARCHING,1);
1524 ttmp->tdetected = TRUE;
1527 ttmp->tseen = 1;
1528 newsym(zx,zy);
1529 (*(int*)num)++;
1531 } else if ((mtmp = m_at(zx, zy)) != 0) {
1532 if(mtmp->m_ap_type) {
1533 seemimic(mtmp);
1534 (*(int*)num)++;
1536 if (mtmp->mundetected &&
1537 (is_hider(mtmp->data) || mtmp->egotype_hide || mtmp->egotype_mimic || mtmp->data->mlet == S_EEL)) {
1538 mtmp->mundetected = 0;
1539 newsym(zx, zy);
1540 (*(int*)num)++;
1542 if (!canspotmon(mtmp) && !(mtmp->data->msound == MS_DEEPSTATE) && !(mtmp->egotype_deepstatemember) &&
1543 !memory_is_invisible(zx, zy))
1544 map_invisible(zx, zy);
1545 } else if (memory_is_invisible(zx, zy)) {
1546 unmap_object(zx, zy);
1547 newsym(zx, zy);
1548 (*(int*)num)++;
1552 STATIC_PTR void
1553 findoneX(zx,zy,num)
1554 int zx,zy;
1555 void * num;
1557 register struct trap *ttmp;
1558 register struct monst *mtmp;
1560 int trapfindchance = 150;
1562 if (!(PlayerCannotUseSkills)) {
1563 switch (P_SKILL(P_SEARCHING)) {
1564 default: break;
1565 case P_BASIC: trapfindchance = 160; break;
1566 case P_SKILLED: trapfindchance = 170; break;
1567 case P_EXPERT: trapfindchance = 180; break;
1568 case P_MASTER: trapfindchance = 200; break;
1569 case P_GRAND_MASTER: trapfindchance = 225; break;
1570 case P_SUPREME_MASTER: trapfindchance = 250; break;
1574 trapfindchance += (boost_power_value() * 3);
1576 /* there should be at least some stat that makes it more likely to find a trap! --Amy */
1577 if (ACURR(A_WIS) > 14) trapfindchance += (ACURR(A_WIS) - 14);
1579 if(!rn2(3) && levl[zx][zy].typ == SDOOR) {
1580 cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */
1581 You("find a secret door!");
1582 u.cnd_searchsecretcount++;
1583 use_skill(P_SEARCHING,1);
1584 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1585 magic_map_background(zx, zy, 0);
1586 newsym(zx, zy);
1587 (*(int*)num)++;
1588 } else if(!rn2(3) && levl[zx][zy].typ == SCORR) {
1589 levl[zx][zy].typ = CORR;
1590 unblock_point(zx,zy);
1591 You("find a secret passage!");
1592 u.cnd_searchsecretcount++;
1593 use_skill(P_SEARCHING,1);
1594 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1595 magic_map_background(zx, zy, 0);
1596 newsym(zx, zy);
1597 (*(int*)num)++;
1598 } else if (!rn2(3) && (ttmp = t_at(zx, zy)) != 0) {
1599 if(!ttmp->tseen && !ttmp->hiddentrap && (ttmp->trapdiff < rnd(trapfindchance)) && (!isfriday || (ttmp->trapdiff < rnd(trapfindchance))) && (ttmp->trapdiff < rnd(trapfindchance)) && ttmp->ttyp != STATUE_TRAP && ttmp->ttyp != SATATUE_TRAP) {
1601 if (!ttmp->tdetected && !rn2(3)) {
1602 use_skill(P_SEARCHING,1);
1603 ttmp->tdetected = TRUE;
1606 ttmp->tseen = 1;
1607 newsym(zx,zy);
1608 (*(int*)num)++;
1610 } else if (!rn2(3) && (mtmp = m_at(zx, zy)) != 0) {
1611 if(mtmp->m_ap_type) {
1612 seemimic(mtmp);
1613 (*(int*)num)++;
1615 if (mtmp->mundetected &&
1616 (is_hider(mtmp->data) || mtmp->egotype_hide || mtmp->egotype_mimic || mtmp->data->mlet == S_EEL)) {
1617 mtmp->mundetected = 0;
1618 newsym(zx, zy);
1619 (*(int*)num)++;
1621 if (!canspotmon(mtmp) && !(mtmp->data->msound == MS_DEEPSTATE) && !(mtmp->egotype_deepstatemember) &&
1622 !memory_is_invisible(zx, zy))
1623 map_invisible(zx, zy);
1624 } else if (memory_is_invisible(zx, zy)) {
1625 unmap_object(zx, zy);
1626 newsym(zx, zy);
1627 (*(int*)num)++;
1631 STATIC_PTR void
1632 openone(zx,zy,num)
1633 int zx,zy;
1634 void * num;
1636 register struct trap *ttmp;
1637 register struct obj *otmp;
1639 if(OBJ_AT(zx, zy)) {
1640 for(otmp = level.objects[zx][zy];
1641 otmp; otmp = otmp->nexthere) {
1642 if(Is_box(otmp) && otmp->olocked) {
1643 otmp->olocked = 0;
1644 (*(int*)num)++;
1647 /* let it fall to the next cases. could be on trap. */
1649 if(levl[zx][zy].typ == SDOOR || (levl[zx][zy].typ == DOOR &&
1650 (levl[zx][zy].doormask & (D_CLOSED|D_LOCKED)))) {
1651 if(levl[zx][zy].typ == SDOOR)
1652 cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */
1653 if(levl[zx][zy].doormask & D_TRAPPED) {
1654 if(distu(zx, zy) < 3) b_trapped("door", 0);
1655 else Norep("You %s an explosion!",
1656 cansee(zx, zy) ? "see" :
1657 (flags.soundok ? "hear" :
1658 "feel the shock of"));
1659 wake_nearto(zx, zy, 11*11);
1660 levl[zx][zy].doormask = D_NODOOR;
1661 } else
1662 levl[zx][zy].doormask = D_ISOPEN;
1663 unblock_point(zx, zy);
1664 newsym(zx, zy);
1665 (*(int*)num)++;
1666 } else if(levl[zx][zy].typ == SCORR) {
1667 levl[zx][zy].typ = CORR;
1668 unblock_point(zx, zy);
1669 newsym(zx, zy);
1670 (*(int*)num)++;
1671 } else if ((ttmp = t_at(zx, zy)) != 0) {
1672 if (!ttmp->tseen && !ttmp->hiddentrap && (ttmp->trapdiff < rnd(150)) && (!isfriday || (ttmp->trapdiff < rnd(150))) && (ttmp->trapdiff < rnd(150)) && ttmp->ttyp != STATUE_TRAP && ttmp->ttyp != SATATUE_TRAP) {
1673 ttmp->tseen = 1;
1674 newsym(zx,zy);
1675 (*(int*)num)++;
1677 } else if (find_drawbridge(&zx, &zy)) {
1678 /* make sure it isn't an open drawbridge */
1679 open_drawbridge(zx, zy);
1680 (*(int*)num)++;
1685 findit() /* returns number of things found */
1687 int num = 0;
1689 if(u.uswallow) return(0);
1690 do_clear_area(u.ux, u.uy, BOLT_LIM, findone, (void *) &num);
1691 return(num);
1695 finditX() /* returns number of things found */
1697 int num = 0;
1699 if(u.uswallow) return(0);
1700 do_clear_area(u.ux, u.uy, 4 + rn2(2), findoneX, (void *) &num);
1701 return(num);
1705 openit() /* returns number of things found and opened */
1707 int num = 0;
1709 if(u.uswallow) {
1710 if (is_animal(u.ustuck->data)) {
1711 if (Blind) pline("Its mouth opens!");
1712 else pline("%s opens its mouth!", Monnam(u.ustuck));
1714 expels(u.ustuck, u.ustuck->data, TRUE);
1715 return(-1);
1718 do_clear_area(u.ux, u.uy, BOLT_LIM, openone, (void *) &num);
1719 return(num);
1722 void
1723 find_trap(trap)
1724 struct trap *trap;
1726 int tt = what_trap(trap->ttyp);
1727 boolean cleared = FALSE;
1729 if (trap->hiddentrap) return;
1731 trap->tseen = 1;
1732 exercise(A_WIS, TRUE);
1733 /* if (Blind)*/
1734 feel_location(trap->tx, trap->ty);
1735 /* else*/
1736 if (!Blind) newsym(trap->tx, trap->ty);
1738 #ifdef DISPLAY_LAYERS
1739 if (levl[trap->tx][trap->ty].mem_obj ||
1740 memory_is_invisible(trap->tx, trap->ty)) {
1741 #else
1742 if (levl[trap->tx][trap->ty].glyph != trap_to_glyph(trap)) {
1743 #endif
1744 /* There's too much clutter to see your find otherwise */
1745 cls();
1746 map_trap(trap, 1);
1747 display_self();
1748 cleared = TRUE;
1751 You("find %s.", an(defsyms[trap_to_defsym(tt)].explanation));
1752 u.cnd_searchtrapcount++;
1753 if (!trap->tdetected) {
1754 mightbooststat(A_WIS);
1755 use_skill(P_SEARCHING,1);
1756 trap->tdetected = TRUE;
1759 if (cleared) {
1760 display_nhwindow(WIN_MAP, TRUE); /* wait */
1761 docrt();
1766 dosearch0(aflag)
1767 register int aflag;
1769 #ifdef GCC_BUG
1770 /* some versions of gcc seriously muck up nested loops. if you get strange
1771 crashes while searching in a version compiled with gcc, try putting
1772 #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the
1773 makefile).
1775 volatile xchar x, y;
1776 #else
1777 register xchar x, y;
1778 #endif
1779 register struct trap *trap;
1780 register struct monst *mtmp;
1782 if (AntisearchEffect || u.uprops[ANTISEARCH_EFFECT].extrinsic || have_unfindablestone() || autismweaponcheck(ART_HER_UNREACHABLE_BROOK) ) return(1);
1784 int fundxtrachange = 10;
1785 if (!(PlayerCannotUseSkills)) {
1786 switch (P_SKILL(P_SEARCHING)) {
1787 default: break;
1788 case P_BASIC: fundxtrachange = 8; break;
1789 case P_SKILLED: fundxtrachange = 6; break;
1790 case P_EXPERT: fundxtrachange = 5; break;
1791 case P_MASTER: fundxtrachange = 4; break;
1792 case P_GRAND_MASTER: fundxtrachange = 3; break;
1793 case P_SUPREME_MASTER: fundxtrachange = 2; break;
1797 int trapdiffbonus = 0;
1798 if (!(PlayerCannotUseSkills)) {
1799 switch (P_SKILL(P_SEARCHING)) {
1800 default: break;
1801 case P_BASIC: trapdiffbonus = rnd(10); break;
1802 case P_SKILLED: trapdiffbonus = rnd(20); break;
1803 case P_EXPERT: trapdiffbonus = rnd(35); break;
1804 case P_MASTER: trapdiffbonus = rnd(50); break;
1805 case P_GRAND_MASTER: trapdiffbonus = rnd(75); break;
1806 case P_SUPREME_MASTER: trapdiffbonus = rnd(100); break;
1809 if (ublindf && ublindf->otyp == SHIELD_PATE_GLASSES) trapdiffbonus += rnd(50);
1811 if(u.uswallow) {
1812 if (!aflag)
1813 pline(FunnyHallu ? "There must be some door here, allowing you to get out..." : "What are you looking for? The exit?");
1814 } else {
1815 int fund = (uwep && uwep->oartifact &&
1816 spec_ability(uwep, SPFX_SEARCH)) ?
1817 uwep->spe : 0;
1818 if (ublindf && ublindf->otyp == LENSES && !Blind)
1819 fund += 2; /* JDS: lenses help searching */
1820 if (ublindf && ublindf->otyp == RADIOGLASSES && !Blind)
1821 fund += 2;
1822 if (ublindf && ublindf->otyp == SHIELD_PATE_GLASSES && !Blind)
1823 fund += 2;
1824 if (ublindf && ublindf->otyp == BOSS_VISOR && !Blind)
1825 fund += 2;
1826 if (uarmh && uarmh->otyp == HELM_OF_DISCOVERY && !Blind)
1827 fund += 1; /* Amy: helm of discovery also helps a bit */
1828 if (fund > 5) fund = 5;
1829 for(x = u.ux-1; x < u.ux+2; x++)
1830 for(y = u.uy-1; y < u.uy+2; y++) {
1831 if(!isok(x,y)) continue;
1832 if(x != u.ux || y != u.uy) {
1833 if (/*Blind &&*/ (!aflag || !rn2(fundxtrachange) || !rn2(fundxtrachange)) ) feel_location(x,y);
1834 if(levl[x][y].typ == SDOOR) {
1835 if(rnl(7-fund) && rn2(fundxtrachange) && (rn2(fundxtrachange) || !rn2(2)) ) continue; /* better chance --Amy */
1836 cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */
1837 You("find a secret door!");
1838 u.cnd_searchsecretcount++;
1839 use_skill(P_SEARCHING,1);
1840 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1841 exercise(A_WIS, TRUE);
1842 nomul(0, 0, FALSE);
1843 if (/*Blind && */(!aflag || !rn2(fundxtrachange) || !rn2(fundxtrachange)) )
1844 feel_location(x,y); /* make sure it shows up */
1845 /*else*/
1846 if (!Blind) newsym(x,y);
1847 } else if(levl[x][y].typ == SCORR) {
1848 if(rnl(7-fund) && rn2(fundxtrachange) && (rn2(fundxtrachange) || !rn2(2)) ) continue; /* better chance --Amy */
1849 levl[x][y].typ = CORR;
1850 unblock_point(x,y); /* vision */
1851 You("find a secret passage!");
1852 u.cnd_searchsecretcount++;
1853 use_skill(P_SEARCHING,1);
1854 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1855 exercise(A_WIS, TRUE);
1856 nomul(0, 0, FALSE);
1857 newsym(x,y);
1858 } else {
1859 /* Be careful not to find anything in an SCORR or SDOOR */
1860 if((mtmp = m_at(x, y)) && (!aflag || !rn2(4)) ) {
1861 if(mtmp->m_ap_type) {
1862 seemimic(mtmp);
1863 find: exercise(A_WIS, TRUE);
1864 if (!canspotmon(mtmp)) {
1865 if (memory_is_invisible(x, y)) {
1866 /* found invisible monster in a square
1867 * which already has an 'I' in it.
1868 * Logically, this should still take
1869 * time and lead to a return(1), but if
1870 * we did that the player would keep
1871 * finding the same monster every turn.
1873 continue;
1874 } else {
1875 You_feel("an unseen monster!");
1876 if (!(mtmp->data->msound == MS_DEEPSTATE) && !(mtmp->egotype_deepstatemember)) map_invisible(x, y);
1878 } else if (!sensemon(mtmp))
1879 You("find %s.", a_monnam(mtmp));
1881 /* No idea why finding a monster stops searching the other squares. Bullshit, I say! --Amy */
1882 if (issoviet) {
1883 if (!rn2(20)) pline("Komanda poiska neozhidanno ostanovilas' iz-za oshibki v ispolnyayemom fayle sovetskogo l'da. Potomu chto v Sovetskoy Rossii vy nikogda ne smozhete nayti material, dazhe yesli on nakhoditsya ryadom s vami, kha-kha.");
1884 return(1);
1886 else continue;
1888 if(!canspotmon(mtmp)) {
1889 if (mtmp->mundetected &&
1890 (is_hider(mtmp->data) || mtmp->egotype_hide || mtmp->egotype_mimic || mtmp->data->mlet == S_EEL))
1891 mtmp->mundetected = 0;
1892 newsym(x,y);
1893 goto find;
1897 /* see if an invisible monster has moved--if Blind,
1898 * feel_location() already did it
1900 if ( (!aflag || !rn2(4)) && !mtmp && !Blind &&
1901 memory_is_invisible(x, y)) {
1902 unmap_object(x,y);
1903 newsym(x,y);
1906 /* finding traps is much too hard. Let's increase the chance. --Amy */
1907 if ((trap = t_at(x,y)) && !trap->tseen && !trap->hiddentrap && (trap->trapdiff < rn2(100 + trapdiffbonus) ) && (!isfriday || (trap->trapdiff < rn2(100 + trapdiffbonus)) ) && (trap->trapdiff < rn2(100 + trapdiffbonus + trapdiffbonus) ) && (!rnl(8-fund) || !rn2(fundxtrachange) || (!rn2(fundxtrachange) && !rn2(2)) ) ) {
1908 nomul(0, 0, FALSE);
1910 if (trap->ttyp == STATUE_TRAP || trap->ttyp == SATATUE_TRAP) {
1911 mtmp = activate_statue_trap(trap, x, y, FALSE);
1912 if (mtmp != (struct monst *)0) {
1913 u.cnd_searchtrapcount++;
1914 exercise(A_WIS, TRUE);
1915 mightbooststat(A_WIS);
1916 use_skill(P_SEARCHING,1); /* you found a trap, so the skill should train --Amy */
1919 /* bah, so they made an extra bullshit return for statue traps... --Amy */
1920 if (issoviet) {
1921 if (!rn2(20)) pline("Komanda poiska neozhidanno ostanovilas' iz-za oshibki v ispolnyayemom fayle sovetskogo l'da. Potomu chto v Sovetskoy Rossii vy nikogda ne smozhete nayti material, dazhe yesli on nakhoditsya ryadom s vami, kha-kha.");
1922 return(1);
1924 } else {
1925 find_trap(trap);
1932 return(1);
1935 /* Pre-map the sokoban levels */
1936 void
1937 sokoban_detect()
1939 register int x, y, randa, randb, randc; /* randomly hide some stuff from view because I'm mean :D --Amy */
1940 register struct trap *ttmp;
1941 register struct obj *obj;
1943 randa = rn2(isfriday ? 8 : 20);
1944 randb = rn2(isfriday ? 4 : 10);
1945 randc = rn2(isfriday ? 4 : 10);
1947 /* if you're such a ch3at0r who intentionally picks races that also cause other level types to be generated,
1948 * and actually think you'd still fully benefit from levels all being pre-mapped, tough luck :-P --Amy */
1949 int badluckor = 0;
1950 if (ismazewalker) badluckor++;
1951 if (isspecialist) badluckor++;
1953 if (badluckor == 1) {
1954 if (!rn2(2)) randa = FALSE;
1955 if (!rn2(2)) randb = FALSE;
1956 if (!rn2(2)) randc = FALSE;
1958 if (badluckor == 2) {
1959 if (rn2(3)) randa = FALSE;
1960 if (rn2(3)) randb = FALSE;
1961 if (rn2(3)) randc = FALSE;
1964 /* Map the background and boulders */
1965 for (x = 1; x < COLNO; x++)
1966 for (y = 0; y < ROWNO; y++) {
1968 if (randa) {
1969 levl[x][y].seenv = SVALL;
1970 levl[x][y].waslit = TRUE;
1971 map_background(x, y, 1);
1974 for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
1975 if ((obj->otyp == BOULDER) && randb)
1976 map_object(obj, 1);
1979 /* Map the traps */
1980 for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
1982 /* but only holes and pits --Amy */
1983 if ((ttmp->ttyp == HOLE || ttmp->ttyp == PIT) && randc && !ttmp->hiddentrap) {
1984 ttmp->tseen = 1;
1985 map_trap(ttmp, 1);
1992 dosearch()
1994 if (uwep && uwep->oartifact == ART_VILEA_S_SECRET && !rn2(20)) {
1996 register struct monst *mtmp;
1998 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1999 if (DEADMONSTER(mtmp)) continue;
2000 if (distu(mtmp->mx,mtmp->my) > 50) continue;
2001 if(cansee(mtmp->mx,mtmp->my)) {
2002 if (!resist(mtmp, SCROLL_CLASS, 0, NOTELL))
2003 monflee(mtmp, rnd(10), FALSE, FALSE);
2009 if (uarmh && uarmh->oartifact == ART_TEN_MINUTES_COLDER && !rn2(2)) {
2010 if (Upolyd) {
2011 u.mh++;
2012 if (u.mh > u.mhmax) u.mh = u.mhmax;
2013 } else {
2014 u.uhp++;
2015 if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
2017 flags.botl = TRUE;
2020 if ((TarmuStrokingNora || u.uprops[TARMU_STROKING_NORA].extrinsic || (uarmh && uarmh->oartifact == ART_STROKING_COMBAT) || have_tarmustrokingnorastone()) && u.tarmustrokingturn < 1) {
2021 u.tarmustrokingturn = rnd(100);
2023 int tryct = 0;
2024 int x, y;
2025 boolean canbeinawall = FALSE;
2026 if (!rn2(Passes_walls ? 5 : 25)) canbeinawall = TRUE;
2028 for (tryct = 0; tryct < 2000; tryct++) {
2029 x = rn1(COLNO-3,2);
2030 y = rn2(ROWNO);
2032 if (isok(x, y) && ((levl[x][y].typ > DBWALL) || canbeinawall) && !(t_at(x, y)) ) {
2033 (void) maketrap(x, y, rndtrap(), 100, FALSE);
2034 break;
2040 return(dosearch0(0));
2043 /*detect.c*/