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,quiet)400 object_detect(detector, class, quiet)
401 struct obj	*detector;	/* object doing the detecting */
402 int		class;		/* an object class, 0 for all */
403 boolean		quiet;		/* don't output any message */
404 {
405     register int x, y;
406     char stuff[BUFSZ];
407     int is_cursed = (detector && detector->cursed);
408     int do_dknown = (detector && (detector->oclass == POTION_CLASS ||
409 				    detector->oclass == SPBOOK_CLASS) &&
410 			detector->blessed);
411     int ct = 0, ctu = 0;
412     register struct obj *obj, *otmp = (struct obj *)0;
413     register struct monst *mtmp;
414     int uw = u.uinwater;
415     int sym, boulder = 0;
416 
417     if (class < 0 || class >= MAXOCLASSES) {
418 	warning("object_detect:  illegal class %d", class);
419 	class = 0;
420     }
421 
422     /* Special boulder symbol check - does the class symbol happen
423      * to match iflags.bouldersym which is a user-defined?
424      * If so, that means we aren't sure what they really wanted to
425      * detect. Rather than trump anything, show both possibilities.
426      * We can exclude checking the buried obj chain for boulders below.
427      */
428     sym = class ? def_oc_syms[class] : 0;
429     if (sym && iflags.bouldersym && sym == iflags.bouldersym)
430     	boulder = ROCK_CLASS;
431 
432     if (Hallucination || (Confusion && class == SCROLL_CLASS))
433 	Strcpy(stuff, something);
434     else
435     	Strcpy(stuff, class ? oclass_names[class] : "objects");
436     if (boulder && class != ROCK_CLASS) Strcat(stuff, " and/or large stones");
437 
438     if (do_dknown) for(obj = invent; obj; obj = obj->nobj) do_dknown_of(obj);
439 
440     for (obj = fobj; obj; obj = obj->nobj) {
441 	if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) {
442 	    if (obj->ox == u.ux && obj->oy == u.uy) ctu++;
443 	    else ct++;
444 	}
445 	if (do_dknown) do_dknown_of(obj);
446     }
447 
448     for (obj = level.buriedobjlist; obj; obj = obj->nobj) {
449 	if (!class || o_in(obj, class)) {
450 	    if (obj->ox == u.ux && obj->oy == u.uy) ctu++;
451 	    else ct++;
452 	}
453 	if (do_dknown) do_dknown_of(obj);
454     }
455 
456     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
457 	if (DEADMONSTER(mtmp)) continue;
458 	for (obj = mtmp->minvent; obj; obj = obj->nobj) {
459 	    if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) ct++;
460 	    if (do_dknown) do_dknown_of(obj);
461 	}
462 	if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT &&
463 	    (!class || class == objects[mtmp->mappearance].oc_class)) ||
464 #ifndef GOLDOBJ
465 	    (mtmp->mgold && (!class || class == COIN_CLASS))) {
466 #else
467 	    (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) {
468 #endif
469 	    ct++;
470 	    break;
471 	}
472     }
473 
474     if (!clear_stale_map(!class ? ALL_CLASSES : class, 0) && !ct) {
475 	if (!ctu) {
476 	    if (detector)
477 		if (!quiet) strange_feeling(detector, "You feel a lack of something.");
478 	    return 1;
479 	}
480 
481 	if (!quiet) You("sense %s nearby.", stuff);
482 	return 0;
483     }
484 
485     if (!quiet) cls();
486 
487     u.uinwater = 0;
488 /*
489  *	Map all buried objects first.
490  */
491     for (obj = level.buriedobjlist; obj; obj = obj->nobj)
492 	if (!class || (otmp = o_in(obj, class))) {
493 	    if (class) {
494 		if (otmp != obj) {
495 		    otmp->ox = obj->ox;
496 		    otmp->oy = obj->oy;
497 		}
498 		map_object(otmp, 1);
499 	    } else
500 		map_object(obj, 1);
501 	}
502     /*
503      * If we are mapping all objects, map only the top object of a pile or
504      * the first object in a monster's inventory.  Otherwise, go looking
505      * for a matching object class and display the first one encountered
506      * at each location.
507      *
508      * Objects on the floor override buried objects.
509      */
510     for (x = 1; x < COLNO; x++)
511 	for (y = 0; y < ROWNO; y++)
512 	    for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
513 		if ((!class && !boulder) ||
514 		    (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) {
515 		    if (class || boulder) {
516 			if (otmp != obj) {
517 			    otmp->ox = obj->ox;
518 			    otmp->oy = obj->oy;
519 			}
520 			map_object(otmp, 1);
521 		    } else
522 			map_object(obj, 1);
523 		    break;
524 		}
525 
526     /* Objects in the monster's inventory override floor objects. */
527     for (mtmp = fmon ; mtmp ; mtmp = mtmp->nmon) {
528 	if (DEADMONSTER(mtmp)) continue;
529 	for (obj = mtmp->minvent; obj; obj = obj->nobj)
530 	    if ((!class && !boulder) ||
531 		 (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) {
532 		if (!class && !boulder) otmp = obj;
533 		otmp->ox = mtmp->mx;		/* at monster location */
534 		otmp->oy = mtmp->my;
535 		map_object(otmp, 1);
536 		break;
537 	    }
538 	/* Allow a mimic to override the detected objects it is carrying. */
539 	if (is_cursed && mtmp->m_ap_type == M_AP_OBJECT &&
540 		(!class || class == objects[mtmp->mappearance].oc_class)) {
541 	    struct obj temp;
542 
543 	    temp.otyp = mtmp->mappearance;	/* needed for obj_to_glyph() */
544 	    temp.ox = mtmp->mx;
545 	    temp.oy = mtmp->my;
546 	    temp.corpsenm = PM_TENGU;		/* if mimicing a corpse */
547 	    map_object(&temp, 1);
548 #ifndef GOLDOBJ
549 	} else if (mtmp->mgold && (!class || class == COIN_CLASS)) {
550 #else
551 	} else if (findgold(mtmp->minvent) && (!class || class == COIN_CLASS)) {
552 #endif
553 	    struct obj gold;
554 
555 	    gold.otyp = GOLD_PIECE;
556 	    gold.ox = mtmp->mx;
557 	    gold.oy = mtmp->my;
558 	    map_object(&gold, 1);
559 	}
560     }
561 
562     newsym(u.ux,u.uy);
563     if (!quiet) {
564 	    You("detect the %s of %s.", ct ? "presence" : "absence", stuff);
565 	    display_nhwindow(WIN_MAP, TRUE);
566 	    /*
567 	     * What are we going to do when the hero does an object detect while blind
568 	     * and the detected object covers a known pool?
569 	     */
570 	    docrt();	/* this will correctly reset vision */
571     }
572 
573     u.uinwater = uw;
574     if (Underwater) under_water(2);
575     if (u.uburied) under_ground(2);
576     return 0;
577 }
578 
579 /*
580  * Used by: crystal balls, potions, fountains
581  *
582  * Returns 1 if nothing was detected.
583  * Returns 0 if something was detected.
584  */
585 int
monster_detect(otmp,mclass)586 monster_detect(otmp, mclass)
587 register struct obj *otmp;	/* detecting object (if any) */
588 int mclass;			/* monster class, 0 for all */
589 {
590     register struct monst *mtmp;
591     int mcnt = 0;
592 
593 
594     /* Note: This used to just check fmon for a non-zero value
595      * but in versions since 3.3.0 fmon can test TRUE due to the
596      * presence of dmons, so we have to find at least one
597      * with positive hit-points to know for sure.
598      */
599     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
600     	if (!DEADMONSTER(mtmp)) {
601 		mcnt++;
602 		break;
603 	}
604 
605     if (!mcnt) {
606 	if (otmp)
607 	    strange_feeling(otmp, Hallucination ?
608 			    "You get the heebie jeebies." :
609 			    "You feel threatened.");
610 	return 1;
611     } else {
612 	boolean woken = FALSE;
613 
614 	cls();
615 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
616 	    if (DEADMONSTER(mtmp)) continue;
617 	    if (!mclass || mtmp->data->mlet == mclass ||
618 		(mtmp->data == &mons[PM_LONG_WORM] && mclass == S_WORM_TAIL))
619 		    if (mtmp->mx > 0) {
620 		    	if (mclass && def_monsyms[mclass] == ' ')
621 				show_glyph(mtmp->mx,mtmp->my,
622 					detected_mon_to_glyph(mtmp));
623 			else
624 				show_glyph(mtmp->mx,mtmp->my,mon_to_glyph(mtmp));
625 			/* don't be stingy - display entire worm */
626 			if (mtmp->data == &mons[PM_LONG_WORM]) detect_wsegs(mtmp,0);
627 		    }
628 	    if (otmp && otmp->cursed &&
629 		(mtmp->msleeping || !mtmp->mcanmove)) {
630 		mtmp->msleeping = mtmp->mfrozen = 0;
631 		mtmp->mcanmove = 1;
632 		woken = TRUE;
633 	    }
634 	}
635 	display_self();
636 	You("sense the presence of monsters.");
637 	if (woken)
638 	    pline("Monsters sense the presence of you.");
639 	display_nhwindow(WIN_MAP, TRUE);
640 	docrt();
641 	if (Underwater) under_water(2);
642 	if (u.uburied) under_ground(2);
643     }
644     return 0;
645 }
646 
647 STATIC_OVL void
sense_trap(trap,x,y,src_cursed)648 sense_trap(trap, x, y, src_cursed)
649 struct trap *trap;
650 xchar x, y;
651 int src_cursed;
652 {
653     if (Hallucination || src_cursed) {
654 	struct obj obj;			/* fake object */
655 	if (trap) {
656 	    obj.ox = trap->tx;
657 	    obj.oy = trap->ty;
658 	} else {
659 	    obj.ox = x;
660 	    obj.oy = y;
661 	}
662 	obj.otyp = (src_cursed) ? GOLD_PIECE : random_object();
663 	obj.corpsenm = random_monster();	/* if otyp == CORPSE */
664 	map_object(&obj,1);
665     } else if (trap) {
666 	map_trap(trap,1);
667 	trap->tseen = 1;
668     } else {
669 	struct trap temp_trap;		/* fake trap */
670 	temp_trap.tx = x;
671 	temp_trap.ty = y;
672 	temp_trap.ttyp = BEAR_TRAP;	/* some kind of trap */
673 	map_trap(&temp_trap,1);
674     }
675 
676 }
677 
678 /* the detections are pulled out so they can	*/
679 /* also be used in the crystal ball routine	*/
680 /* returns 1 if nothing was detected		*/
681 /* returns 0 if something was detected		*/
682 int
trap_detect(sobj)683 trap_detect(sobj)
684 register struct obj *sobj;
685 /* sobj is null if crystal ball, *scroll if gold detection scroll */
686 {
687     register struct trap *ttmp;
688     register struct obj *obj;
689     register int door;
690     int uw = u.uinwater;
691     boolean found = FALSE;
692     coord cc;
693 
694     for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
695 	if (ttmp->tx != u.ux || ttmp->ty != u.uy)
696 	    goto outtrapmap;
697 	else found = TRUE;
698     }
699     for (obj = fobj; obj; obj = obj->nobj) {
700 	if ((obj->otyp == LARGE_BOX || obj->otyp == CHEST || obj->otyp == IRON_SAFE) &&
701 	    obj->otrapped) {
702 	    if (obj->ox != u.ux || obj->oy != u.uy)
703 		goto outtrapmap;
704 	    else found = TRUE;
705 	}
706     }
707     for (door = 0; door < doorindex; door++) {
708 	cc = doors[door];
709 	if (levl[cc.x][cc.y].doormask & D_TRAPPED) {
710 	    if (cc.x != u.ux || cc.y != u.uy)
711 		goto outtrapmap;
712 	    else found = TRUE;
713 	}
714     }
715     if (!found) {
716 	char buf[42];
717 	Sprintf(buf, "Your %s stop itching.", makeplural(body_part(TOE)));
718 	strange_feeling(sobj,buf);
719 	return(1);
720     }
721     /* traps exist, but only under me - no separate display required */
722     Your("%s itch.", makeplural(body_part(TOE)));
723     return(0);
724 outtrapmap:
725     cls();
726 
727     u.uinwater = 0;
728     for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
729 	sense_trap(ttmp, 0, 0, sobj && sobj->cursed);
730 
731     for (obj = fobj; obj; obj = obj->nobj)
732 	if ((obj->otyp == LARGE_BOX || obj->otyp == CHEST || obj->otyp == IRON_SAFE) &&
733 	    obj->otrapped)
734 	sense_trap((struct trap *)0, obj->ox, obj->oy, sobj && sobj->cursed);
735 
736     for (door = 0; door < doorindex; door++) {
737 	cc = doors[door];
738 	if (levl[cc.x][cc.y].doormask & D_TRAPPED)
739 	sense_trap((struct trap *)0, cc.x, cc.y, sobj && sobj->cursed);
740     }
741 
742     newsym(u.ux,u.uy);
743     You_feel("%s.", sobj && sobj->cursed ? "very greedy" : "entrapped");
744     display_nhwindow(WIN_MAP, TRUE);
745     docrt();
746     u.uinwater = uw;
747     if (Underwater) under_water(2);
748     if (u.uburied) under_ground(2);
749     return(0);
750 }
751 
752 const char *
level_distance(where)753 level_distance(where)
754 d_level *where;
755 {
756     register schar ll = depth(&u.uz) - depth(where);
757     register boolean indun = (u.uz.dnum == where->dnum);
758 
759     if (ll < 0) {
760 	if (ll < (-8 - rn2(3)))
761 	    if (!indun)	return "far away";
762 	    else	return "far below";
763 	else if (ll < -1)
764 	    if (!indun)	return "away below you";
765 	    else	return "below you";
766 	else
767 	    if (!indun)	return "in the distance";
768 	    else	return "just below";
769     } else if (ll > 0) {
770 	if (ll > (8 + rn2(3)))
771 	    if (!indun)	return "far away";
772 	    else	return "far above";
773 	else if (ll > 1)
774 	    if (!indun)	return "away above you";
775 	    else	return "above you";
776 	else
777 	    if (!indun)	return "in the distance";
778 	    else	return "just above";
779     } else
780 	    if (!indun)	return "in the distance";
781 	    else	return "near you";
782 }
783 
784 static const struct {
785     const char *what;
786     d_level *where;
787 } level_detects[] = {
788   { "Delphi", &oracle_level },
789   { "Medusa's lair", &medusa_level },
790   { "a castle", &stronghold_level },
791   { "the Wizard of Yendor's tower", &wiz1_level },
792 };
793 
794 void
use_crystal_ball(obj)795 use_crystal_ball(obj)
796 struct obj *obj;
797 {
798     char ch;
799     int oops;
800 
801     if (Blind) {
802 	pline("Too bad you can't see %s.", the(xname(obj)));
803 	return;
804     }
805     oops = (rnd(obj->blessed ? 13 : 20) > ACURR(A_INT) || obj->cursed);
806     if (oops && (obj->spe > 0)) {
807 	switch (rnd(obj->oartifact ? 4 : 5)) {
808 	case 1 : pline("%s too much to comprehend!", Tobjnam(obj, "are"));
809 	    break;
810 	case 2 : pline("%s you!", Tobjnam(obj, "confuse"));
811 	    make_confused(HConfusion + rnd(100),FALSE);
812 	    break;
813 	case 3 : if (!resists_blnd(&youmonst)) {
814 		pline("%s your vision!", Tobjnam(obj, "damage"));
815 		make_blinded(Blinded + rnd(100),FALSE);
816 		if (!Blind) Your("%s", vision_clears);
817 	    } else {
818 		pline("%s your vision.", Tobjnam(obj, "assault"));
819 		You("are unaffected!");
820 	    }
821 	    break;
822 	case 4 : pline("%s your mind!", Tobjnam(obj, "zap"));
823 	    (void) make_hallucinated(HHallucination + rnd(100),FALSE,0L);
824 	    break;
825 	case 5 : pline("%s!", Tobjnam(obj, "explode"));
826 	    useup(obj);
827 	    obj = 0;	/* it's gone */
828 	    losehp(rnd(30), "exploding crystal ball", KILLED_BY_AN);
829 	    break;
830 	}
831 	if (obj) consume_obj_charge(obj, TRUE);
832 	return;
833     }
834 
835     if (Hallucination) {
836 	if (!obj->spe) {
837 	    pline("All you see is funky %s haze.", hcolor((char *)0));
838 	} else {
839 	    switch(rnd(6)) {
840 	    case 1 : You("grok some groovy globs of incandescent lava.");
841 		break;
842 	    case 2 : pline("Whoa!  Psychedelic colors, %s!",
843 			   poly_gender() == 1 ? "babe" : "dude");
844 		break;
845 	    case 3 : pline_The("crystal pulses with sinister %s light!",
846 				hcolor((char *)0));
847 		break;
848 	    case 4 : You("see goldfish swimming above fluorescent rocks.");
849 		break;
850 	    case 5 : You("see tiny snowflakes spinning around a miniature farmhouse.");
851 		break;
852 	    default: pline("Oh wow... like a kaleidoscope!");
853 		break;
854 	    }
855 	    consume_obj_charge(obj, TRUE);
856 	}
857 	return;
858     }
859 
860     /* read a single character */
861     if (flags.verbose) You("may look for an object or monster symbol.");
862     ch = yn_function("What do you look for?", (char *)0, '\0');
863     /* Don't filter out ' ' here; it has a use */
864     if ((ch != def_monsyms[S_GHOST]) && index(quitchars,ch)) {
865 	if (flags.verbose) pline("%s", Never_mind);
866 	return;
867     }
868     You("peer into %s...", the(xname(obj)));
869     nomul(-rnd(10), "gazing into a crystal ball");
870     nomovemsg = "";
871     if (obj->spe <= 0)
872 	pline_The("vision is unclear.");
873     else {
874 	int class;
875 	int ret = 0;
876 
877 	makeknown(CRYSTAL_BALL);
878 	consume_obj_charge(obj, TRUE);
879 
880 	/* special case: accept ']' as synonym for mimic
881 	 * we have to do this before the def_char_to_objclass check
882 	 */
883 	if (ch == DEF_MIMIC_DEF) ch = DEF_MIMIC;
884 
885 	if ((class = def_char_to_objclass(ch)) != MAXOCLASSES)
886 		ret = object_detect((struct obj *)0, class, FALSE);
887 	else if ((class = def_char_to_monclass(ch)) != MAXMCLASSES)
888 		ret = monster_detect((struct obj *)0, class);
889 	else if (iflags.bouldersym && (ch == iflags.bouldersym))
890 		ret = object_detect((struct obj *)0, ROCK_CLASS, FALSE);
891 	else switch(ch) {
892 		case '^':
893 		    ret = trap_detect((struct obj *)0);
894 		    break;
895 		default:
896 		    {
897 		    int i = rn2(SIZE(level_detects));
898 		    You("see %s, %s.",
899 			level_detects[i].what,
900 			level_distance(level_detects[i].where));
901 		    }
902 		    ret = 0;
903 		    break;
904 	}
905 
906 	if (ret) {
907 	    if (!rn2(100))  /* make them nervous */
908 		You("see the Wizard of Yendor gazing out at you.");
909 	    else pline_The("vision is unclear.");
910 	}
911     }
912     return;
913 }
914 
915 STATIC_OVL void
show_map_spot(x,y)916 show_map_spot(x, y)
917 register int x, y;
918 {
919     register struct rm *lev;
920 
921     if (Confusion && rn2(7)) return;
922     lev = &levl[x][y];
923 
924     lev->seenv = SVALL;
925 
926     /* Secret corridors are found, but not secret doors. */
927     if (lev->typ == SCORR) {
928 	lev->typ = CORR;
929 	unblock_point(x,y);
930     }
931 
932     /* if we don't remember an object or trap there, map it */
933     if (lev->typ == ROOM ?
934 	    (glyph_is_cmap(lev->glyph) && !glyph_is_trap(lev->glyph) &&
935 		glyph_to_cmap(lev->glyph) != ROOM) :
936 	    (!glyph_is_object(lev->glyph) && !glyph_is_trap(lev->glyph))) {
937 	if (level.flags.hero_memory) {
938 	    magic_map_background(x,y,0);
939 	    newsym(x,y);			/* show it, if not blocked */
940 	} else {
941 	    magic_map_background(x,y,1);	/* display it */
942 	}
943     }
944 }
945 
946 void
do_mapping()947 do_mapping()
948 {
949     register int zx, zy;
950     int uw = u.uinwater;
951 
952     u.uinwater = 0;
953     for (zx = 1; zx < COLNO; zx++)
954 	for (zy = 0; zy < ROWNO; zy++)
955 	    show_map_spot(zx, zy);
956     exercise(A_WIS, TRUE);
957     u.uinwater = uw;
958     if (!level.flags.hero_memory || Underwater) {
959 	flush_screen(1);			/* flush temp screen */
960 	display_nhwindow(WIN_MAP, TRUE);	/* wait */
961 	docrt();
962     }
963 }
964 
965 void
do_vicinity_map()966 do_vicinity_map()
967 {
968     register int zx, zy;
969     int lo_y = (u.uy-5 < 0 ? 0 : u.uy-5),
970 	hi_y = (u.uy+6 > ROWNO ? ROWNO : u.uy+6),
971 	lo_x = (u.ux-9 < 1 ? 1 : u.ux-9),	/* avoid column 0 */
972 	hi_x = (u.ux+10 > COLNO ? COLNO : u.ux+10);
973 
974     for (zx = lo_x; zx < hi_x; zx++)
975 	for (zy = lo_y; zy < hi_y; zy++)
976 	    show_map_spot(zx, zy);
977 
978     if (!level.flags.hero_memory || Underwater) {
979 	flush_screen(1);			/* flush temp screen */
980 	display_nhwindow(WIN_MAP, TRUE);	/* wait */
981 	docrt();
982     }
983 }
984 
985 /* convert a secret door into a normal door */
986 void
cvt_sdoor_to_door(lev)987 cvt_sdoor_to_door(lev)
988 struct rm *lev;
989 {
990 	int newmask = lev->doormask & ~WM_MASK;
991 
992 #ifdef REINCARNATION
993 	if (Is_rogue_level(&u.uz))
994 	    /* rogue didn't have doors, only doorways */
995 	    newmask = D_NODOOR;
996 	else
997 #endif
998 	    /* newly exposed door is closed */
999 	    if (!(newmask & D_LOCKED)) newmask |= D_CLOSED;
1000 
1001 	lev->typ = DOOR;
1002 	lev->doormask = newmask;
1003 }
1004 
1005 
1006 STATIC_PTR void
findone(zx,zy,num)1007 findone(zx,zy,num)
1008 int zx,zy;
1009 genericptr_t num;
1010 {
1011 	register struct trap *ttmp;
1012 	register struct monst *mtmp;
1013 
1014 	if(levl[zx][zy].typ == SDOOR) {
1015 		cvt_sdoor_to_door(&levl[zx][zy]);	/* .typ = DOOR */
1016 		magic_map_background(zx, zy, 0);
1017 		newsym(zx, zy);
1018 		(*(int*)num)++;
1019 	} else if(levl[zx][zy].typ == SCORR) {
1020 		levl[zx][zy].typ = CORR;
1021 		unblock_point(zx,zy);
1022 		magic_map_background(zx, zy, 0);
1023 		newsym(zx, zy);
1024 		(*(int*)num)++;
1025 	} else if ((ttmp = t_at(zx, zy)) != 0) {
1026 		if(!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) {
1027 			ttmp->tseen = 1;
1028 			newsym(zx,zy);
1029 			(*(int*)num)++;
1030 		}
1031 	} else if ((mtmp = m_at(zx, zy)) != 0) {
1032 		if(mtmp->m_ap_type) {
1033 			seemimic(mtmp);
1034 			(*(int*)num)++;
1035 		}
1036 		if (mtmp->mundetected &&
1037 		    (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) {
1038 			mtmp->mundetected = 0;
1039 			newsym(zx, zy);
1040 			(*(int*)num)++;
1041 		}
1042 		if (!canspotmon(mtmp) &&
1043 				    !glyph_is_invisible(levl[zx][zy].glyph))
1044 			map_invisible(zx, zy);
1045 	} else if (glyph_is_invisible(levl[zx][zy].glyph)) {
1046 		unmap_object(zx, zy);
1047 		newsym(zx, zy);
1048 		(*(int*)num)++;
1049 	}
1050 }
1051 
1052 STATIC_PTR void
openone(zx,zy,num)1053 openone(zx,zy,num)
1054 int zx,zy;
1055 genericptr_t num;
1056 {
1057 	register struct trap *ttmp;
1058 	register struct obj *otmp;
1059 
1060 	if(OBJ_AT(zx, zy)) {
1061 		for(otmp = level.objects[zx][zy];
1062 				otmp; otmp = otmp->nexthere) {
1063 		    if(Is_box(otmp) && otmp->olocked) {
1064 			otmp->olocked = 0;
1065 			(*(int*)num)++;
1066 		    }
1067 		}
1068 		/* let it fall to the next cases. could be on trap. */
1069 	}
1070 	if(levl[zx][zy].typ == SDOOR || (levl[zx][zy].typ == DOOR &&
1071 		      (levl[zx][zy].doormask & (D_CLOSED|D_LOCKED)))) {
1072 		if(levl[zx][zy].typ == SDOOR)
1073 		    cvt_sdoor_to_door(&levl[zx][zy]);	/* .typ = DOOR */
1074 		if(levl[zx][zy].doormask & D_TRAPPED) {
1075 		    if(distu(zx, zy) < 3) b_trapped("door", 0);
1076 		    else Norep("You %s an explosion!",
1077 				cansee(zx, zy) ? "see" :
1078 				   (flags.soundok ? "hear" :
1079 						"feel the shock of"));
1080 		    wake_nearto(zx, zy, 11*11);
1081 		    levl[zx][zy].doormask = D_NODOOR;
1082 		} else
1083 		    levl[zx][zy].doormask = D_ISOPEN;
1084 		unblock_point(zx, zy);
1085 		newsym(zx, zy);
1086 		(*(int*)num)++;
1087 	} else if(levl[zx][zy].typ == SCORR) {
1088 		levl[zx][zy].typ = CORR;
1089 		unblock_point(zx, zy);
1090 		newsym(zx, zy);
1091 		(*(int*)num)++;
1092 	} else if ((ttmp = t_at(zx, zy)) != 0) {
1093 		if (!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) {
1094 		    ttmp->tseen = 1;
1095 		    newsym(zx,zy);
1096 		    (*(int*)num)++;
1097 		}
1098 	} else if (find_drawbridge(&zx, &zy)) {
1099 		/* make sure it isn't an open drawbridge */
1100 		open_drawbridge(zx, zy);
1101 		(*(int*)num)++;
1102 	}
1103 }
1104 
1105 int
findit()1106 findit()	/* returns number of things found */
1107 {
1108 	int num = 0;
1109 
1110 	if(u.uswallow) return(0);
1111 	do_clear_area(u.ux, u.uy, BOLT_LIM, findone, (genericptr_t) &num);
1112 	return(num);
1113 }
1114 
1115 int
openit()1116 openit()	/* returns number of things found and opened */
1117 {
1118 	int num = 0;
1119 
1120 	if(u.uswallow) {
1121 		if (is_animal(u.ustuck->data)) {
1122 			if (Blind) pline("Its mouth opens!");
1123 			else pline("%s opens its mouth!", Monnam(u.ustuck));
1124 		}
1125 		expels(u.ustuck, u.ustuck->data, TRUE);
1126 		return(-1);
1127 	}
1128 
1129 	do_clear_area(u.ux, u.uy, BOLT_LIM, openone, (genericptr_t) &num);
1130 	return(num);
1131 }
1132 
1133 void
find_trap(trap)1134 find_trap(trap)
1135 struct trap *trap;
1136 {
1137     int tt = what_trap(trap->ttyp);
1138     boolean cleared = FALSE;
1139 
1140     trap->tseen = 1;
1141     exercise(A_WIS, TRUE);
1142     if (Blind)
1143 	feel_location(trap->tx, trap->ty);
1144     else
1145 	newsym(trap->tx, trap->ty);
1146 
1147     if (levl[trap->tx][trap->ty].glyph != trap_to_glyph(trap)) {
1148     	/* There's too much clutter to see your find otherwise */
1149 	cls();
1150 	map_trap(trap, 1);
1151 	display_self();
1152 	cleared = TRUE;
1153     }
1154 
1155     You("find %s.", an(defsyms[trap_to_defsym(tt)].explanation));
1156 
1157     if (cleared) {
1158 	display_nhwindow(WIN_MAP, TRUE);	/* wait */
1159 	docrt();
1160     }
1161 }
1162 
1163 int
dosearch0(aflag)1164 dosearch0(aflag)
1165 register int aflag;
1166 {
1167 #ifdef GCC_BUG
1168 /* some versions of gcc seriously muck up nested loops. if you get strange
1169    crashes while searching in a version compiled with gcc, try putting
1170    #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the
1171    makefile).
1172  */
1173 	volatile xchar x, y;
1174 #else
1175 	register xchar x, y;
1176 #endif
1177 	register struct trap *trap;
1178 	register struct monst *mtmp;
1179 
1180 	if(u.uswallow) {
1181 		if (!aflag)
1182 			pline("What are you looking for?  The exit?");
1183 	} else {
1184 	    int fund = (uwep && uwep->oartifact &&
1185 		    spec_ability(uwep, SPFX_SEARCH)) ?
1186 		    uwep->spe : 0;
1187 	    if (ublindf && ublindf->otyp == LENSES && !Blind)
1188 		    fund += 2; /* JDS: lenses help searching */
1189 	    if (fund > 5) fund = 5;
1190 	    for(x = u.ux-1; x < u.ux+2; x++)
1191 	      for(y = u.uy-1; y < u.uy+2; y++) {
1192 		if(!isok(x,y)) continue;
1193 		if(x != u.ux || y != u.uy) {
1194 		    if (Blind && !aflag) feel_location(x,y);
1195 		    if(levl[x][y].typ == SDOOR) {
1196 			if(rnl(7-fund)) continue;
1197 			cvt_sdoor_to_door(&levl[x][y]);	/* .typ = DOOR */
1198 			exercise(A_WIS, TRUE);
1199 			nomul(0, 0);
1200 			if (Blind && !aflag)
1201 			    feel_location(x,y);	/* make sure it shows up */
1202 			else
1203 			    newsym(x,y);
1204 		    } else if(levl[x][y].typ == SCORR) {
1205 			if(rnl(7-fund)) continue;
1206 			levl[x][y].typ = CORR;
1207 			unblock_point(x,y);	/* vision */
1208 			exercise(A_WIS, TRUE);
1209 			nomul(0, 0);
1210 			newsym(x,y);
1211 		    } else {
1212 		/* Be careful not to find anything in an SCORR or SDOOR */
1213 			if((mtmp = m_at(x, y)) && !aflag) {
1214 			    if(mtmp->m_ap_type) {
1215 				seemimic(mtmp);
1216 		find:		exercise(A_WIS, TRUE);
1217 				if (!canspotmon(mtmp)) {
1218 				    if (glyph_is_invisible(levl[x][y].glyph)) {
1219 					/* found invisible monster in a square
1220 					 * which already has an 'I' in it.
1221 					 * Logically, this should still take
1222 					 * time and lead to a return(1), but if
1223 					 * we did that the player would keep
1224 					 * finding the same monster every turn.
1225 					 */
1226 					continue;
1227 				    } else {
1228 					You_feel("an unseen monster!");
1229 					map_invisible(x, y);
1230 				    }
1231 				} else if (!sensemon(mtmp))
1232 				    You("find %s.", a_monnam(mtmp));
1233 				return(1);
1234 			    }
1235 			    if(!canspotmon(mtmp)) {
1236 				if (mtmp->mundetected &&
1237 				   (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL))
1238 					mtmp->mundetected = 0;
1239 				newsym(x,y);
1240 				goto find;
1241 			    }
1242 			}
1243 
1244 			/* see if an invisible monster has moved--if Blind,
1245 			 * feel_location() already did it
1246 			 */
1247 			if (!aflag && !mtmp && !Blind &&
1248 				    glyph_is_invisible(levl[x][y].glyph)) {
1249 			    unmap_object(x,y);
1250 			    newsym(x,y);
1251 			}
1252 
1253 			if ((trap = t_at(x,y)) && !trap->tseen && !rnl(8)) {
1254 			    nomul(0, 0);
1255 
1256 			    if (trap->ttyp == STATUE_TRAP) {
1257 				if (activate_statue_trap(trap, x, y, FALSE))
1258 				    exercise(A_WIS, TRUE);
1259 				return(1);
1260 			    } else {
1261 				find_trap(trap);
1262 			    }
1263 			}
1264 		    }
1265 		}
1266 	    }
1267 	}
1268 	return(1);
1269 }
1270 
1271 int
dosearch()1272 dosearch()
1273 {
1274 	return(dosearch0(0));
1275 }
1276 
1277 /* Pre-map the sokoban levels */
1278 void
sokoban_detect()1279 sokoban_detect()
1280 {
1281 	register int x, y;
1282 	register struct trap *ttmp;
1283 	register struct obj *obj;
1284 
1285 	/* Map the background and boulders */
1286 	for (x = 1; x < COLNO; x++)
1287 	    for (y = 0; y < ROWNO; y++) {
1288 		if (IS_WALL(levl[x][y].typ))
1289 		    levl[x][y].seenv = SVALL;
1290 		else if (levl[x][y].typ == SDOOR)
1291 		    levl[x][y].typ = DOOR;
1292 		else if (levl[x][y].typ == SCORR)
1293 		    levl[x][y].typ = CORR;
1294 
1295 		/* all Sokoban floors only shown lit when dark_room is deactivated */
1296 		levl[x][y].waslit = (levl[x][y].typ != CORR) ? (!iflags.dark_room) : levl[x][y].lit;
1297 	    	map_background(x, y, 1);
1298 	    	for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
1299 	    	    if (obj->otyp == BOULDER)
1300 	    	    	map_object(obj, 1);
1301 	    }
1302 
1303 	/* Map the traps */
1304 	for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
1305 	    ttmp->tseen = 1;
1306 	    map_trap(ttmp, 1);
1307 	}
1308 }
1309 
1310 
1311 /*detect.c*/
1312