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. */
4 
5 /*
6  * Detection routines, including crystal ball, magic mapping, and search
7  * command.
8  */
9 
10 #include "hack.h"
11 #include "artifact.h"
12 
13 extern boolean known;	/* from read.c */
14 
15 STATIC_DCL void FDECL(do_dknown_of, (struct obj *));
16 STATIC_DCL boolean FDECL(check_map_spot, (int,int,CHAR_P,unsigned));
17 STATIC_DCL boolean FDECL(clear_stale_map, (CHAR_P,unsigned));
18 STATIC_DCL void FDECL(sense_trap, (struct trap *,XCHAR_P,XCHAR_P,int));
19 STATIC_DCL void FDECL(show_map_spot, (int,int));
20 STATIC_PTR void FDECL(findone,(int,int,genericptr_t));
21 STATIC_PTR void FDECL(openone,(int,int,genericptr_t));
22 
23 /* Recursively search obj for an object in class oclass and return 1st found */
24 struct obj *
o_in(obj,oclass)25 o_in(obj, oclass)
26 struct obj* obj;
27 char oclass;
28 {
29     register struct obj* otmp;
30     struct obj *temp;
31 
32     if (obj->oclass == oclass) return obj;
33 
34     if (Has_contents(obj)) {
35 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
36 	    if (otmp->oclass == oclass) return otmp;
37 	    else if (Has_contents(otmp) && (temp = o_in(otmp, oclass)))
38 		return temp;
39     }
40     return (struct obj *) 0;
41 }
42 
43 /* Recursively search obj for an object made of specified material and return 1st found */
44 struct obj *
o_material(obj,material)45 o_material(obj, material)
46 struct obj* obj;
47 unsigned material;
48 {
49     register struct obj* otmp;
50     struct obj *temp;
51 
52     if (objects[obj->otyp].oc_material == material) return obj;
53 
54     if (Has_contents(obj)) {
55 	for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
56 	    if (objects[otmp->otyp].oc_material == material) return otmp;
57 	    else if (Has_contents(otmp) && (temp = o_material(otmp, material)))
58 		return temp;
59     }
60     return (struct obj *) 0;
61 }
62 
63 STATIC_OVL void
do_dknown_of(obj)64 do_dknown_of(obj)
65 struct obj *obj;
66 {
67     struct obj *otmp;
68 
69     obj->dknown = 1;
70     if (Has_contents(obj)) {
71 	for(otmp = obj->cobj; otmp; otmp = otmp->nobj)
72 	    do_dknown_of(otmp);
73     }
74 }
75 
76 /* Check whether the location has an outdated object displayed on it. */
77 STATIC_OVL boolean
check_map_spot(x,y,oclass,material)78 check_map_spot(x, y, oclass, material)
79 int x, y;
80 register char oclass;
81 unsigned material;
82 {
83 	register int glyph;
84 	register struct obj *otmp;
85 	register struct monst *mtmp;
86 
87 	glyph = glyph_at(x,y);
88 	if (glyph_is_object(glyph)) {
89 	    /* there's some object shown here */
90 	    if (oclass == ALL_CLASSES) {
91 		return((boolean)( !(level.objects[x][y] ||     /* stale if nothing here */
92 			    ((mtmp = m_at(x,y)) != 0 &&
93 				(
94 #ifndef GOLDOBJ
95 				 mtmp->mgold ||
96 #endif
97 						 mtmp->minvent)))));
98 	    } else {
99 		if (material && objects[glyph_to_obj(glyph)].oc_material == material) {
100 			/* the object shown here is of interest because material matches */
101 			for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
102 				if (o_material(otmp, GOLD)) return FALSE;
103 			/* didn't find it; perhaps a monster is carrying it */
104 			if ((mtmp = m_at(x,y)) != 0) {
105 				for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
106 					if (o_material(otmp, GOLD)) return FALSE;
107 		        }
108 			/* detection indicates removal of this object from the map */
109 			return TRUE;
110 		}
111 	        if (oclass && objects[glyph_to_obj(glyph)].oc_class == oclass) {
112 			/* the object shown here is of interest because its class matches */
113 			for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
114 				if (o_in(otmp, oclass)) return FALSE;
115 			/* didn't find it; perhaps a monster is carrying it */
116 #ifndef GOLDOBJ
117 			if ((mtmp = m_at(x,y)) != 0) {
118 				if (oclass == COIN_CLASS && mtmp->mgold)
119 					return FALSE;
120 				else for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
121 					if (o_in(otmp, oclass)) return FALSE;
122 		        }
123 #else
124 			if ((mtmp = m_at(x,y)) != 0) {
125 				for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
126 					if (o_in(otmp, oclass)) return FALSE;
127 		        }
128 #endif
129 			/* detection indicates removal of this object from the map */
130 			return TRUE;
131 	        }
132 	    }
133 	}
134 	return FALSE;
135 }
136 
137 /*
138    When doing detection, remove stale data from the map display (corpses
139    rotted away, objects carried away by monsters, etc) so that it won't
140    reappear after the detection has completed.  Return true if noticeable
141    change occurs.
142  */
143 STATIC_OVL boolean
clear_stale_map(oclass,material)144 clear_stale_map(oclass, material)
145 register char oclass;
146 unsigned material;
147 {
148 	register int zx, zy;
149 	register boolean change_made = FALSE;
150 
151 	for (zx = 1; zx < COLNO; zx++)
152 	    for (zy = 0; zy < ROWNO; zy++)
153 		if (check_map_spot(zx, zy, oclass,material)) {
154 		    unmap_object(zx, zy);
155 		    change_made = TRUE;
156 		}
157 
158 	return change_made;
159 }
160 
161 /* look for gold, on the floor or in monsters' possession */
162 int
gold_detect(sobj)163 gold_detect(sobj)
164 register struct obj *sobj;
165 {
166     register struct obj *obj;
167     register struct monst *mtmp;
168     int uw = u.uinwater;
169     struct obj *temp;
170     boolean stale;
171 
172     known = stale = clear_stale_map(COIN_CLASS,
173 				(unsigned)(sobj->blessed ? GOLD : 0));
174 
175     /* look for gold carried by monsters (might be in a container) */
176     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
177     	if (DEADMONSTER(mtmp)) continue;	/* probably not needed in this case but... */
178 #ifndef GOLDOBJ
179 	if (mtmp->mgold || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
180 #else
181 	if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
182 #endif
183 	    known = TRUE;
184 	    goto outgoldmap;	/* skip further searching */
185 	} else for (obj = mtmp->minvent; obj; obj = obj->nobj)
186 	    if (sobj->blessed && o_material(obj, GOLD)) {
187 	    	known = TRUE;
188 	    	goto outgoldmap;
189 	    } else if (o_in(obj, COIN_CLASS)) {
190 		known = TRUE;
191 		goto outgoldmap;	/* skip further searching */
192 	    }
193     }
194 
195     /* look for gold objects */
196     for (obj = fobj; obj; obj = obj->nobj) {
197 	if (sobj->blessed && o_material(obj, GOLD)) {
198 	    known = TRUE;
199 	    if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap;
200 	} else if (o_in(obj, COIN_CLASS)) {
201 	    known = TRUE;
202 	    if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap;
203 	}
204     }
205 
206     if (!known) {
207 	/* no gold found on floor or monster's inventory.
208 	   adjust message if you have gold in your inventory */
209 	if (sobj) {
210 		char buf[BUFSZ];
211 		if (youmonst.data == &mons[PM_GOLD_GOLEM]) {
212 			Sprintf(buf, "You feel like a million %s!",
213 				currency(2L));
214 		} else if (hidden_gold() ||
215 #ifndef GOLDOBJ
216 				u.ugold)
217 #else
218 			        money_cnt(invent))
219 #endif
220 			Strcpy(buf,
221 				"You feel worried about your future financial situation.");
222 		else
223 			Strcpy(buf, "You feel materially poor.");
224 		strange_feeling(sobj, buf);
225         }
226 	return(1);
227     }
228     /* only under me - no separate display required */
229     if (stale) docrt();
230     You("notice some gold between your %s.", makeplural(body_part(FOOT)));
231     return(0);
232 
233 outgoldmap:
234     cls();
235 
236     u.uinwater = 0;
237     /* Discover gold locations. */
238     for (obj = fobj; obj; obj = obj->nobj) {
239     	if (sobj->blessed && (temp = o_material(obj, GOLD))) {
240 	    if (temp != obj) {
241 		temp->ox = obj->ox;
242 		temp->oy = obj->oy;
243 	    }
244 	    map_object(temp,1);
245 	} else if ((temp = o_in(obj, COIN_CLASS))) {
246 	    if (temp != obj) {
247 		temp->ox = obj->ox;
248 		temp->oy = obj->oy;
249 	    }
250 	    map_object(temp,1);
251 	}
252     }
253     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
254     	if (DEADMONSTER(mtmp)) continue;	/* probably overkill here */
255 #ifndef GOLDOBJ
256 	if (mtmp->mgold || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
257 #else
258 	if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
259 #endif
260 	    struct obj gold;
261 
262 	    gold.otyp = GOLD_PIECE;
263 	    gold.ox = mtmp->mx;
264 	    gold.oy = mtmp->my;
265 	    map_object(&gold,1);
266 	} else for (obj = mtmp->minvent; obj; obj = obj->nobj)
267 	    if (sobj->blessed && (temp = o_material(obj, GOLD))) {
268 		temp->ox = mtmp->mx;
269 		temp->oy = mtmp->my;
270 		map_object(temp,1);
271 		break;
272 	    } else if ((temp = o_in(obj, COIN_CLASS))) {
273 		temp->ox = mtmp->mx;
274 		temp->oy = mtmp->my;
275 		map_object(temp,1);
276 		break;
277 	    }
278     }
279 
280     newsym(u.ux,u.uy);
281     You_feel("very greedy, and sense gold!");
282     exercise(A_WIS, TRUE);
283     display_nhwindow(WIN_MAP, TRUE);
284     docrt();
285     u.uinwater = uw;
286     if (Underwater) under_water(2);
287     if (u.uburied) under_ground(2);
288     return(0);
289 }
290 
291 /* returns 1 if nothing was detected		*/
292 /* returns 0 if something was detected		*/
293 int
food_detect(sobj)294 food_detect(sobj)
295 register struct obj	*sobj;
296 {
297     register struct obj *obj;
298     register struct monst *mtmp;
299     register int ct = 0, ctu = 0;
300     boolean confused = (Confusion || (sobj && sobj->cursed)), stale;
301     char oclass = confused ? POTION_CLASS : FOOD_CLASS;
302     const char *what = confused ? something : "food";
303     int uw = u.uinwater;
304 
305     stale = clear_stale_map(oclass, 0);
306 
307     for (obj = fobj; obj; obj = obj->nobj)
308 	if (o_in(obj, oclass)) {
309 	    if (obj->ox == u.ux && obj->oy == u.uy) ctu++;
310 	    else ct++;
311 	}
312     for (mtmp = fmon; mtmp && !ct; mtmp = mtmp->nmon) {
313 	/* no DEADMONSTER(mtmp) check needed since dmons never have inventory */
314 	for (obj = mtmp->minvent; obj; obj = obj->nobj)
315 	    if (o_in(obj, oclass)) {
316 		ct++;
317 		break;
318 	    }
319     }
320 
321     if (!ct && !ctu) {
322 	known = stale && !confused;
323 	if (stale) {
324 	    docrt();
325 	    You("sense a lack of %s nearby.", what);
326 	    if (sobj && sobj->blessed) {
327 		if (!u.uedibility) Your("%s starts to tingle.", body_part(NOSE));
328 		u.uedibility = 1;
329 	    }
330 	} else if (sobj) {
331 	    char buf[BUFSZ];
332 	    Sprintf(buf, "Your %s twitches%s.", body_part(NOSE),
333 			(sobj->blessed && !u.uedibility) ? " then starts to tingle" : "");
334 	    if (sobj->blessed && !u.uedibility) {
335 		boolean savebeginner = flags.beginner;	/* prevent non-delivery of */
336 		flags.beginner = FALSE;			/* 	message            */
337 		strange_feeling(sobj, buf);
338 		flags.beginner = savebeginner;
339 		u.uedibility = 1;
340 	    } else
341 		strange_feeling(sobj, buf);
342 	}
343 	return !stale;
344     } else if (!ct) {
345 	known = TRUE;
346 	You("%s %s nearby.", sobj ? "smell" : "sense", what);
347 	if (sobj && sobj->blessed) {
348 		if (!u.uedibility) pline("Your %s starts to tingle.", body_part(NOSE));
349 		u.uedibility = 1;
350 	}
351     } else {
352 	struct obj *temp;
353 	known = TRUE;
354 	cls();
355 	u.uinwater = 0;
356 	for (obj = fobj; obj; obj = obj->nobj)
357 	    if ((temp = o_in(obj, oclass)) != 0) {
358 		if (temp != obj) {
359 		    temp->ox = obj->ox;
360 		    temp->oy = obj->oy;
361 		}
362 		map_object(temp,1);
363 	    }
364 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
365 	    /* no DEADMONSTER(mtmp) check needed since dmons never have inventory */
366 	    for (obj = mtmp->minvent; obj; obj = obj->nobj)
367 		if ((temp = o_in(obj, oclass)) != 0) {
368 		    temp->ox = mtmp->mx;
369 		    temp->oy = mtmp->my;
370 		    map_object(temp,1);
371 		    break;	/* skip rest of this monster's inventory */
372 		}
373 	newsym(u.ux,u.uy);
374 	if (sobj) {
375 	    if (sobj->blessed) {
376 	    	Your("%s %s to tingle and you smell %s.", body_part(NOSE),
377 	    		u.uedibility ? "continues" : "starts", what);
378 		u.uedibility = 1;
379 	    } else
380 		Your("%s tingles and you smell %s.", body_part(NOSE), what);
381 	}
382 	else You("sense %s.", what);
383 	display_nhwindow(WIN_MAP, TRUE);
384 	exercise(A_WIS, TRUE);
385 	docrt();
386 	u.uinwater = uw;
387 	if (Underwater) under_water(2);
388 	if (u.uburied) under_ground(2);
389     }
390     return(0);
391 }
392 
393 /*
394  * Used for scrolls, potions, spells, and crystal balls.  Returns:
395  *
396  *	1 - nothing was detected
397  *	0 - something was detected
398  */
399 int
object_detect(detector,class)400 object_detect(detector, class)
401 struct obj	*detector;	/* object doing the detecting */
402 int		class;		/* an object class, 0 for all */
403 {
404     register int x, y;
405     char stuff[BUFSZ];
406     int is_cursed = (detector && detector->cursed);
407     int do_dknown = (detector && (detector->oclass == POTION_CLASS ||
408 				    detector->oclass == SPBOOK_CLASS) &&
409 			detector->blessed);
410     int ct = 0, ctu = 0;
411     register struct obj *obj, *otmp = (struct obj *)0;
412     register struct monst *mtmp;
413     int uw = u.uinwater;
414     int sym, boulder = 0;
415 
416     if (class < 0 || class >= MAXOCLASSES) {
417 	warning("object_detect:  illegal class %d", class);
418 	class = 0;
419     }
420 
421     /* Special boulder symbol check - does the class symbol happen
422      * to match iflags.bouldersym which is a user-defined?
423      * If so, that means we aren't sure what they really wanted to
424      * detect. Rather than trump anything, show both possibilities.
425      * We can exclude checking the buried obj chain for boulders below.
426      */
427     sym = class ? def_oc_syms[class] : 0;
428     if (sym && iflags.bouldersym && sym == iflags.bouldersym)
429     	boulder = ROCK_CLASS;
430 
431     if (Hallucination || (Confusion && class == SCROLL_CLASS))
432 	Strcpy(stuff, something);
433     else
434     	Strcpy(stuff, class ? oclass_names[class] : "objects");
435     if (boulder && class != ROCK_CLASS) Strcat(stuff, " and/or large stones");
436 
437     if (do_dknown) for(obj = invent; obj; obj = obj->nobj) do_dknown_of(obj);
438 
439     for (obj = fobj; obj; obj = obj->nobj) {
440 	if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) {
441 	    if (obj->ox == u.ux && obj->oy == u.uy) ctu++;
442 	    else ct++;
443 	}
444 	if (do_dknown) do_dknown_of(obj);
445     }
446 
447     for (obj = level.buriedobjlist; obj; obj = obj->nobj) {
448 	if (!class || o_in(obj, class)) {
449 	    if (obj->ox == u.ux && obj->oy == u.uy) ctu++;
450 	    else ct++;
451 	}
452 	if (do_dknown) do_dknown_of(obj);
453     }
454 
455     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
456 	if (DEADMONSTER(mtmp)) continue;
457 	for (obj = mtmp->minvent; obj; obj = obj->nobj) {
458 	    if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) ct++;
459 	    if (do_dknown) do_dknown_of(obj);
460 	}
461 	if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT &&
462 	    (!class || class == objects[mtmp->mappearance].oc_class)) ||
463 #ifndef GOLDOBJ
464 	    (mtmp->mgold && (!class || class == COIN_CLASS))) {
465 #else
466 	    (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) {
467 #endif
468 	    ct++;
469 	    break;
470 	}
471     }
472 
473     if (!clear_stale_map(!class ? ALL_CLASSES : class, 0) && !ct) {
474 	if (!ctu) {
475 	    if (detector)
476 		strange_feeling(detector, "You feel a lack of something.");
477 	    return 1;
478 	}
479 
480 	You("sense %s nearby.", stuff);
481 	return 0;
482     }
483 
484     cls();
485 
486     u.uinwater = 0;
487 /*
488  *	Map all buried objects first.
489  */
490     for (obj = level.buriedobjlist; obj; obj = obj->nobj)
491 	if (!class || (otmp = o_in(obj, class))) {
492 	    if (class) {
493 		if (otmp != obj) {
494 		    otmp->ox = obj->ox;
495 		    otmp->oy = obj->oy;
496 		}
497 		map_object(otmp, 1);
498 	    } else
499 		map_object(obj, 1);
500 	}
501     /*
502      * If we are mapping all objects, map only the top object of a pile or
503      * the first object in a monster's inventory.  Otherwise, go looking
504      * for a matching object class and display the first one encountered
505      * at each location.
506      *
507      * Objects on the floor override buried objects.
508      */
509     for (x = 1; x < COLNO; x++)
510 	for (y = 0; y < ROWNO; y++)
511 	    for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
512 		if ((!class && !boulder) ||
513 		    (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) {
514 		    if (class || boulder) {
515 			if (otmp != obj) {
516 			    otmp->ox = obj->ox;
517 			    otmp->oy = obj->oy;
518 			}
519 			map_object(otmp, 1);
520 		    } else
521 			map_object(obj, 1);
522 		    break;
523 		}
524 
525     /* Objects in the monster's inventory override floor objects. */
526     for (mtmp = fmon ; mtmp ; mtmp = mtmp->nmon) {
527 	if (DEADMONSTER(mtmp)) continue;
528 	for (obj = mtmp->minvent; obj; obj = obj->nobj)
529 	    if ((!class && !boulder) ||
530 		 (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) {
531 		if (!class && !boulder) otmp = obj;
532 		otmp->ox = mtmp->mx;		/* at monster location */
533 		otmp->oy = mtmp->my;
534 		map_object(otmp, 1);
535 		break;
536 	    }
537 	/* Allow a mimic to override the detected objects it is carrying. */
538 	if (is_cursed && mtmp->m_ap_type == M_AP_OBJECT &&
539 		(!class || class == objects[mtmp->mappearance].oc_class)) {
540 	    struct obj temp;
541 
542 	    temp.otyp = mtmp->mappearance;	/* needed for obj_to_glyph() */
543 	    temp.ox = mtmp->mx;
544 	    temp.oy = mtmp->my;
545 	    temp.corpsenm = PM_TENGU;		/* if mimicing a corpse */
546 	    map_object(&temp, 1);
547 #ifndef GOLDOBJ
548 	} else if (mtmp->mgold && (!class || class == COIN_CLASS)) {
549 #else
550 	} else if (findgold(mtmp->minvent) && (!class || class == COIN_CLASS)) {
551 #endif
552 	    struct obj gold;
553 
554 	    gold.otyp = GOLD_PIECE;
555 	    gold.ox = mtmp->mx;
556 	    gold.oy = mtmp->my;
557 	    map_object(&gold, 1);
558 	}
559     }
560 
561     newsym(u.ux,u.uy);
562     You("detect the %s of %s.", ct ? "presence" : "absence", stuff);
563     display_nhwindow(WIN_MAP, TRUE);
564     /*
565      * What are we going to do when the hero does an object detect while blind
566      * and the detected object covers a known pool?
567      */
568     docrt();	/* this will correctly reset vision */
569 
570     u.uinwater = uw;
571     if (Underwater) under_water(2);
572     if (u.uburied) under_ground(2);
573     return 0;
574 }
575 
576 /*
577  * Used by: crystal balls, potions, fountains
578  *
579  * Returns 1 if nothing was detected.
580  * Returns 0 if something was detected.
581  */
582 int
monster_detect(otmp,mclass)583 monster_detect(otmp, mclass)
584 register struct obj *otmp;	/* detecting object (if any) */
585 int mclass;			/* monster class, 0 for all */
586 {
587     register struct monst *mtmp;
588     int mcnt = 0;
589 
590 
591     /* Note: This used to just check fmon for a non-zero value
592      * but in versions since 3.3.0 fmon can test TRUE due to the
593      * presence of dmons, so we have to find at least one
594      * with positive hit-points to know for sure.
595      */
596     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
597     	if (!DEADMONSTER(mtmp)) {
598 		mcnt++;
599 		break;
600 	}
601 
602     if (!mcnt) {
603 	if (otmp)
604 	    strange_feeling(otmp, Hallucination ?
605 			    "You get the heebie jeebies." :
606 			    "You feel threatened.");
607 	return 1;
608     } else {
609 	boolean woken = FALSE;
610 
611 	cls();
612 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
613 	    if (DEADMONSTER(mtmp)) continue;
614 	    if (!mclass || mtmp->data->mlet == mclass ||
615 		(mtmp->data == &mons[PM_LONG_WORM] && mclass == S_WORM_TAIL))
616 		    if (mtmp->mx > 0) {
617 		    	if (mclass && def_monsyms[mclass] == ' ')
618 				show_glyph(mtmp->mx,mtmp->my,
619 					detected_mon_to_glyph(mtmp));
620 			else
621 				show_glyph(mtmp->mx,mtmp->my,mon_to_glyph(mtmp));
622 			/* don't be stingy - display entire worm */
623 			if (mtmp->data == &mons[PM_LONG_WORM]) detect_wsegs(mtmp,0);
624 		    }
625 	    if (otmp && otmp->cursed &&
626 		(mtmp->msleeping || !mtmp->mcanmove)) {
627 		mtmp->msleeping = mtmp->mfrozen = 0;
628 		mtmp->mcanmove = 1;
629 		woken = TRUE;
630 	    }
631 	}
632 	display_self();
633 	You("sense the presence of monsters.");
634 	if (woken)
635 	    pline("Monsters sense the presence of you.");
636 	display_nhwindow(WIN_MAP, TRUE);
637 	docrt();
638 	if (Underwater) under_water(2);
639 	if (u.uburied) under_ground(2);
640     }
641     return 0;
642 }
643 
644 STATIC_OVL void
sense_trap(trap,x,y,src_cursed)645 sense_trap(trap, x, y, src_cursed)
646 struct trap *trap;
647 xchar x, y;
648 int src_cursed;
649 {
650     if (Hallucination || src_cursed) {
651 	struct obj obj;			/* fake object */
652 	if (trap) {
653 	    obj.ox = trap->tx;
654 	    obj.oy = trap->ty;
655 	} else {
656 	    obj.ox = x;
657 	    obj.oy = y;
658 	}
659 	obj.otyp = (src_cursed) ? GOLD_PIECE : random_object();
660 	obj.corpsenm = random_monster();	/* if otyp == CORPSE */
661 	map_object(&obj,1);
662     } else if (trap) {
663 	map_trap(trap,1);
664 	trap->tseen = 1;
665     } else {
666 	struct trap temp_trap;		/* fake trap */
667 	temp_trap.tx = x;
668 	temp_trap.ty = y;
669 	temp_trap.ttyp = BEAR_TRAP;	/* some kind of trap */
670 	map_trap(&temp_trap,1);
671     }
672 
673 }
674 
675 /* the detections are pulled out so they can	*/
676 /* also be used in the crystal ball routine	*/
677 /* returns 1 if nothing was detected		*/
678 /* returns 0 if something was detected		*/
679 int
trap_detect(sobj)680 trap_detect(sobj)
681 register struct obj *sobj;
682 /* sobj is null if crystal ball, *scroll if gold detection scroll */
683 {
684     register struct trap *ttmp;
685     register struct obj *obj;
686     register int door;
687     int uw = u.uinwater;
688     boolean found = FALSE;
689     coord cc;
690 
691     for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
692 	if (ttmp->tx != u.ux || ttmp->ty != u.uy)
693 	    goto outtrapmap;
694 	else found = TRUE;
695     }
696     for (obj = fobj; obj; obj = obj->nobj) {
697 	if ((obj->otyp == LARGE_BOX || obj->otyp == CHEST || obj->otyp == IRON_SAFE) &&
698 	    obj->otrapped) {
699 	    if (obj->ox != u.ux || obj->oy != u.uy)
700 		goto outtrapmap;
701 	    else found = TRUE;
702 	}
703     }
704     for (door = 0; door < doorindex; door++) {
705 	cc = doors[door];
706 	if (levl[cc.x][cc.y].doormask & D_TRAPPED) {
707 	    if (cc.x != u.ux || cc.y != u.uy)
708 		goto outtrapmap;
709 	    else found = TRUE;
710 	}
711     }
712     if (!found) {
713 	char buf[42];
714 	Sprintf(buf, "Your %s stop itching.", makeplural(body_part(TOE)));
715 	strange_feeling(sobj,buf);
716 	return(1);
717     }
718     /* traps exist, but only under me - no separate display required */
719     Your("%s itch.", makeplural(body_part(TOE)));
720     return(0);
721 outtrapmap:
722     cls();
723 
724     u.uinwater = 0;
725     for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
726 	sense_trap(ttmp, 0, 0, sobj && sobj->cursed);
727 
728     for (obj = fobj; obj; obj = obj->nobj)
729 	if ((obj->otyp == LARGE_BOX || obj->otyp == CHEST || obj->otyp == IRON_SAFE) &&
730 	    obj->otrapped)
731 	sense_trap((struct trap *)0, obj->ox, obj->oy, sobj && sobj->cursed);
732 
733     for (door = 0; door < doorindex; door++) {
734 	cc = doors[door];
735 	if (levl[cc.x][cc.y].doormask & D_TRAPPED)
736 	sense_trap((struct trap *)0, cc.x, cc.y, sobj && sobj->cursed);
737     }
738 
739     newsym(u.ux,u.uy);
740     You_feel("%s.", sobj && sobj->cursed ? "very greedy" : "entrapped");
741     display_nhwindow(WIN_MAP, TRUE);
742     docrt();
743     u.uinwater = uw;
744     if (Underwater) under_water(2);
745     if (u.uburied) under_ground(2);
746     return(0);
747 }
748 
749 const char *
level_distance(where)750 level_distance(where)
751 d_level *where;
752 {
753     register schar ll = depth(&u.uz) - depth(where);
754     register boolean indun = (u.uz.dnum == where->dnum);
755 
756     if (ll < 0) {
757 	if (ll < (-8 - rn2(3)))
758 	    if (!indun)	return "far away";
759 	    else	return "far below";
760 	else if (ll < -1)
761 	    if (!indun)	return "away below you";
762 	    else	return "below you";
763 	else
764 	    if (!indun)	return "in the distance";
765 	    else	return "just below";
766     } else if (ll > 0) {
767 	if (ll > (8 + rn2(3)))
768 	    if (!indun)	return "far away";
769 	    else	return "far above";
770 	else if (ll > 1)
771 	    if (!indun)	return "away above you";
772 	    else	return "above you";
773 	else
774 	    if (!indun)	return "in the distance";
775 	    else	return "just above";
776     } else
777 	    if (!indun)	return "in the distance";
778 	    else	return "near you";
779 }
780 
781 static const struct {
782     const char *what;
783     d_level *where;
784 } level_detects[] = {
785   { "Delphi", &oracle_level },
786   { "Medusa's lair", &medusa_level },
787   { "a castle", &stronghold_level },
788   { "the Wizard of Yendor's tower", &wiz1_level },
789 };
790 
791 void
use_crystal_ball(obj)792 use_crystal_ball(obj)
793 struct obj *obj;
794 {
795     char ch;
796     int oops;
797 
798     if (Blind) {
799 	pline("Too bad you can't see %s.", the(xname(obj)));
800 	return;
801     }
802     oops = (rnd(obj->blessed ? 13 : 20) > ACURR(A_INT) || obj->cursed);
803     if (oops && (obj->spe > 0)) {
804 	switch (rnd(obj->oartifact ? 4 : 5)) {
805 	case 1 : pline("%s too much to comprehend!", Tobjnam(obj, "are"));
806 	    break;
807 	case 2 : pline("%s you!", Tobjnam(obj, "confuse"));
808 	    make_confused(HConfusion + rnd(100),FALSE);
809 	    break;
810 	case 3 : if (!resists_blnd(&youmonst)) {
811 		pline("%s your vision!", Tobjnam(obj, "damage"));
812 		make_blinded(Blinded + rnd(100),FALSE);
813 		if (!Blind) Your(vision_clears);
814 	    } else {
815 		pline("%s your vision.", Tobjnam(obj, "assault"));
816 		You("are unaffected!");
817 	    }
818 	    break;
819 	case 4 : pline("%s your mind!", Tobjnam(obj, "zap"));
820 	    (void) make_hallucinated(HHallucination + rnd(100),FALSE,0L);
821 	    break;
822 	case 5 : pline("%s!", Tobjnam(obj, "explode"));
823 	    useup(obj);
824 	    obj = 0;	/* it's gone */
825 	    losehp(rnd(30), "exploding crystal ball", KILLED_BY_AN);
826 	    break;
827 	}
828 	if (obj) consume_obj_charge(obj, TRUE);
829 	return;
830     }
831 
832     if (Hallucination) {
833 	if (!obj->spe) {
834 	    pline("All you see is funky %s haze.", hcolor((char *)0));
835 	} else {
836 	    switch(rnd(6)) {
837 	    case 1 : You("grok some groovy globs of incandescent lava.");
838 		break;
839 	    case 2 : pline("Whoa!  Psychedelic colors, %s!",
840 			   poly_gender() == 1 ? "babe" : "dude");
841 		break;
842 	    case 3 : pline_The("crystal pulses with sinister %s light!",
843 				hcolor((char *)0));
844 		break;
845 	    case 4 : You("see goldfish swimming above fluorescent rocks.");
846 		break;
847 	    case 5 : You("see tiny snowflakes spinning around a miniature farmhouse.");
848 		break;
849 	    default: pline("Oh wow... like a kaleidoscope!");
850 		break;
851 	    }
852 	    consume_obj_charge(obj, TRUE);
853 	}
854 	return;
855     }
856 
857     /* read a single character */
858     if (flags.verbose) You("may look for an object or monster symbol.");
859     ch = yn_function("What do you look for?", (char *)0, '\0');
860     /* Don't filter out ' ' here; it has a use */
861     if ((ch != def_monsyms[S_GHOST]) && index(quitchars,ch)) {
862 	if (flags.verbose) pline(Never_mind);
863 	return;
864     }
865     You("peer into %s...", the(xname(obj)));
866     nomul(-rnd(10), "gazing into a crystal ball");
867     nomovemsg = "";
868     if (obj->spe <= 0)
869 	pline_The("vision is unclear.");
870     else {
871 	int class;
872 	int ret = 0;
873 
874 	makeknown(CRYSTAL_BALL);
875 	consume_obj_charge(obj, TRUE);
876 
877 	/* special case: accept ']' as synonym for mimic
878 	 * we have to do this before the def_char_to_objclass check
879 	 */
880 	if (ch == DEF_MIMIC_DEF) ch = DEF_MIMIC;
881 
882 	if ((class = def_char_to_objclass(ch)) != MAXOCLASSES)
883 		ret = object_detect((struct obj *)0, class);
884 	else if ((class = def_char_to_monclass(ch)) != MAXMCLASSES)
885 		ret = monster_detect((struct obj *)0, class);
886 	else if (iflags.bouldersym && (ch == iflags.bouldersym))
887 		ret = object_detect((struct obj *)0, ROCK_CLASS);
888 	else switch(ch) {
889 		case '^':
890 		    ret = trap_detect((struct obj *)0);
891 		    break;
892 		default:
893 		    {
894 		    int i = rn2(SIZE(level_detects));
895 		    You("see %s, %s.",
896 			level_detects[i].what,
897 			level_distance(level_detects[i].where));
898 		    }
899 		    ret = 0;
900 		    break;
901 	}
902 
903 	if (ret) {
904 	    if (!rn2(100))  /* make them nervous */
905 		You("see the Wizard of Yendor gazing out at you.");
906 	    else pline_The("vision is unclear.");
907 	}
908     }
909     return;
910 }
911 
912 STATIC_OVL void
show_map_spot(x,y)913 show_map_spot(x, y)
914 register int x, y;
915 {
916     register struct rm *lev;
917 
918     if (Confusion && rn2(7)) return;
919     lev = &levl[x][y];
920 
921     lev->seenv = SVALL;
922 
923     /* Secret corridors are found, but not secret doors. */
924     if (lev->typ == SCORR) {
925 	lev->typ = CORR;
926 	unblock_point(x,y);
927     }
928 
929     /* if we don't remember an object or trap there, map it */
930     if (lev->typ == ROOM ?
931 	    (glyph_is_cmap(lev->glyph) && !glyph_is_trap(lev->glyph) &&
932 		glyph_to_cmap(lev->glyph) != ROOM) :
933 	    (!glyph_is_object(lev->glyph) && !glyph_is_trap(lev->glyph))) {
934 	if (level.flags.hero_memory) {
935 	    magic_map_background(x,y,0);
936 	    newsym(x,y);			/* show it, if not blocked */
937 	} else {
938 	    magic_map_background(x,y,1);	/* display it */
939 	}
940     }
941 }
942 
943 void
do_mapping()944 do_mapping()
945 {
946     register int zx, zy;
947     int uw = u.uinwater;
948 
949     u.uinwater = 0;
950     for (zx = 1; zx < COLNO; zx++)
951 	for (zy = 0; zy < ROWNO; zy++)
952 	    show_map_spot(zx, zy);
953     exercise(A_WIS, TRUE);
954     u.uinwater = uw;
955     if (!level.flags.hero_memory || Underwater) {
956 	flush_screen(1);			/* flush temp screen */
957 	display_nhwindow(WIN_MAP, TRUE);	/* wait */
958 	docrt();
959     }
960 }
961 
962 void
do_vicinity_map()963 do_vicinity_map()
964 {
965     register int zx, zy;
966     int lo_y = (u.uy-5 < 0 ? 0 : u.uy-5),
967 	hi_y = (u.uy+6 > ROWNO ? ROWNO : u.uy+6),
968 	lo_x = (u.ux-9 < 1 ? 1 : u.ux-9),	/* avoid column 0 */
969 	hi_x = (u.ux+10 > COLNO ? COLNO : u.ux+10);
970 
971     for (zx = lo_x; zx < hi_x; zx++)
972 	for (zy = lo_y; zy < hi_y; zy++)
973 	    show_map_spot(zx, zy);
974 
975     if (!level.flags.hero_memory || Underwater) {
976 	flush_screen(1);			/* flush temp screen */
977 	display_nhwindow(WIN_MAP, TRUE);	/* wait */
978 	docrt();
979     }
980 }
981 
982 /* convert a secret door into a normal door */
983 void
cvt_sdoor_to_door(lev)984 cvt_sdoor_to_door(lev)
985 struct rm *lev;
986 {
987 	int newmask = lev->doormask & ~WM_MASK;
988 
989 #ifdef REINCARNATION
990 	if (Is_rogue_level(&u.uz))
991 	    /* rogue didn't have doors, only doorways */
992 	    newmask = D_NODOOR;
993 	else
994 #endif
995 	    /* newly exposed door is closed */
996 	    if (!(newmask & D_LOCKED)) newmask |= D_CLOSED;
997 
998 	lev->typ = DOOR;
999 	lev->doormask = newmask;
1000 }
1001 
1002 
1003 STATIC_PTR void
findone(zx,zy,num)1004 findone(zx,zy,num)
1005 int zx,zy;
1006 genericptr_t num;
1007 {
1008 	register struct trap *ttmp;
1009 	register struct monst *mtmp;
1010 
1011 	if(levl[zx][zy].typ == SDOOR) {
1012 		cvt_sdoor_to_door(&levl[zx][zy]);	/* .typ = DOOR */
1013 		magic_map_background(zx, zy, 0);
1014 		newsym(zx, zy);
1015 		(*(int*)num)++;
1016 	} else if(levl[zx][zy].typ == SCORR) {
1017 		levl[zx][zy].typ = CORR;
1018 		unblock_point(zx,zy);
1019 		magic_map_background(zx, zy, 0);
1020 		newsym(zx, zy);
1021 		(*(int*)num)++;
1022 	} else if ((ttmp = t_at(zx, zy)) != 0) {
1023 		if(!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) {
1024 			ttmp->tseen = 1;
1025 			newsym(zx,zy);
1026 			(*(int*)num)++;
1027 		}
1028 	} else if ((mtmp = m_at(zx, zy)) != 0) {
1029 		if(mtmp->m_ap_type) {
1030 			seemimic(mtmp);
1031 			(*(int*)num)++;
1032 		}
1033 		if (mtmp->mundetected &&
1034 		    (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) {
1035 			mtmp->mundetected = 0;
1036 			newsym(zx, zy);
1037 			(*(int*)num)++;
1038 		}
1039 		if (!canspotmon(mtmp) &&
1040 				    !glyph_is_invisible(levl[zx][zy].glyph))
1041 			map_invisible(zx, zy);
1042 	} else if (glyph_is_invisible(levl[zx][zy].glyph)) {
1043 		unmap_object(zx, zy);
1044 		newsym(zx, zy);
1045 		(*(int*)num)++;
1046 	}
1047 }
1048 
1049 STATIC_PTR void
openone(zx,zy,num)1050 openone(zx,zy,num)
1051 int zx,zy;
1052 genericptr_t num;
1053 {
1054 	register struct trap *ttmp;
1055 	register struct obj *otmp;
1056 
1057 	if(OBJ_AT(zx, zy)) {
1058 		for(otmp = level.objects[zx][zy];
1059 				otmp; otmp = otmp->nexthere) {
1060 		    if(Is_box(otmp) && otmp->olocked) {
1061 			otmp->olocked = 0;
1062 			(*(int*)num)++;
1063 		    }
1064 		}
1065 		/* let it fall to the next cases. could be on trap. */
1066 	}
1067 	if(levl[zx][zy].typ == SDOOR || (levl[zx][zy].typ == DOOR &&
1068 		      (levl[zx][zy].doormask & (D_CLOSED|D_LOCKED)))) {
1069 		if(levl[zx][zy].typ == SDOOR)
1070 		    cvt_sdoor_to_door(&levl[zx][zy]);	/* .typ = DOOR */
1071 		if(levl[zx][zy].doormask & D_TRAPPED) {
1072 		    if(distu(zx, zy) < 3) b_trapped("door", 0);
1073 		    else Norep("You %s an explosion!",
1074 				cansee(zx, zy) ? "see" :
1075 				   (flags.soundok ? "hear" :
1076 						"feel the shock of"));
1077 		    wake_nearto(zx, zy, 11*11);
1078 		    levl[zx][zy].doormask = D_NODOOR;
1079 		} else
1080 		    levl[zx][zy].doormask = D_ISOPEN;
1081 		unblock_point(zx, zy);
1082 		newsym(zx, zy);
1083 		(*(int*)num)++;
1084 	} else if(levl[zx][zy].typ == SCORR) {
1085 		levl[zx][zy].typ = CORR;
1086 		unblock_point(zx, zy);
1087 		newsym(zx, zy);
1088 		(*(int*)num)++;
1089 	} else if ((ttmp = t_at(zx, zy)) != 0) {
1090 		if (!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) {
1091 		    ttmp->tseen = 1;
1092 		    newsym(zx,zy);
1093 		    (*(int*)num)++;
1094 		}
1095 	} else if (find_drawbridge(&zx, &zy)) {
1096 		/* make sure it isn't an open drawbridge */
1097 		open_drawbridge(zx, zy);
1098 		(*(int*)num)++;
1099 	}
1100 }
1101 
1102 int
findit()1103 findit()	/* returns number of things found */
1104 {
1105 	int num = 0;
1106 
1107 	if(u.uswallow) return(0);
1108 	do_clear_area(u.ux, u.uy, BOLT_LIM, findone, (genericptr_t) &num);
1109 	return(num);
1110 }
1111 
1112 int
openit()1113 openit()	/* returns number of things found and opened */
1114 {
1115 	int num = 0;
1116 
1117 	if(u.uswallow) {
1118 		if (is_animal(u.ustuck->data)) {
1119 			if (Blind) pline("Its mouth opens!");
1120 			else pline("%s opens its mouth!", Monnam(u.ustuck));
1121 		}
1122 		expels(u.ustuck, u.ustuck->data, TRUE);
1123 		return(-1);
1124 	}
1125 
1126 	do_clear_area(u.ux, u.uy, BOLT_LIM, openone, (genericptr_t) &num);
1127 	return(num);
1128 }
1129 
1130 void
find_trap(trap)1131 find_trap(trap)
1132 struct trap *trap;
1133 {
1134     int tt = what_trap(trap->ttyp);
1135     boolean cleared = FALSE;
1136 
1137     trap->tseen = 1;
1138     exercise(A_WIS, TRUE);
1139     if (Blind)
1140 	feel_location(trap->tx, trap->ty);
1141     else
1142 	newsym(trap->tx, trap->ty);
1143 
1144     if (levl[trap->tx][trap->ty].glyph != trap_to_glyph(trap)) {
1145     	/* There's too much clutter to see your find otherwise */
1146 	cls();
1147 	map_trap(trap, 1);
1148 	display_self();
1149 	cleared = TRUE;
1150     }
1151 
1152     You("find %s.", an(defsyms[trap_to_defsym(tt)].explanation));
1153 
1154     if (cleared) {
1155 	display_nhwindow(WIN_MAP, TRUE);	/* wait */
1156 	docrt();
1157     }
1158 }
1159 
1160 int
dosearch0(aflag)1161 dosearch0(aflag)
1162 register int aflag;
1163 {
1164 #ifdef GCC_BUG
1165 /* some versions of gcc seriously muck up nested loops. if you get strange
1166    crashes while searching in a version compiled with gcc, try putting
1167    #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the
1168    makefile).
1169  */
1170 	volatile xchar x, y;
1171 #else
1172 	register xchar x, y;
1173 #endif
1174 	register struct trap *trap;
1175 	register struct monst *mtmp;
1176 
1177 	if(u.uswallow) {
1178 		if (!aflag)
1179 			pline("What are you looking for?  The exit?");
1180 	} else {
1181 	    int fund = (uwep && uwep->oartifact &&
1182 		    spec_ability(uwep, SPFX_SEARCH)) ?
1183 		    uwep->spe : 0;
1184 	    if (ublindf && ublindf->otyp == LENSES && !Blind)
1185 		    fund += 2; /* JDS: lenses help searching */
1186 	    if (fund > 5) fund = 5;
1187 	    for(x = u.ux-1; x < u.ux+2; x++)
1188 	      for(y = u.uy-1; y < u.uy+2; y++) {
1189 		if(!isok(x,y)) continue;
1190 		if(x != u.ux || y != u.uy) {
1191 		    if (Blind && !aflag) feel_location(x,y);
1192 		    if(levl[x][y].typ == SDOOR) {
1193 			if(rnl(7-fund)) continue;
1194 			cvt_sdoor_to_door(&levl[x][y]);	/* .typ = DOOR */
1195 			exercise(A_WIS, TRUE);
1196 			nomul(0, 0);
1197 			if (Blind && !aflag)
1198 			    feel_location(x,y);	/* make sure it shows up */
1199 			else
1200 			    newsym(x,y);
1201 		    } else if(levl[x][y].typ == SCORR) {
1202 			if(rnl(7-fund)) continue;
1203 			levl[x][y].typ = CORR;
1204 			unblock_point(x,y);	/* vision */
1205 			exercise(A_WIS, TRUE);
1206 			nomul(0, 0);
1207 			newsym(x,y);
1208 		    } else {
1209 		/* Be careful not to find anything in an SCORR or SDOOR */
1210 			if((mtmp = m_at(x, y)) && !aflag) {
1211 			    if(mtmp->m_ap_type) {
1212 				seemimic(mtmp);
1213 		find:		exercise(A_WIS, TRUE);
1214 				if (!canspotmon(mtmp)) {
1215 				    if (glyph_is_invisible(levl[x][y].glyph)) {
1216 					/* found invisible monster in a square
1217 					 * which already has an 'I' in it.
1218 					 * Logically, this should still take
1219 					 * time and lead to a return(1), but if
1220 					 * we did that the player would keep
1221 					 * finding the same monster every turn.
1222 					 */
1223 					continue;
1224 				    } else {
1225 					You_feel("an unseen monster!");
1226 					map_invisible(x, y);
1227 				    }
1228 				} else if (!sensemon(mtmp))
1229 				    You("find %s.", a_monnam(mtmp));
1230 				return(1);
1231 			    }
1232 			    if(!canspotmon(mtmp)) {
1233 				if (mtmp->mundetected &&
1234 				   (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL))
1235 					mtmp->mundetected = 0;
1236 				newsym(x,y);
1237 				goto find;
1238 			    }
1239 			}
1240 
1241 			/* see if an invisible monster has moved--if Blind,
1242 			 * feel_location() already did it
1243 			 */
1244 			if (!aflag && !mtmp && !Blind &&
1245 				    glyph_is_invisible(levl[x][y].glyph)) {
1246 			    unmap_object(x,y);
1247 			    newsym(x,y);
1248 			}
1249 
1250 			if ((trap = t_at(x,y)) && !trap->tseen && !rnl(8)) {
1251 			    nomul(0, 0);
1252 
1253 			    if (trap->ttyp == STATUE_TRAP) {
1254 				if (activate_statue_trap(trap, x, y, FALSE))
1255 				    exercise(A_WIS, TRUE);
1256 				return(1);
1257 			    } else {
1258 				find_trap(trap);
1259 			    }
1260 			}
1261 		    }
1262 		}
1263 	    }
1264 	}
1265 	return(1);
1266 }
1267 
1268 int
dosearch()1269 dosearch()
1270 {
1271 	return(dosearch0(0));
1272 }
1273 
1274 /* Pre-map the sokoban levels */
1275 void
sokoban_detect()1276 sokoban_detect()
1277 {
1278 	register int x, y;
1279 	register struct trap *ttmp;
1280 	register struct obj *obj;
1281 
1282 	/* Map the background and boulders */
1283 	for (x = 1; x < COLNO; x++)
1284 	    for (y = 0; y < ROWNO; y++) {
1285 		if (IS_WALL(levl[x][y].typ))
1286 		    levl[x][y].seenv = SVALL;
1287 		else if (levl[x][y].typ == SDOOR)
1288 		    levl[x][y].typ = DOOR;
1289 		else if (levl[x][y].typ == SCORR)
1290 		    levl[x][y].typ = CORR;
1291 
1292 		/* all Sokoban floors only shown lit when dark_room is deactivated */
1293 		levl[x][y].waslit = (levl[x][y].typ != CORR) ? (!iflags.dark_room) : levl[x][y].lit;
1294 	    	map_background(x, y, 1);
1295 	    	for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
1296 	    	    if (obj->otyp == BOULDER)
1297 	    	    	map_object(obj, 1);
1298 	    }
1299 
1300 	/* Map the traps */
1301 	for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
1302 	    ttmp->tseen = 1;
1303 	    map_trap(ttmp, 1);
1304 	}
1305 }
1306 
1307 
1308 /*detect.c*/
1309